Files
khosra/.claude/commands/invariants.md
T
bdeshiandClaude Opus 5 ec6e9838f0 rename docs/ to harness/, and reserve docs/ for the reader
docs/content-model.md opens with "Engine specification". It is also where the
rule lives that a leading underscore makes a file unaddressable — and the human
who owns this site did not know that rule, because nothing in this repository is
addressed to an author. Twelve documents named docs/ while being exclusively
about building the parser is a signpost pointing at the wrong room.

Naming the directory for its audience makes the gap visible instead of hiding it.
docs/ is now reserved and deliberately absent: an empty docs/ is an honest
statement that end-user documentation does not exist, where docs/ full of parser
specs was a claim that it did.

HARNESS.md stays at the root. Root holds the three entry points — README.md for a
human, CLAUDE.md for an agent, HARNESS.md for whoever maintains the machine — and
harness/README.md is the map of the directory, so moving the guide inside would
have collided with it for nothing.

Mechanical and wide: 100 path references across 24 files. Every verify.sh gate
that names a doc by path, the directory lists the dangling-path and ADR-number
gates scan, surface.sh's output target, the Makefile, CLAUDE.md's read order, the
skill, four commands, and two Go package comments. A first pass with a shell loop
silently edited only four files and the rest still said docs/; the fix was to
write the file list out and check the remaining count was zero rather than trust
the loop's exit status.

No rule, threshold, gate or obligation moved — this is a rename, and the gates
demonstrated it twice: they stayed green on the new paths, and the ADR-number gate
caught ADR-0082 before the entry existed.

Deferred, both on the human's call: the end-user documentation site itself, which
wants its own decision about where it lives and whether its claims are gated; and
moving examples/ under docs/, since demo-site is a live site root that verify.sh,
the coverage test and make demo all point at, and moving it would couple a rename
to a design nobody has made.

31 files, +146/-106.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 20:11:06 +06:00

2.2 KiB

description
description
Check the architecture invariants against the code, not against the docs

verify.sh checks what a grep can check. This pass checks the nine invariants in harness/architecture.md, which need reading the code. Run at arc boundaries, before a freeze, and before the first deploy.

For each invariant, answer held / violated / not yet applicable, with a file and line when violated. Do not fix anything in this pass.

  1. Open page object — are all fields optional in practice? Find any place a missing field causes a nil deref, an error return, or a template failure that reaches the response.
  2. Trusted / untrusted modes — trace every path by which non-repo bytes could reach shortcode or template evaluation. This is the one invariant where "probably fine" is not an answer: name the check that stops it, or report it violated.
  3. Identity is not language — is the bundle key free of language? Any place a language suffix leaks into a cache key, a URL, or a dependency key is a violation.
  4. Request-time render behind a cache — does export walk the same code path as the server, or has a second path appeared?
  5. Permalinks permanent — does any code derive a URL by a rule other than the one in content-model.md? Does every rename path emit an alias plus a permanent redirect?
  6. Interactions off the content graph — can an interaction invalidate more than its own fragment?
  7. Every feature is a leaf — is each internal/ext/* package deletable without touching the core? Try naming the diff that removes one.
  8. Degrades with external services off — for each external client, is there a path that still serves correctly, slowly, when it is unreachable?
  9. Core stops growing after Arc 2 — compare the core figure verify.sh prints against the one recorded at the freeze in state.md. Post-freeze growth is the finding, not the number.

Then: report held/violated per invariant, and for anything violated, whether it is a bug to fix now or a latent item with a trigger. A violated invariant is a stop condition (CLAUDE.md §6) — say so plainly rather than documenting it as the new normal.