Each is a gate; a red one blocks the ship.
-
Tests, fresh. go test -count=1 ./... (no cache). Never trust a cached pass or a
subagent's "it's green": the integration and e2e tiers must actually execute, and -short
or a cache hides the DB-backed behavior. Note which behaviors passed, not just ok.
-
API-first drift. make gen, then git diff --exit-code on the generated artifacts. A
non-empty diff means the committed spec or clients drifted from the Go; commit the regen.
-
House style. No em dashes and no AI/assistant attribution in any changed file (grep the
diff; scan the commit messages and the PR body).
-
Docs with everything, status, and decisions. The teaching docs ship in this PR, and the
architecture-of-record stays consistent. Three status surfaces move with the code, never
silently: the build-log.md entry is added; each architecture page the slice
advances has its status badge flipped to its new floor (Design to Partial to Built); and
if the build diverges from a page's present-tense design, the page carries an inline note and
a decision-log entry (an ADR) lands in the same PR. A page that
gained a built capability but kept a Design badge is a red gate.
Beyond status, every operator surface the diff moves takes its guide in the same PR. Grep
the diff and walk the surfaces, mapping each to its home; a surface that moved while its guide
did not is a red gate:
- a new or changed API route / Huma op (
internal/api, api/openapi.*) to the API
reference (architecture/api.md);
- a new or changed CLI command to the CLI guide (
guides/cli.md), including a generated
command: if make gen touched internal/cli/api_gen.go, the CLI guide is in scope (this
is how the password and profile commands shipped undocumented);
- a changed console surface (
web/src) to the console guide (guides/console.md) plus the
live screenshots (item 9).
Mechanically, run the docs lint suite; it must be green:
go test ./internal/docslint/ ./internal/cli/ -run 'TestVocabulary|TestDecisionsFormat|TestDocsOnlyNameRealCommands' -count=1.
Then sweep the architecture pages the slice touches for Still Design, later slice,
not yet, soon, and deferred fences and confirm none of them describes what the slice
just built; a fence still hedging a shipped capability is a red gate. And if the slice
renames or retires an identifier, the internal/docslint denylist entry and the docs sweep
land in the same PR (the rename ripple, like /storage-schema-change's gateway ripple).
-
The neighbor check. A slice that flips a behavior greps the docs for the claim it
falsified, not just its own page: search the whole docs tree for the key nouns of the
changed behavior and list the hits in the ship-review's Docs line. The two shipped
lessons: the alarms-actions cycle-safety premise died on a health slice, and the vendors
guide died on the products slice; in both, a neighboring page kept teaching the falsified
claim because only the slice's own page was updated.
-
Dev seed. If the slice adds a new operator entity (a Storage Gateway create plus a surface
for it), it adds example rows for that entity to the dev seed (internal/devseed/fixtures.yaml),
so make dev comes up populated and nobody hand-creates locations, users, or grants to exercise
the feature. The seed stays idempotent: a re-run of make dev changes nothing. n/a when the
slice adds no new entity. This is the dev-only example fleet, never the boot seed
(internal/seed, ship-with reference data that also runs in production).
-
Review. A reviewer pass over the diff (/adversarial-review for loop-built slices and
any diff wanting the anti-pattern sweep; code-review or cavecrew-reviewer otherwise),
findings addressed. Add a security-review lens if the slice touches authz, secrets, the
edge, or an invariant. Verify behavior to the outcome line, not just call sites.
-
Scope honesty. Every thin cut is documented; every deferral is a filed issue.
-
Evidence in the PR. Paste the actual fresh test output (the tail of make test, plus
web tests if touched) into the PR body, not a "they pass" claim. For any operator-facing
change, include screenshots driven live (e.g. against make dev). Capture them headless
with node web/e2e/shot.mjs <url> <out.png> [--token <og-token>] [--click <sel>]... [--select "<sel>||<value>"]... (bundled chromium, writes to the host FS, drives interactive
states like an open menu or a chosen option). Host them with the gh image extension
(node web/e2e/shot.mjs ... && gh image <out.png> prints the markdown to paste). gh image
auto-extracts the browser session cookie by default (no GH_SESSION_TOKEN, no setup);
gh image check-token verifies it is valid. GH_SESSION_TOKEN / --token are optional
overrides for a machine with no logged-in browser. Otherwise commit them
under .github/screenshots/ and embed by immutable commit SHA
(https://raw.githubusercontent.com/<owner>/<repo>/<sha>/.github/screenshots/...), so the
link survives the branch being deleted on squash-merge. A headless or remote session (no
logged-in browser, e.g. an unattended loop run) defaults to this committed path rather
than gh image.
Docs screenshots are a generated resource, in two renders. The images embedded on
the docs pages are declared in each page's screenshots frontmatter and captured by
make docs-shots from the real console, never hand-added; each capture writes the CLEAN
shot (docs/public/screenshots/, every region live) and its masked BASELINE twin
(docs/screenshots/baseline/), and make docs-shots-check recaptures and diffs the
baselines at zero tolerance, the visual sibling of the make gen drift check, so a stale
screenshot cannot merge. A slice that changes an operator-facing surface re-runs
make docs-shots and commits both sets. Adding a new shot is a frontmatter entry plus a
::screenshot{#id} directive in the prose, not a code change. PR bodies, comments, and
issues embed the clean renders, never the baselines (a masked strip teaches nothing);
the baselines exist only for the gate.
-
Audit coverage. Every privileged mutation and every auth event the slice adds
writes an audit_log row: a fleet or IAM mutation through writeAuditRes in the same
transaction as the change (a committed change without its audit row is a red gate), and an
auth event (login, logout, a denied sign-in) through WriteAuthEvent on the read/no-tx path.
Grep the diff for new gateway writes and new handlers; each names an actor (and, under
impersonation, carries the real actor via the request context). A new privileged write with no
audit row, or an auth event that is silently unlogged, is a red gate. Reads are not audited
(except secret decrypts, which always are).
-
Generate first. Scan the diff for hand-written artifacts that restate a fact the code
already knows: a table of routes, columns, env vars, or seeded rows; a copied schema; an
asset a generator could emit. Each is either replaced by a generated render in this PR or
has a filed issue named in the ship-review's Docs line. Hand-written narrative is fine;
hand-written facts are the drift class the 2026-07-30 audit proved out.
Squash-merge (the conventional-commit PR title drives the release), remove the worktree, then
logwork.