Skip to content

A control can name the controls that hold its gap - #363

Open
robertblust wants to merge 9 commits into
mainfrom
a-control-names-what-covers-its-gap
Open

robertblust wants to merge 9 commits into
mainfrom
a-control-names-what-covers-its-gap

Conversation

@robertblust

@robertblust robertblust commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

In all three instances, three controls name the control that holds their gap inside a sentence, where nothing resolves the name and a rename leaves it stale. This adds an optional field to core's control schema, compensated-by, naming the controls that hold a gap the page is known to leave. The page's prose keeps the gap and the field carries the name, so it is written once and R4 resolves it.

Whether a named control really holds the gap toward what the covered one is for needs both pages, so it is a check rather than a writing rule: each control named in compensated-by must share a value of mitigates or enforces with the page (R16). The check is driven by a compensated property on the control's row of TYPES, as binds is for rules, reads each page by its own fields, and leaves to another check an unresolved name (R4), a name two controls carry (R2), a named control whose frontmatter cannot be read, and a vendored core that does not declare the field. A self-name and two controls naming each other pass on purpose; a writing rule refuses the first. The example gains the edge, from "Main requires a review" to a new detective control, "An unapproved merge is read before it ships", read in Release between the merge and the tag, whose name avoids the stem "review" so mcp-server's search test keeps its name tier when it re-pins.

The field cites no standard: NIST, the one definition read at source, uses "compensating control" for a replacement, not for cover of another control's gap. The spec says which instance controls move after the release (only-the-owner's-account in all three) and which wait for evidence (release tag, registry entry). The spec and the plan are in this pull request: docs/superpowers/specs/2026-10-17-a-control-names-what-covers-its-gap-design.md, docs/superpowers/plans/2026-10-18-a-control-names-what-covers-its-gap.md. No version bump; the release is the owner's.

Verified: typecheck, build:check, verify (67 checks), every test:* script, conventions-format and conventions-check pass with nothing skipped; each new test failed first or, where it pins behavior the spec states, failed under a deliberate break of the code it guards. Two fresh reviews read the whole branch; their findings on the check and the example's timing are fixed, and the spec records the amendment.

🤖 Generated with Claude Code

robertblust and others added 9 commits October 17, 2026 23:23
In all three instances, three controls name the control that holds their gap inside a sentence, where nothing resolves the name and a rename leaves it stale. The spec gives a control the optional field compensated-by, keeps the gap in the page's prose, and adds an instance check that a covering control shares a risk or a rule with the control it covers, since that norm needs both pages.

It also says which instance controls move: only-the-owner's-account in all three, while the release-tag and registry controls stay in prose until the covering control's page records a refusal of such an action. The September 30 spec gains a sentence on why the edge runs between two controls of equal rank.

Verified: conventions-format and conventions-check pass on the branch; the instance facts were read from the three instances' control pages, and NIST's definition from its glossary.

Process: Delivery
Phase: Spec
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The spec of October 17 becomes three tasks: the field with its Purpose sentence and writing rules, the check that a covering control shares a risk or a rule with what it covers, and the example's edge. Each task carries its tests first, the exact schema row, the TypeEntry property and the check's message, so an implementer needs nothing from this conversation.

Verified: conventions-format and conventions-check pass; the failure messages the plan expects for an undeclared field and a reference to the wrong type were read from the checker on a copy of the control test.

Process: Delivery
Phase: Plan
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Instances name the control that covers another's gap inside a sentence, where nothing resolves it. The control schema now declares compensated-by, an optional list of controls, with a Purpose sentence and two writing rules: the prose says which gap each named control holds without repeating its name, and a control never names itself.

Verified: node --test verify/rule-risk-control.test.mjs, npm run verify, npm run test:instance-checks, npm run test:judge and conventions-format pass.

Process: Delivery
Phase: Implement
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whether a named control holds a gap toward what the covered control is for needs both pages, so it is a check and not a sentence. A control's row now carries compensated, and a check reads it: each control a page names in compensated-by shares a value of mitigates or enforces with the page, or the page fails once for that name. A name R4 refuses is not read again.

Verified: node --test verify/rule-risk-control.test.mjs, npm run typecheck, npm run build, npm run build:check, npm run verify, npm run test:instance-checks, npm run test:rules, npm run test:ids and npm run test:cli pass.

Process: Delivery
Phase: Implement
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The example now shows the edge the field draws, so the checks and the MCP server's tests read it. Main requires a review says a repository admin can merge past it and names a new detective control, An unapproved merge is read before the next release, which the Reviewer carries out before Release and which answers to the same risk and rule. Its name carries no stem of review, so mcp-server's search test keeps its name tier when it re-pins.

Verified: npm run build:check, npm run verify, every test:* script, conventions-format and conventions-check pass.

Process: Delivery
Phase: Implement
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The branch review found two untrue findings. A page with no H1, or one sharing its H1 with another control, was judged by whatever page held that name, and so told it shared nothing when it did. A core that predates compensated-by already reports the field as undeclared, and the check added a second finding about a field that core does not have. The check now reads a page's mitigates and enforces from its own frontmatter, and skips a type whose vendored schema does not declare the field.

Verified: the two new tests in verify/rule-risk-control.test.mjs failed first and pass now, 30 of 30; typecheck, build:check, verify, every test:* script, conventions-format and conventions-check pass.

Process: Delivery
Phase: Implement
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pull request's review found that the example's new control, read before Release, saw an admin's merge only before the next release, after the change had gone out, so its tagline and its claim to mitigate the risk did not hold in the example's own process. The spec now has it read in Release between the merge and the tag, and names it for that.

It also states the failure message the check emits, which says entry rather than risk and rule, compares each shared field with itself, and names the three cases the check leaves to another one: a core without the field, a name two pages carry, and a named page whose frontmatter cannot be read.

Verified: conventions-format passes; the example's Release activities were read from its phase page.

Process: Delivery
Phase: Spec
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pull request's review found two findings the check added beside ones already reported. Where two controls carry one name, the verdict depended on which file sorted last, on top of R2's finding; and a named control whose frontmatter cannot be read made the page naming it fail too. The check now skips both, and its comment no longer says a self-naming control always passes: one that answers to nothing fails. The control schema's Purpose opens its next sentence with its subject, since the sentence before it is now about the page.

Two tests pin what the spec states and were shown to guard it by breaking the code on purpose: a self-naming control that answers to nothing fails, and a risk and a rule of one name are compared each in its own field.

Verified: the two new skip tests failed first and pass now, the two pinning tests failed under a deliberate break of the code they guard, 34 of 34 in verify/rule-risk-control.test.mjs; typecheck, build:check, verify, every test:* script, conventions-format and conventions-check pass.

Process: Delivery
Phase: Implement
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Release merges and tags in one activity, so a control read before Release saw an admin's merge only before the next release, after the change had reached customers, and its claim to mitigate that risk did not hold. The control now reads such merges in Release, once the branch is merged and before the release is tagged, and a finding holds the tag. It is named for that, An unapproved merge is read before it ships, still without a stem of review, and Main requires a review says merge past the protection, since rule is a type of its own here.

Verified: npm run verify failed on the renamed reference before the control was renamed and passes after it; every test:* script, conventions-format and conventions-check pass.

Process: Delivery
Phase: Implement
Track: Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant