MOTIR-2356Done
The model is fully enforced — `PLANNED_PERMISSIONS` empties, the guard's PENDING arm is deleted, and the inventory closes
The card that makes "the permission model is fully enforced" a statement the build can check rather than a claim in a description. Every sibling card has landed its gates; this one turns the temporary scaffolding off.
What it does
- Flips the last
enforcementflags.ai:planandai:view_planare held atplannedwhile four and two cards respectively wire their operations — a key may only be markedenforcedwhen EVERY operation the inventory maps to it has its gate, or the flag lies in the direction the model exists to prevent. This card verifies each and flips whatever is left. - Empties
PLANNED_PERMISSIONS.lib/permissions/catalog.tssays it in its own comment: "the model is fully enforced has a machine-readable definition: this array is empty." After this card it is, andtests/permissions/catalog.test.ts's partition test proves it rather than a count. - Deletes the
PENDINGarm of the guard.tests/permissions/noUngovernedOperation.test.tssays "this arm is deleted when the count reaches 0, which takes BOTH." Deleted, not re-pinned at zero — a pin at zero is a slot for the next one to creep back into. - Deletes the
CLAIMED_BUT_UNVERIFIEDarm on the same terms, once both unconfirmed-gate cards have emptied it. - Closes the inventory.
docs/decisions/permission-inventory.md's headline counts, its enforced/planned split and its "wired so far" list are re-derived from the code and the document records that theplannedtier is gone. - Sweeps the story's own referrers. Every comment in
catalog.ts,builtinRoles.tsand the two guard files that names this story or the administrative split as a FUTURE owner is corrected to the past tense. A comment promising work that has shipped is the same class of defect as a count that is wrong.
What it must not do
It must not make a number true by editing the number. If the guard still reports a pending or unverified operation, the answer is a missing gate, not a smaller pin — and the correct move is to say so and stop, so the gap becomes a card. A close-out card that quietly re-pins is worse than no close-out card, because it converts a real hole into a green build.
Acceptance criteria
PLANNED_PERMISSIONSis empty andENFORCED_PERMISSIONSholds all 31 catalog keys, asserted by the partition test rather than by a length constant.- The
PENDINGset, its pinned count and the "every pending operation names the permission that will govern it" test are DELETED fromtests/permissions/noUngovernedOperation.test.ts; theCLAIMED_BUT_UNVERIFIEDset and its pin likewise. - The guard's remaining assertions still fail when they should: the synthetic-ungated-route control and the two extractor / local-helper regression controls are kept, and the suite is run once with a deliberately ungated route added to confirm it goes red before that route is removed again.
docs/decisions/permission-inventory.md's counts are re-derived from the code on this branch, and no row is left with anewdecision.- Every comment in
lib/permissions/catalog.tsandlib/permissions/builtinRoles.tsnaming a story as the future owner of aplannedkey is corrected. pnpm test tests/permissions/is green, and the PR body quotes the guard's final output.
Context refs
lib/permissions/catalog.ts—PLANNED_PERMISSIONS,ENFORCED_PERMISSIONS, and the comments that promise this card.tests/permissions/noUngovernedOperation.test.ts— the two arms this card deletes and the controls it keeps.tests/permissions/catalog.test.ts— the partition test that becomes the real assertion.docs/decisions/permission-inventory.md— the counts and the "wired so far" list.- The permission MODEL — the story that defined the
enforced/plannedseam this card retires.