packs
The suite polices itself, on every push.
A pack is a self-contained bundle that loads into a host's runner, uses the host's real surface as its vocabulary, and proves the contract it claims to enforce. Nothing inside a pack imports the target. govstruct ships ten check-profile packs and one crashtest lane - the same SPEC v1 grammar the whole family loads.
The packs, live
Ten SPEC v1 check-profile packs under packs/public/, each a pure-reading verifier over files on disk, plus the crashtest dogfood lane that attacks govstruct lint with a hostile member-block corpus. A NEW exploited case or any verdict regression fails CI.
| pack | what it verifies | verdict |
|---|---|---|
| comment-shapes | comment hygiene across the tree pure-reading checks; a violation is named at file:line | PASS |
| env-shapes | environment-key declarations every env key a member claims is declared once, in the shared block | PASS |
| floor-shapes | engine floors a floor bump propagates through the dependency graph, never drifts silently | PASS |
| hygiene-shapes | tree hygiene no stray build product, lockfile, or repo-bound internal in a shipped surface | PASS |
| naming-shapes | the naming contract ids, aliases, and file names agree with the roster grammar | PASS |
| pin-shapes | pin style pins, never floats: every dependency and workflow uses: carries an exact rev | PASS |
| style-shapes | source style the shared source-consistency rules, enforced as a pack, not a fifth app | PASS |
| test-shapes | the test floor every member carries a real test suite, not a green stub | PASS |
| version-shapes | version truth package.json is the single version source; a living surface cannot hand-copy it | PASS |
| a11y-shapes | the emitted pane's floor a named landmark, a real anchor per row, a visible focus ring, keyed strings + a locale fallback | PASS |
| govstruct-manifest-shapes | hostile member blocks nine attacks over govstruct lint: malformed blocks refuse (never crash), every refusal carries a registered code, spec-allowed shapes are never over-strictly flagged | REFUSED |
The counts above are current-tree receipts, not marketing: the committed crashtest ledger sits at labs/crashledger.json(63 REFUSED verdicts), the packs live under packs/public/, and the full grammar is at the docs packs page.
The verdict taxonomy
Every scenario lands in exactly one of four buckets. Adoption is explicit - a new verdict only enters the ledger through a reviewed commit, never a silent rebuild.
REFUSED
The surface said no, cleanly, with its named code. A regression here is loud, not quiet.
BOUNDED
The damage was contained to a documented limit - a byte cap, a fixture lifespan. Bounds live in the ledger, not in prose.
PASSED
The safe path works end to end: checks, gates, roundtrips.
EXPLOITED
The attack landed. A new EXPLOITED or the regression of any previously recorded row fails CI.
Running the lane
The check host reads each pack's declared checks over the tree; the crashtest lane drives govstruct lint in-process over a hostile corpus. Exit 0 on green, 1 on findings.
# run every check pack npm run check # manifest + entry grammar (packstruct) npm run lint:packs # the dogfood: hostile member blocks over the CLI npx crashtest run