5.8 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-07-30 against commit
d3ec723.
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. The pre-commit secret scan
Repo-managed hooks live in .githooks/ (in version control, unlike .git/hooks). Enable them once per
clone:
git config core.hooksPath .githooks
pre-commit is a fast, dependency-free backstop against a credential leaking into a file that shouldn't
hold one. It scans only staged additions, so it is quick. It rejects a commit that stages:
- the retired hardcoded admin password
qw123321, anywhere; - private-key material or an AWS access-key id, anywhere;
- the deployment's SQL Server host
87.107.152.16outside the declared config files; - a real connection-string password in any
appsettings*.jsonoutside the declared config files (elsewhere only theSET_VIA_USER_SECRETS_OR_ENVplaceholder is allowed).
The declared-config allow-list
The pre-launch demo deployment configures itself from committed files rather than a secret store (see
DEPLOY.md), so a short allow-list is exempt from the last two checks:
appsettings.Development.json · docker-compose.yml · telegram-otp-bot/.env.example · DEPLOY.md
It is maintained in the declared_config function in the hook, and it is the honest record of where
this repo's secrets are. Shrink it, never grow it. Once real users exist, those values must be
rotated and moved out of git.
Limits
This is the local first line of defence, not a replacement for a full scanner (gitleaks, trufflehog)
in CI. Bypass a false positive with git commit --no-verify — sparingly, and only when you are certain
the flagged line is not a secret.
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.