build: the gate is scripts/check.sh, and CI goes

The Gitea Actions gate repeated, after the merge, what a release already runs
before it, and its runner shared the git host's container: one run there
starved Gitea of memory until it stopped answering. The lanes now live in
scripts/check.sh, run the same by the release dispatcher and by hand, and the
gate-contract test holds its lines (the ruff and pip-audit checks read it
instead of the workflow). The two audits only CI ran join the gate: pip-audit
over the lock (pinned in the test image, blocking at any severity) and npm
audit of the production dependencies. The engine contracts drop the CI
containers; the register records that pushes have no server-side gate.
This commit is contained in:
2026-10-04 06:20:58 +02:00
parent 0528b35f2d
commit cc414de952
14 changed files with 234 additions and 253 deletions
+20 -4
View File
@@ -5,7 +5,7 @@ How to run Siftlode locally and pass the gate. Conventions for the backend code
## Node
One major, everywhere. `.nvmrc` pins it; the CI container, the `Dockerfile`'s frontend build stage,
One major, everywhere. `.nvmrc` pins it; the `Dockerfile`'s frontend build stage,
`frontend/package.json`'s `engines` and `@types/node` must all match it — and so must the machine you
run the gate on. `frontend/src/lib/nodeEngine.contract.test.ts` fails the gate the moment any of them
drift apart, including when yours is the odd one out. `nvm use` in the repo root picks it up.
@@ -38,9 +38,20 @@ decisions and the chosen patterns, rendered with the app's real CSS. It never re
## The gate
A change is done when all of this is green. CI runs the same checks server-side
(`.gitea/workflows/check.yml`), so "main is always green". What each gate deliberately does NOT
check — and why — is the [gate register](gates.md); a test fails when a narrowing is missing from it.
A change is done when this is green, from the repo root:
```bash
bash scripts/check.sh # every lane
bash scripts/check.sh lint # the static lanes only (no tests, build or audits) — the quick loop
```
It runs every lane even after one fails and names each red one at the end. What it runs, and why
each lane runs where it does, is in the script's comments; `frontend/src/lib/gates.contract.test.ts`
holds its lines, so a lane dropped or narrowed there fails a test. What each gate deliberately does
NOT check — and why — is the [gate register](gates.md). There is no CI: the gate runs here, and a
release runs it (plus e2e and the CVE scan) before anything is merged.
The lanes, for running one by hand:
**Backend**
@@ -58,6 +69,10 @@ docker compose -f backend/docker-compose.test.yml run --rm --no-deps --build tes
# coverage total. The backend tree is bind-mounted, so it always tests your working files.
docker compose -f backend/docker-compose.test.yml up --build --abort-on-container-exit --exit-code-from test
docker compose -f backend/docker-compose.test.yml down -v
# the lock against the advisory databases, at any severity
docker compose -f backend/docker-compose.test.yml run --rm --no-deps test \
pip-audit -r requirements.lock --no-deps --disable-pip
```
A missing database or ffmpeg is a hard error, not a skip — so the gate can't print green while the
@@ -75,6 +90,7 @@ npm run format:check # prettier
npm run knip # unused files/exports/deps — and unused by what SHIPS (--production)
npm run test # vitest (incl. the compiler, size/complexity and gate-register contracts)
npx vite build # the production bundle (devOnlyGuard fails it on dev-only code)
npm audit --omit=dev --audit-level=high # what ships to the browser, at high or above
```
Coverage is reported, never enforced: `npm run test -- --coverage`, and the pytest lane's last line.