5.0 KiB
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:copyis part ofcheck, 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.
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). - It follows the rules for that project — the relevant
CLAUDE.mdplus 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 §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 §6 already documents the repo's actual trade: config lives in
committed files, including live credentials, until real users exist (see
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
mainand 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.