# Git and the quality gates What must pass before work is done, and what the repo refuses to let you commit. > Last verified: 2026-08-02 against commit `51e86a1`. --- ## 1. The gates Each project is built, linted, and tested **on its own**. There is no root-level build, package, or solution, so there is no single command that gates the repo. Run the gate for the side you edited. ### Client — `cd client` | Command | What it runs | | --- | --- | | `npm run check` | **The gate.** `type` → `lint` → `lint:copy`, in that order | | `npm run type` | `tsc --noEmit` (`strict` on) | | `npm run lint` | `eslint .` (flat config) | | `npm run lint:copy` | `node scripts/check-copy.mjs` — greps `fa.json` for banned Persian orthography variants | | `npm run test:ci` | `jest --ci` — **also required** when you touched a component with a co-located `*.test.tsx` | `npm run check` must be green. `en.json` and `fa.json` must be in sync. > `lint:copy` is part of `check`, not a separate step you can forget. It is what stops a copy regression > — a hamza-less «تایید», a space in the brand name — from needing to be re-discovered by a human. The > rules it enforces are in [client/i18n.md](../client/i18n.md). ### Server — `cd server` | Command | What it runs | | --- | --- | | `dotnet build Baya.sln` | **Zero new warnings.** Unused usings, locals, parameters, private fields or members count as failures — delete them, don't suppress them | | `dotnet test Baya.sln` | All tests pass, including the ones your change adds | A reachable SQL Server is required to run the API (not to build or unit-test it). ### Both Read your own diff as if you were reviewing the PR: **would a senior engineer approve it without comment?** A change that passes the mechanical gate and fails that question is not done. --- ## 2. What "done" means A change is done when all of these hold: - [ ] The full scope is implemented. No `// TODO: implement later`, no stub that returns fake data. Anything not real is behind a **DI-registered seam** and recorded (see [code-quality.md](code-quality.md)). - [ ] It follows the rules for that project — the relevant `CLAUDE.md` plus the one reference file for the area you touched. - [ ] No dead code. Comments explain *why*, not *what*. - [ ] The project's own gate above is green. - [ ] If the structure changed, the matching **architecture section** is updated in the same change (see [documentation.md](../documentation.md) §3). - [ ] If a business rule was discovered or decided, `product/` reflects it — recorded, not invented. - [ ] If a new reusable pattern or seam landed, the reference file for that area names it, so the next change reuses it instead of reinventing it. A change that doesn't pass its own gate is **not done**, regardless of how complete the code looks. --- ## 3. No pre-commit secret scan (for now) There is no git hook enforcing anything in this repo — `.githooks/` was removed in phase 7 as an MVP-stage call: this is a pre-launch demo project and the mechanical backstop wasn't worth the overhead yet. The underlying rule is unchanged — **never commit a real secret** — it's just unenforced by tooling. Root [CLAUDE.md](../../../CLAUDE.md) §6 already documents the repo's actual trade: config lives in committed files, including live credentials, until real users exist (see [DEPLOY.md](../../../DEPLOY.md) "Going to Production" for the rotation step that unblocks that). Revisit adding a hook — or a CI scanner (gitleaks, trufflehog) — if that trade changes before this one does. --- ## 4. Branches and commits `main` is the default branch and the base for PRs. - **Commit or push only when asked.** If you are on `main` and about to commit, branch first. - One coherent change per commit. The repo's history reads as a sequence of completed units of work (`ui phase 11`, `remove user-secrets approach & prepare a pilot deploy`) — keep that. - Never skip hooks (`--no-verify`) or bypass signing unless explicitly asked. If a hook fails, fix the underlying issue. - Prefer a new commit over amending an existing one. - Before a destructive git operation (`reset --hard`, `push --force`, `checkout --`), consider whether a safer route reaches the same place. --- ## 5. Known pre-existing warnings These are expected and **must not be "fixed"** unless a task says so — a change that touches them is scope creep, and one that silences them is worse. | Warning | Project | Note | | --- | --- | --- | | `NU1510` on `Microsoft.Extensions.Logging.Debug` | `Baya.Web.Api` | Redundant transitive reference, harmless | | `NETSDK1057` (preview SDK) | all server projects | The .NET 10 SDK is preview on this machine | On the client, `import/no-cycle` is disabled in `eslint.config.mjs` (its TypeScript resolver has an interface mismatch with this toolchain), and **ESLint is pinned to 9** — ESLint 10 crashes against this Next 16 toolchain with `scopeManager.addGlobals is not a function`. See [client/testing.md](../client/testing.md).