Repository navigation
feat(policy): a fifth conserves arm for a port without a retirement - #794
Conversation
CLOUD-1268 Port-without-retirement: the ledger has no spelling for a suite whose subject survives — ~82s, 15 suites, and `session-start` is NOT one of them (its 135.9s is `mise install`, not the harness)
|
| filed | corrected | |
|---|---|---|
| members | 16 | 15 |
| class total | 217.9s | ~82.0s |
| "90% in three suites" | 195.3s | 59.4s in two — helpers 36.1 + pre-commit-staging 23.3 |
The remaining 13 members total ~22.6s, so this row is now a mechanism row with a modest**
**yield, not a 218-second recovery. That does not make it not worth doing — the ledger
spelling is the deliverable CLOUD-1156 deferred and nothing else can land
the class — but it must be scheduled against ~82s, and the makespan-floor argument below is
withdrawn: session-start leaves this row still standing at 135.9s, so this row does not
move the floor after Bundle A. Only its own remedy does.
And .claude/hooks/session-start.sh was never governed either
The premise that put it in this class — "the subject cannot die" — is true but irrelevant
for it. governed_at_head selects mise-tasks/ paths carrying a shebang or #MISE description, plus any .bats under tests/. A .claude/hooks/ program is in neither set,
so it is ungoverned for edits and for deletion. Filing it under "immortal subject" sent
every pass at it toward a retirement it never needed.
Action: drop session-start from §1's scope and from Acceptance, and file its
[tasks."test:bats"] warm-install remedy as its own row.
Why
SubjectFacts::died is .all() — every declared subject must be absent before a suite's
deletion is admitted. 16 suites declare a # subject: that is not a mise-tasks/ program:
mise.toml, hk.pkl, batten.toml, clippy.toml, install.sh, a .claude/hooks/ program,
or Rust source. Those subjects are not what the campaign retires, so .all() can never hold,
so the suites are undeletable by construction.
Measured at origin/main against bench/suites/RESULTS.md (138 suites, 1097.1s):
| suite | s | # subject: |
|---|---|---|
session-start |
135.9 | .claude/hooks/session-start.sh |
helpers |
36.1 | tests/helpers.bash |
pre-commit-staging |
23.3 | hk.pkl |
lint-deno |
5.6 | mise.toml |
hk-selection |
5.0 | hk.pkl |
spawn-census |
2.9 | clippy.toml |
lint-rego |
2.6 | mise.toml |
install |
2.2 | install.sh |
verify |
1.5 | mise.toml |
fact-record-keying |
1.0 | crates/batten/src/facts.rs |
commit-attribution |
0.6 | hk.pkl mise.toml |
commit-convention |
0.4 | batten.toml mise.toml |
task-fail-closed |
0.4 | mise.toml |
git-hook |
0.3 | .claude/hooks/git-hook.sh |
cross-check |
0.1 | mise.toml |
zizmor-split |
0.0 | mise.toml |
| 217.9 | 19.9% |
Three suites are 195.3s — 90% of the class.
The row that owns this is Done, and it deferred the recovery to a row nobody filed
CLOUD-1156 closed 2026-08-31 04:36:52, inside the same ~4-second bulk cluster CLOUD-1253
documents. PR #777 landed policy/suite-subject-retirable.rego — the detector, which
refuses a new instance arriving unnoticed. That is a real deliverable and it is not this row's
complaint.
What it deferred is stated in the module's own header, policy/suite-subject-retirable.rego:47-51:
THE THIRD ROUTE IS STILL OPEN AND IS NOT THIS MODULE'S. A suite over
batten.tomlhas
cases worth porting intocrates/batten/tests/*.rseven though nothing dies — a port
WITHOUT a retirement, which the ledger has no spelling for. Each such port is its own row.
This module only refuses a NINETEENTH instance arriving unnoticed, which is the acceptance
CLOUD-1156 owes.
No such row exists. CLOUD-1156's own Acceptance says "All 19 suites are classified:
exempted, re-subjected, or ported-without-retirement" — they are exempted, which is one of
the three, and the 217.9s is untouched. This is CLOUD-1253's class stated precisely: the row**
**closed when its analysis was finished, not when its condition was gone.
Why the two obvious routes are refused, and why the third is landable
The module's header already establishes the first two, and they are not re-litigated here:
- RE-SUBJECT — rewriting a
# subject:line is an edit to a governedtests/**/*.bats.
governed_at_headselects every bats suite, so it isV-SHELL-RULE-EDITED: one route, no
bypass_env. The one admitted edit needs every removed line to name a path the same delta
deletes, and a re-subjected header names paths that are staying. Refused. - AN IN-FILE MARKER — an added line that is neither a truncation nor a repointing. Refused
by the same arm.
The third route is landable, and that is the finding. A ledger spelling for
port-without-retirement lives in policy/shell-retirement.rego and crates/batten/src/rules.rs
— neither is governed by shell-retirement (governed_at_head selects mise-tasks/ paths
and .bats suites and nothing else). So unlike mutant.sh (CLOUD-1267) this class is not
trapped behind an unlandable edit. Nobody has tried.
And the ledger genuinely has no spelling today — checked rather than inherited.
shell-retirement.rego:62 declares
#MUTANT shell-subject-alive-unchecked|…|CLOUD-1130 — a row naming a subject this delta does NOT retire is refused, whichever of the four markers it carries, and named_and_alive
(:683-688) raises on exactly that. So CLOUD-1130 tightened this deliberately, and the new
spelling must be additive rather than a loosening of that arm — a suite deletion whose ledger
carries a complete port arm for every case, with the surviving subject named and its ongoing
coverage asserted elsewhere. .claude/rules/toolchain.md's "the ledger must name it too"
states the obligation; what is missing is a marker under which naming it is admitted.
It moves the makespan floor a second time, which is the reason to do it after Bundle A
test:bats runs --no-parallelize-within-files, so the lane's makespan cannot fall below the
longest single suite.
| longest suite | corpus | |
|---|---|---|
| today | land-lock 195.1 |
1097.1 |
| after Bundle A (CLOUD-1170) | session-start 135.9 |
866.2 |
| after this row | land 96.2 (CLOUD-1148's) |
~648 |
Bundle A hands the floor to this class. It is the only other bundle that moves the floor
rather than the total, and it becomes the binding constraint the moment Bundle A lands.
Co-dispatchable remainder — 43.7s, and it shares NO mechanism with the above
Named here so it stops being unscheduled, not because it belongs to the same unit. Each is an
independent delta and any of them can be dropped without touching the spine:
| what | s | state |
|---|---|---|
CLOUD-1163 units 6, 7, 8, 10 — token-bench(+check), suite-bench-check(+suite-bench), gh-guard(+check), perf-gate(+perf-compare) |
19.1 | groomed 2026-08-31 as landing today; dispatched nowhere |
hook-latency-drift |
24.6 | a member of CLOUD-1170's own table, "costed separately"; excluded from Bundle A by the dispatching session and in no bundle since |
Units 6, 7, 8 each declare two subjects in one suite (tests/token-bench.bats:2,
tests/suite-bench-check.bats:2, tests/gh-guard.bats:2), so both members of each pair must
die in one delta — SubjectFacts::died is .all().
Refinement — Ready (give the ledger a port-without-retirement spelling, then spend it)
Refinement gate: Definition of Ready & Done. This body carries only specializations.
- **Authority boundary (§1). **
policy/shell-retirement.regoandcrates/batten/src/rules.rs
for the spelling; then the suites themselves are deleted, oneconservesarm per path.
**No **mise-tasks/**program and no **tests/**/*.batsis edited or added — every change to a
suite here is a deletion, which is the only shape available. - Computable predicate (§2). A
.batsdeletion whose declared subject survives is admitted
iff the ledger carries a complete port arm naming where every case went, and refused
otherwise.named_and_alive's existing refusal stands for every other marker; this adds one
admitted shape rather than weakening an arm. - The discriminating pair (§2), and it is the whole row. A deletion with a complete port
arm passes; the same deletion with one case unported still refuses. Without the second,
the spelling is a hole and CLOUD-908's finding — "retires_withconserves files, not logic…*
*six cases have no successor anything in the tree can name" — recurs by design. - Coverage must not fall (§2). The subject is still alive and still needs testing. Each
ported case names itscrates/batten/tests/*.rshome, and the surviving subject's coverage
is asserted there. A port that deletes 36 seconds ofhelpers.batsand lands nothing is the
defect, not the deliverable. - Deliberately not in scope (§2). Changing
SubjectFacts::diedtoany— that readmits
the partial-retirement defect its own comment names, and CLOUD-1156 already rejected it.
Re-subjecting any suite. Retiringrelease-tracking-check.shorboard-payloads.sh, the two
CLOUD-1156 records as stranded by a governed co-subject — each needs this spelling first and
then its own row. - **Effect (§3). **
readfor the policy half. - Output and exit (§5). Pointer-only: the suite path and the unported case's name. Never a
case body. - **Commit / bump (§6). **
feat(policy)for the spelling,refactor(ci)!per port — patch (0.0.x, so afeatis a patch bump and a!on a test-lane refactor carries no public surface with it). - Test obligation (§7). Over the compiled binary in
crates/batten/tests/;suite_subjects.rs
is the existing tier. Shown able to fail per CLOUD-418, plus the anti-vacuity mirror: a
conforming whole-file retirement still passes and an unexempted immortal subject is still
refused, so this does not weakensuite-subject-retirable. - Blockers (§8). None. Sequenced **after **CLOUD-1170's Bundle A, since that is what makes
session-startthe floor and this row the binding constraint.relatedToCLOUD-1156 (Done,
detector landed, this is the recovery it deferred), CLOUD-1130 (whose arm this must extend
rather than loosen), CLOUD-908 (the conserve-logic-not-files bar), CLOUD-1253 (the
closed-while-the-condition-persists class this is an instance of), CLOUD-1163 and CLOUD-1170
(the co-dispatchable remainder), CLOUD-1140 (suite cost).
Acceptance
- The ledger admits a port-without-retirement, and refuses the same deletion with one case
unported. ~~session-start~~~~, ~~helpersandpre-commit-stagingare ported and deleted — 59.4s,
with every case's new home named and the surviving subject's coverage asserted.
session-startis struck: its 135.9s ismise installin two cases, not the harness,
so a port pays the same seconds. See the correction at the top of this row.bench/suites/RESULTS.mdregenerates withhelpersandpre-commit-stagingabsent and the
serial total down by the measured amount. ~~If ~~~~session-start~~~~still heads that table after~~~~
and will still head the table; the makespan floor is its own remedy's to move.
* The remaining 13 members each carry a disposition: ported, or exempted with a reason that is
not "the subject cannot die" — that one is now answered.
* `suite-subject-retirable` still refuses an unexempted new instance, asserted.
Found by subtracting four dispatched bundles from the corpus and asking what was left: this
class was in none of them, and the session that built those bundles had recorded
`session-start.bats` as *"the largest number in the tree with no owning row"* — which was
wrong twice over, since [CLOUD-1156](https://linear.app/buttoninc/issue/CLOUD-1156/19-bats-suites-3020s-210percent-of-the-corpus-declare-a-subject-that) owns it and had already closed.
</p>
</details>
<!-- linear-review-link -->
<p><a href="https://linear.app/buttoninc/review/featpolicy-a-fifth-conserves-arm-for-a-port-without-a-retirement-12e33d433120">Review in Linear</a></p>
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (10)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe change adds a Merge Risk: 🔵 Low · up to The PR adds a public MCP configuration contract for credential and source wiring; if schema-accepted settings do not match every runtime consumer, users could receive configuration that validates but does not behave as expected. The change is mergeable with explicit owner awareness of this bounded integration risk. Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing. Comment |
7c04f82 to
89b4342
Compare
Dispositions for the rest of the classCLOUD-1268's Acceptance owes one per remaining member, and none may read "the subject cannot 14 remain — 16 minus the two ported here. Not 13: the row's Acceptance said 13 while counting
Twelve of the fourteen are now portable and were not before, which is the deliverable. They total Two members are deliberately still refused, and by a new arm
Filed rather than deferred silently
Generated by Claude Code |
Correction to the dispositions comment above — the class is 17, not 14, and my stated reason was wrongTwo errors in my previous comment, both from the same cause. Correcting rather than editing, so the The derivation was wrong. I used:
Mixed subjects are the whole reason So the count is 17, not 14, which is also exactly what And my stated reason for their absence was wrong. I wrote that they "never appeared in the What does not changeThe three dispositions themselves, and the commit prose in
13 + 3 + 1 = 17. ✅ Generated by Claude Code |
89b4342 to
9023895
Compare
ad2f550 to
0ce043b
Compare
…t arm
The case granularity landed in the previous commit; this is the half
`shell-retirement` decides. Without the marker in `arm_markers` the module
cannot SEE a `// ported:` row at all, so a deletion whose ledger maps it
completely would still raise `V-RETIREMENT-UNMAPPED` — the spelling would have
existed at one level and been invisible at the other.
Three refusals, and between them they are what make the arm oblige MORE than
the `// carried:` it sits beside rather than less:
* `V-PORT-SUBJECT-UNNAMED` — naming the survivor is the whole arm. Without
the field this is `carried` with a different word on it, and since the port
arm waives the policy-surface obligation it would be strictly WEAKER than
the marker it imitates.
* `V-PORT-SUBJECT-RETIRED` — the mirror of `V-WITHDRAWAL-SUBJECT-ALIVE`. A
subject that went with the suite makes this a plain retirement, and
`carried` already spells that with one obligation fewer. Admitting both
would let the ledger record one event in two vocabularies.
* `V-PORT-SUBJECT-GOVERNED` — what keeps CLOUD-1130 whole in the presence of
a fifth marker. A live governed path is something the campaign RETIRES, so
porting a suite's cases away while its governed subject stands is exactly
the deletion `named_and_alive` refuses under the other four — the same
claim, decided by which word the author typed. It is also why the two
suites stranded by a governed co-subject stay out until each has its row.
Exactly one obligation is waived and it is the one a port cannot meet: a
port-without-retirement lands nothing on the engine, so demanding a policy
surface would force the author to name a module that does not exist.
`V-SUCCESSOR-NO-TEST` is deliberately NOT waived — the compiled-binary test is
not incidental to a port, it IS the port, and a change that deleted a suite and
landed no coverage would be the defect rather than the deliverable.
The `subject:` field is marked rather than positional and excluded from
`path_successors_for`, for the reason `runs:` and `kind:` already give: nothing
positional separates the tail's fields, and a field that could satisfy
`has_binary_test` would let the survivor discharge the obligation to test it.
Five cases in `shell_retirement.rs` drive the compiled binary, which is the
tier that matters here: the arm reads a `[[pattern]]` row, and a fabricated
vocabulary would pass over a pattern the committed config does not carry — a
dead gate byte-identical to a clean tree.
`Conserves::ported`'s doc names no consumer artifact. The first draft listed
this repository's own immortal subjects and `no_artifact_name_reaches_the_core`
refused it, correctly: the engine knows only that a declared subject survived,
and which paths those are is the consumer's fact (non-negotiable rule 1).
Refs: CLOUD-1268
Admits: bc0321f2fc7cbb652a826c1d4f8928972e3d7c212a817ed94c9af37e90c74973
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: 0ce043b
Admits-epoch: 96ae87916950f4f3f2ec3352c8b0c5a1b70bc206f8053658cd49b4659c82fe63
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: The whole row, and the 17 suites it unblocks. `Conserves::ported` in crates/batten/src/rules.rs is inert without `ported = "// ported:"` declared here — `claimed_cases` only pushes the arm where the row declares the token — so the fifth marker would exist in the engine and be unreachable from any consumer. The three V-PORT-SUBJECT-* verdicts are worse than inert: policy/shell-retirement.rego raises them, and a token no `[[verdict]]` row declares refuses the module load outright, so the file-granularity half would not load at all. Without this write CLOUD-1268 cannot land in any form, and `SubjectFacts::died` being `.all()` leaves every suite whose declared subject survives undeletable by construction — the condition CLOUD-1156 deferred and nobody has been able to spend since.
Admits-answer-precondition: batten.toml IS the surface this class names — it is the policy authority itself, so there is no owning surface above it to route through. CLOUD-1268's deliverable is a fifth `[rule.conserves]` arm (`ported = "// ported:"`), one `[[pattern]]` row (`retirement-subject-field`) and three `[[verdict]]` rows (V-PORT-SUBJECT-UNNAMED/-RETIRED/-GOVERNED). A rule column, a pattern id and a verdict token are readable by the engine from exactly one place by construction: `Rule` carries `deny_unknown_fields` so an undeclared column is a load error, and the verdict registry is held in BOTH directions so a module raising a token no row declares fails to load. The fact satisfying the precondition: the change is four declarations in the one file that can hold them, and it lands in PR #794 where the diff is in front of every reviewer and review bot.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is the one I rejected, and it does not apply because batten.toml has no owning surface. The redirect exists for `.serena/memories/**`, where write_memory/edit_memory/rename_memory own the file and rewrite referrers; batten.toml has no such tool — `batten config` reads it and nothing writes it, which is deliberate (house-style §8: one committed authority). Its own `[[redirect]]` row says the remedy is "change it in a pull request", which is what this is: branch claude/suite-subject-retirement-g2g00c, PR #794, with `config-lint` judging the result against origin/main and a `Weakens:` trailer already carrying the one predicate change it raised. R-RESTORE-IT is not applicable either — restoring the path would discard the deliverable rather than repair damage; nothing here is a mistaken write to undo.
0ce043b to
3888241
Compare
3888241 to
9c035c6
Compare
…t arm
The case granularity landed in the previous commit; this is the half
`shell-retirement` decides. Without the marker in `arm_markers` the module
cannot SEE a `// ported:` row at all, so a deletion whose ledger maps it
completely would still raise `V-RETIREMENT-UNMAPPED` — the spelling would have
existed at one level and been invisible at the other.
Three refusals, and between them they are what make the arm oblige MORE than
the `// carried:` it sits beside rather than less:
* `V-PORT-SUBJECT-UNNAMED` — naming the survivor is the whole arm. Without
the field this is `carried` with a different word on it, and since the port
arm waives the policy-surface obligation it would be strictly WEAKER than
the marker it imitates.
* `V-PORT-SUBJECT-RETIRED` — the mirror of `V-WITHDRAWAL-SUBJECT-ALIVE`. A
subject that went with the suite makes this a plain retirement, and
`carried` already spells that with one obligation fewer. Admitting both
would let the ledger record one event in two vocabularies.
* `V-PORT-SUBJECT-GOVERNED` — what keeps CLOUD-1130 whole in the presence of
a fifth marker. A live governed path is something the campaign RETIRES, so
porting a suite's cases away while its governed subject stands is exactly
the deletion `named_and_alive` refuses under the other four — the same
claim, decided by which word the author typed. It is also why the two
suites stranded by a governed co-subject stay out until each has its row.
Exactly one obligation is waived and it is the one a port cannot meet: a
port-without-retirement lands nothing on the engine, so demanding a policy
surface would force the author to name a module that does not exist.
`V-SUCCESSOR-NO-TEST` is deliberately NOT waived — the compiled-binary test is
not incidental to a port, it IS the port, and a change that deleted a suite and
landed no coverage would be the defect rather than the deliverable.
The `subject:` field is marked rather than positional and excluded from
`path_successors_for`, for the reason `runs:` and `kind:` already give: nothing
positional separates the tail's fields, and a field that could satisfy
`has_binary_test` would let the survivor discharge the obligation to test it.
Five cases in `shell_retirement.rs` drive the compiled binary, which is the
tier that matters here: the arm reads a `[[pattern]]` row, and a fabricated
vocabulary would pass over a pattern the committed config does not carry — a
dead gate byte-identical to a clean tree.
`Conserves::ported`'s doc names no consumer artifact. The first draft listed
this repository's own immortal subjects and `no_artifact_name_reaches_the_core`
refused it, correctly: the engine knows only that a declared subject survived,
and which paths those are is the consumer's fact (non-negotiable rule 1).
Refs: CLOUD-1268
Admits: bc0321f2fc7cbb652a826c1d4f8928972e3d7c212a817ed94c9af37e90c74973
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: 0ce043b
Admits-epoch: 96ae87916950f4f3f2ec3352c8b0c5a1b70bc206f8053658cd49b4659c82fe63
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: The whole row, and the 17 suites it unblocks. `Conserves::ported` in crates/batten/src/rules.rs is inert without `ported = "// ported:"` declared here — `claimed_cases` only pushes the arm where the row declares the token — so the fifth marker would exist in the engine and be unreachable from any consumer. The three V-PORT-SUBJECT-* verdicts are worse than inert: policy/shell-retirement.rego raises them, and a token no `[[verdict]]` row declares refuses the module load outright, so the file-granularity half would not load at all. Without this write CLOUD-1268 cannot land in any form, and `SubjectFacts::died` being `.all()` leaves every suite whose declared subject survives undeletable by construction — the condition CLOUD-1156 deferred and nobody has been able to spend since.
Admits-answer-precondition: batten.toml IS the surface this class names — it is the policy authority itself, so there is no owning surface above it to route through. CLOUD-1268's deliverable is a fifth `[rule.conserves]` arm (`ported = "// ported:"`), one `[[pattern]]` row (`retirement-subject-field`) and three `[[verdict]]` rows (V-PORT-SUBJECT-UNNAMED/-RETIRED/-GOVERNED). A rule column, a pattern id and a verdict token are readable by the engine from exactly one place by construction: `Rule` carries `deny_unknown_fields` so an undeclared column is a load error, and the verdict registry is held in BOTH directions so a module raising a token no row declares fails to load. The fact satisfying the precondition: the change is four declarations in the one file that can hold them, and it lands in PR #794 where the diff is in front of every reviewer and review bot.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is the one I rejected, and it does not apply because batten.toml has no owning surface. The redirect exists for `.serena/memories/**`, where write_memory/edit_memory/rename_memory own the file and rewrite referrers; batten.toml has no such tool — `batten config` reads it and nothing writes it, which is deliberate (house-style §8: one committed authority). Its own `[[redirect]]` row says the remedy is "change it in a pull request", which is what this is: branch claude/suite-subject-retirement-g2g00c, PR #794, with `config-lint` judging the result against origin/main and a `Weakens:` trailer already carrying the one predicate change it raised. R-RESTORE-IT is not applicable either — restoring the path would discard the deliverable rather than repair damage; nothing here is a mistaken write to undo.
…t arm
The case granularity landed in the previous commit; this is the half
`shell-retirement` decides. Without the marker in `arm_markers` the module
cannot SEE a `// ported:` row at all, so a deletion whose ledger maps it
completely would still raise `V-RETIREMENT-UNMAPPED` — the spelling would have
existed at one level and been invisible at the other.
Three refusals, and between them they are what make the arm oblige MORE than
the `// carried:` it sits beside rather than less:
* `V-PORT-SUBJECT-UNNAMED` — naming the survivor is the whole arm. Without
the field this is `carried` with a different word on it, and since the port
arm waives the policy-surface obligation it would be strictly WEAKER than
the marker it imitates.
* `V-PORT-SUBJECT-RETIRED` — the mirror of `V-WITHDRAWAL-SUBJECT-ALIVE`. A
subject that went with the suite makes this a plain retirement, and
`carried` already spells that with one obligation fewer. Admitting both
would let the ledger record one event in two vocabularies.
* `V-PORT-SUBJECT-GOVERNED` — what keeps CLOUD-1130 whole in the presence of
a fifth marker. A live governed path is something the campaign RETIRES, so
porting a suite's cases away while its governed subject stands is exactly
the deletion `named_and_alive` refuses under the other four — the same
claim, decided by which word the author typed. It is also why the two
suites stranded by a governed co-subject stay out until each has its row.
Exactly one obligation is waived and it is the one a port cannot meet: a
port-without-retirement lands nothing on the engine, so demanding a policy
surface would force the author to name a module that does not exist.
`V-SUCCESSOR-NO-TEST` is deliberately NOT waived — the compiled-binary test is
not incidental to a port, it IS the port, and a change that deleted a suite and
landed no coverage would be the defect rather than the deliverable.
The `subject:` field is marked rather than positional and excluded from
`path_successors_for`, for the reason `runs:` and `kind:` already give: nothing
positional separates the tail's fields, and a field that could satisfy
`has_binary_test` would let the survivor discharge the obligation to test it.
Five cases in `shell_retirement.rs` drive the compiled binary, which is the
tier that matters here: the arm reads a `[[pattern]]` row, and a fabricated
vocabulary would pass over a pattern the committed config does not carry — a
dead gate byte-identical to a clean tree.
`Conserves::ported`'s doc names no consumer artifact. The first draft listed
this repository's own immortal subjects and `no_artifact_name_reaches_the_core`
refused it, correctly: the engine knows only that a declared subject survived,
and which paths those are is the consumer's fact (non-negotiable rule 1).
Refs: CLOUD-1268
Admits: bc0321f2fc7cbb652a826c1d4f8928972e3d7c212a817ed94c9af37e90c74973
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: 0ce043b
Admits-epoch: 96ae87916950f4f3f2ec3352c8b0c5a1b70bc206f8053658cd49b4659c82fe63
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: The whole row, and the 17 suites it unblocks. `Conserves::ported` in crates/batten/src/rules.rs is inert without `ported = "// ported:"` declared here — `claimed_cases` only pushes the arm where the row declares the token — so the fifth marker would exist in the engine and be unreachable from any consumer. The three V-PORT-SUBJECT-* verdicts are worse than inert: policy/shell-retirement.rego raises them, and a token no `[[verdict]]` row declares refuses the module load outright, so the file-granularity half would not load at all. Without this write CLOUD-1268 cannot land in any form, and `SubjectFacts::died` being `.all()` leaves every suite whose declared subject survives undeletable by construction — the condition CLOUD-1156 deferred and nobody has been able to spend since.
Admits-answer-precondition: batten.toml IS the surface this class names — it is the policy authority itself, so there is no owning surface above it to route through. CLOUD-1268's deliverable is a fifth `[rule.conserves]` arm (`ported = "// ported:"`), one `[[pattern]]` row (`retirement-subject-field`) and three `[[verdict]]` rows (V-PORT-SUBJECT-UNNAMED/-RETIRED/-GOVERNED). A rule column, a pattern id and a verdict token are readable by the engine from exactly one place by construction: `Rule` carries `deny_unknown_fields` so an undeclared column is a load error, and the verdict registry is held in BOTH directions so a module raising a token no row declares fails to load. The fact satisfying the precondition: the change is four declarations in the one file that can hold them, and it lands in PR #794 where the diff is in front of every reviewer and review bot.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is the one I rejected, and it does not apply because batten.toml has no owning surface. The redirect exists for `.serena/memories/**`, where write_memory/edit_memory/rename_memory own the file and rewrite referrers; batten.toml has no such tool — `batten config` reads it and nothing writes it, which is deliberate (house-style §8: one committed authority). Its own `[[redirect]]` row says the remedy is "change it in a pull request", which is what this is: branch claude/suite-subject-retirement-g2g00c, PR #794, with `config-lint` judging the result against origin/main and a `Weakens:` trailer already carrying the one predicate change it raised. R-RESTORE-IT is not applicable either — restoring the path would discard the deliverable rather than repair damage; nothing here is a mistaken write to undo.
68fb14e to
9eeda3c
Compare
`SubjectFacts::died` is `.all()`, so a suite whose declared `# subject:` is not something the CLOUD-843 campaign retires can never satisfy it. Re-derived from the tree: 16 suites declare `mise.toml`, `hk.pkl`, `batten.toml`, `clippy.toml`, `install.sh`, a `.claude/hooks/` program, `tests/helpers.bash` or Rust source — 217.9s of a 1097.1s corpus, undeletable by construction, in a lane whose makespan cannot fall below its longest suite. The two obvious routes are refused by `shell-retirement` and stay refused: re-subjecting a suite EDITS a governed `.bats` (`V-SHELL-RULE-EDITED`, one route, no `bypass_env`), and an in-file marker is an added line that is neither a truncation nor a repointing. `policy/suite-subject-retirable.rego`'s own header names the third route and defers it; this is it. `// ported:` is the exact mirror of `// withdrawn:`. That one is admissible only where the dying file's declared subject DIED; this one only where it LIVES. It obliges more than `carried`, never less: a target the tree carries, plus a `subject:` field naming a path the DYING FILE ITSELF declared at base and the head tree still carries. The subject is read from the base header rather than taken from the author, which is the anti-fabrication term. That field is what clears the aggregate subject-alive term — by naming the survivor, rather than by a `carried` row falsely claiming the case moved into it. CLOUD-1130's refusal over the four existing markers is untouched: `named_and_alive` reads `carried` and `subsumed` only, and this adds an admitted shape rather than relaxing an arm. The discriminating pair is the whole of the arm and it is in `ratchet.rs`, over the compiled binary: a deletion with a complete port arm passes, and the same deletion with one case unported still refuses. Without the second this would be a hole and CLOUD-908's "conserves files, not logic" recurs by design. `a_carried_arm_over_a_live_subject_still_refuses` is the anti-vacuity mirror that would go red if this had relaxed CLOUD-1130 rather than added to it. `resolved_claim` is extracted from `unconserved_cases` to stay under the line lint; the seam is the natural one, since everything above it resolves a case NAME and everything in it judges the claim that resolved. Refs: CLOUD-1268
…t arm
The case granularity landed in the previous commit; this is the half
`shell-retirement` decides. Without the marker in `arm_markers` the module
cannot SEE a `// ported:` row at all, so a deletion whose ledger maps it
completely would still raise `V-RETIREMENT-UNMAPPED` — the spelling would have
existed at one level and been invisible at the other.
Three refusals, and between them they are what make the arm oblige MORE than
the `// carried:` it sits beside rather than less:
* `V-PORT-SUBJECT-UNNAMED` — naming the survivor is the whole arm. Without
the field this is `carried` with a different word on it, and since the port
arm waives the policy-surface obligation it would be strictly WEAKER than
the marker it imitates.
* `V-PORT-SUBJECT-RETIRED` — the mirror of `V-WITHDRAWAL-SUBJECT-ALIVE`. A
subject that went with the suite makes this a plain retirement, and
`carried` already spells that with one obligation fewer. Admitting both
would let the ledger record one event in two vocabularies.
* `V-PORT-SUBJECT-GOVERNED` — what keeps CLOUD-1130 whole in the presence of
a fifth marker. A live governed path is something the campaign RETIRES, so
porting a suite's cases away while its governed subject stands is exactly
the deletion `named_and_alive` refuses under the other four — the same
claim, decided by which word the author typed. It is also why the two
suites stranded by a governed co-subject stay out until each has its row.
Exactly one obligation is waived and it is the one a port cannot meet: a
port-without-retirement lands nothing on the engine, so demanding a policy
surface would force the author to name a module that does not exist.
`V-SUCCESSOR-NO-TEST` is deliberately NOT waived — the compiled-binary test is
not incidental to a port, it IS the port, and a change that deleted a suite and
landed no coverage would be the defect rather than the deliverable.
The `subject:` field is marked rather than positional and excluded from
`path_successors_for`, for the reason `runs:` and `kind:` already give: nothing
positional separates the tail's fields, and a field that could satisfy
`has_binary_test` would let the survivor discharge the obligation to test it.
Five cases in `shell_retirement.rs` drive the compiled binary, which is the
tier that matters here: the arm reads a `[[pattern]]` row, and a fabricated
vocabulary would pass over a pattern the committed config does not carry — a
dead gate byte-identical to a clean tree.
`Conserves::ported`'s doc names no consumer artifact. The first draft listed
this repository's own immortal subjects and `no_artifact_name_reaches_the_core`
refused it, correctly: the engine knows only that a declared subject survived,
and which paths those are is the consumer's fact (non-negotiable rule 1).
Refs: CLOUD-1268
Admits: bc0321f2fc7cbb652a826c1d4f8928972e3d7c212a817ed94c9af37e90c74973
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: 0ce043b
Admits-epoch: 96ae87916950f4f3f2ec3352c8b0c5a1b70bc206f8053658cd49b4659c82fe63
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: The whole row, and the 17 suites it unblocks. `Conserves::ported` in crates/batten/src/rules.rs is inert without `ported = "// ported:"` declared here — `claimed_cases` only pushes the arm where the row declares the token — so the fifth marker would exist in the engine and be unreachable from any consumer. The three V-PORT-SUBJECT-* verdicts are worse than inert: policy/shell-retirement.rego raises them, and a token no `[[verdict]]` row declares refuses the module load outright, so the file-granularity half would not load at all. Without this write CLOUD-1268 cannot land in any form, and `SubjectFacts::died` being `.all()` leaves every suite whose declared subject survives undeletable by construction — the condition CLOUD-1156 deferred and nobody has been able to spend since.
Admits-answer-precondition: batten.toml IS the surface this class names — it is the policy authority itself, so there is no owning surface above it to route through. CLOUD-1268's deliverable is a fifth `[rule.conserves]` arm (`ported = "// ported:"`), one `[[pattern]]` row (`retirement-subject-field`) and three `[[verdict]]` rows (V-PORT-SUBJECT-UNNAMED/-RETIRED/-GOVERNED). A rule column, a pattern id and a verdict token are readable by the engine from exactly one place by construction: `Rule` carries `deny_unknown_fields` so an undeclared column is a load error, and the verdict registry is held in BOTH directions so a module raising a token no row declares fails to load. The fact satisfying the precondition: the change is four declarations in the one file that can hold them, and it lands in PR #794 where the diff is in front of every reviewer and review bot.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is the one I rejected, and it does not apply because batten.toml has no owning surface. The redirect exists for `.serena/memories/**`, where write_memory/edit_memory/rename_memory own the file and rewrite referrers; batten.toml has no such tool — `batten config` reads it and nothing writes it, which is deliberate (house-style §8: one committed authority). Its own `[[redirect]]` row says the remedy is "change it in a pull request", which is what this is: branch claude/suite-subject-retirement-g2g00c, PR #794, with `config-lint` judging the result against origin/main and a `Weakens:` trailer already carrying the one predicate change it raised. R-RESTORE-IT is not applicable either — restoring the path would discard the deliverable rather than repair damage; nothing here is a mistaken write to undo.
The first two spends of CLOUD-1268's fifth ledger arm, and between them the
whole shape it exists for: a suite whose declared subject SURVIVES.
`tests/helpers.bash` is loaded by eleven other suites and `hk.pkl` is this
repository's gate definition. Neither dies; neither is touched. That is exactly
why no route existed before — `SubjectFacts::died` is `.all()`, so neither
deletion could be admitted under any of the four markers, and re-subjecting or
marking a suite in place both EDIT a governed `.bats`, which
`V-SHELL-RULE-EDITED` refuses with no override. Fifteen `// ported:` arms name
where each case went and which survivor it still accounts for.
COVERAGE DOES NOT FALL, which is the bar CLOUD-908 set and the one a port can
most easily miss:
* `run_timeout` stands in for a GNU `timeout(1)` macOS does not ship, at nine
call sites across three suites that assert exact numbers — so a helper
returning merely "non-zero" would make every one pass vacuously. All eight
branches of the exit mapping stay pinned.
* The staging cases keep their negative control: the same fixture with
`stash` removed shows the whole-tree fixer stamping a file the author never
staged. If hk stops honouring the setting, that case goes green and its
neighbour goes red — the pair saying the same thing from both sides.
* `this_repositorys_hk_pkl_declares_stash_on_the_pre_commit_hook` reads the
COMMITTED bytes. The other six run a fixture config, so they would all stay
green if the real `hk.pkl` dropped the line — which is precisely how the
setting arrived unasserted in the first place.
Both subjects are exercised rather than described: the helper is sourced from
the checkout and hk runs the fixture gate. A copy would drift and pass while the
shipped thing was broken, which is the argument `install_module` already makes
for a committed policy module.
Existing targets rather than new ones (CLOUD-1210), and the right ones:
`bats_invocation.rs` is already the file about the bats harness, and
`hk_fix_selection.rs` already has `hk.pkl` as its subject.
`policy/suite-subject-retirable.rego` loses both rows: arm C holds that table in
both directions, so an exemption outliving its suite is itself a finding.
WHAT THE REGENERATED CORPUS ACTUALLY SAYS, stated carefully because the headline
number is misleading. 138 suites -> 136, and the two removed are the two ported.
The serial total reads 1097.1s -> 667.4s, but MOST OF THAT IS NOT THIS CHANGE:
the same run puts `land-lock` at 141.8s against a recorded 195.1s and
`session-start` at 97.8s against 135.9s, neither of which this branch touches.
This change removes two suites recorded at 36.1s and 23.3s; the rest is the
machine. `session-start` still heads the table below `land-lock`, exactly as
CLOUD-1268's own correction predicted, and its remedy is CLOUD-1273's.
Refs: CLOUD-1268
…ld reason is answered `suite-subject-retirable`'s table was written when "the subject cannot die" was a true and sufficient reason for every row in it. It is neither any more: the fifth ledger arm admits a deletion whose subject survives, and two rows have already left the table by spending it. So the prose says what an exemption MEANS now. The thirteen remaining rows total 11.4s of a 667.4s corpus, and each would owe a ledger block and a Rust port that spawns whatever its subject is, for a sub-second yield. They are exempt on COST — unported rather than unportable, which is the distinction the next reader needs and the one the old wording cannot express. `session-start` is called out separately because its reason is neither: its cost is `mise install` in the two cases that opt back in through `real_install_or_skip`, so a port would move the seconds rather than remove them, and `.claude/hooks/session-start.sh` was never governed for edits or for deletion in the first place. Its remedy is CLOUD-1273's and is not a retirement. Refs: CLOUD-1268
`spawn_census` refused all three `#[expect(clippy::disallowed_types)]` the ports added: every spawn annotation is an INVENTORY ROW, so its reason must open with `stays` or `GOES`, and mine opened with the justification instead. The verdict is `stays` in all three cases, and each now says what would retire it rather than only why it exists: the subject of a ported suite is a bash library or a gate definition, so exercising it means spawning, and the annotation goes when its subject does. That is what `#[expect]` rather than `#[allow]` buys — a deleted spawn with a stale annotation is red too, so the inventory self-cleans in both directions. Refs: CLOUD-1268 Weakens: rule-predicate-changed rule[bats-tests-not-deleted].conserves
The prose this corrects is mine, from two commits ago, and it over-claimed in
exactly the way CLOUD-1166 names: it said "every row remaining is exempt on
COST" over a table of SEVENTEEN rows, and gave a count of thirteen without
saying which thirteen. A reader reconciling the two would conclude the other
four are cheap ports nobody got to. That is the opposite of true for all four.
The 13/11.4s figure was right and is kept, re-derived from the regenerated
corpus rather than carried over. What is added is the boundary around it:
* COST (13 rows, 11.4s) — portable today, unported because a sub-second yield
does not pay for a ledger block and a Rust port.
* STRUCTURE (3 rows, 9.2s) — `replay`'s subject is a `.py` that
`governed_when_deleted` excludes by extension, and `release-tracking-check`
and `remedy-payload-source` each name a GOVERNED live subject, which
`V-PORT-SUBJECT-GOVERNED` refuses deliberately. Willingness moves none of
them.
* `session-start` — its own row, already argued below the table.
That third refusal is worth stating in the table's own prose rather than only
in the module that raises it: the fifth arm answers "the subject cannot die"
for a suite whose subject is ungoverned, and says nothing for a suite gluing a
live governed program to an immortal one. Reading the arm as a general answer
is how those two would get ported around instead of retired.
Refs: CLOUD-1268
CI was red on `windows` and green everywhere else, on one case:
a_command_killed_by_a_signal_it_raised_itself_is_not_a_timeout
left: 1 right: 143
143 is POSIX's `128 + SIGTERM`. Windows has no such encoding, so `kill -TERM $$`
under Git Bash exits 1 — and 124, 137 and 143 are every number these cases
assert, so the contract is not merely untestable there, it is meaningless.
THE DEFECT IS THE PORT'S, NOT THE CODE'S, AND IT IS A HAZARD OF PORTING RATHER
THAN OF THESE CASES. `test:bats` runs on ubuntu only, so `tests/helpers.bats`
and `tests/pre-commit-staging.bats` never faced Windows in their lives. Moving
them onto `cargo test` silently WIDENED them onto the windows matrix, which no
part of the change said out loud and no reviewer would have seen. A port moves
cases between harnesses, and two harnesses do not run the same platforms; that
difference belongs to the port to declare.
`verify` structurally could not catch it — it has no windows arm — which is what
`land` means by "a red run on a verified branch means verify and CI disagree".
So the POSIX-dependent cases carry `#[cfg(unix)]`, with the reason in the block
header rather than as a bare attribute, and stating that it was measured on CI
rather than reasoned about. The staging fixtures are gated for the same bound:
their fixer is `sed -i` in a shell step.
COVERAGE DOES NOT FALL, which is the bar this whole row is held to. These cases
ran on Linux and macOS before and still do — 3491 passed, 0 skipped, with all 32
ported cases among them. What stops is a claim about a platform their subject
was never exercised on. `this_repositorys_hk_pkl_declares_stash_on_the_pre_commit_hook`
stays ungated: reading committed bytes is portable, and it is the case that keeps
the other six from being vacuous.
Refs: CLOUD-1268
CLOUD-1210 moved `crates/batten/tests/*.rs` under `crates/batten/tests/it/` after these arms were written. A conserves arm resolves its target by exact tracked path, so an arm naming the pre-move location is `case-target-missing` for every case this delta deletes — the seventeen arms of the two ported suites. The arms elsewhere in the tree are untouched on purpose: they belong to deltas that already landed, and only the cases a delta removes are re-resolved. Regenerated `bench/suites/RESULTS.md` over the rebased tree, which also carries six suites main retired since the last run: 130 suites, 660.5s serial. Refs: CLOUD-1268
9eeda3c to
0b31cae
Compare
|
❌ The last analysis has failed. |
|
/fast-forward |
129 suites, 664.1s serial. `tests/session-start.bats` retires in this branch and #794's own retirements landed on main in between, so the table records a suite set neither side alone produces. Refs: CLOUD-312, CLOUD-1294
…that drift PR #794 landed three `V-PORT-SUBJECT-*` verdicts and declared mutations for two of them. `V-PORT-SUBJECT-RETIRED` had none, and the gap was two-deep: the suite `#MUTANT-SUITE` names carried no case for that arm either. The load-time tier pinned the predicate and `ratchet.rs` pinned the case granularity, but neither is the declared suite, so a mutation of this arm had nothing to redden and could only ever have been reported as a survivor. `a_port_over_a_subject_that_died_is_refused` is that case. It discriminates because `tests/helpers.bash` is neither a `.bats` nor under `mise-tasks/`, so `governed_when_deleted` does not select it and its own deletion owes no arm — leaving the dying-subject arm the only one that can fire. Two numbers in `suite-subject-retirable.rego`'s header also came from that PR and were wrong. The corpus denominator is DELETED rather than refreshed: it moves every time a suite retires, so restating one is a number that goes stale silently. `session-start`'s seconds are removed for a different reason — 97.8s matched no measurement that exists, and the suite is the corpus's second-largest on a cold container and unremarkable on a warm one, so the honest place for a number is the row that owns both readings. Both memories gain the inference their own rules did not state. A defect in a governed program is a RETIREMENT row, never a block — "leave it alone" is the shape for a file needing no change, not an answer to one that does. And an In Review row is landed, not occupied, so its declared still-open acceptance bullets are pullable work. Refs: CLOUD-1302 Admits: d90a5f385ccca5b96d4a1196cc70273e2ec067f27aad9e66ba8c93fc13ff929a Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: policy/shell-retirement.rego Admits-head: 6063049 Admits-epoch: 71bf7f9f4f378e71c73ceeea5eb44c0217d75bdca1c242d0f9cdfb31f03c5117 Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: V-PORT-SUBJECT-RETIRED keeps its status as the one arm of three shipped by PR #794 whose mutation was never declared, so nothing proves its compiled-binary case discriminates. That leaves a predicate that can silently stop refusing, in exactly the class CLOUD-1267 withdrew 32 exemptions to close. Admits-answer-precondition: A registered .rego module has no owning surface that can write it: batten offers no verb that adds a #MUTANT declaration line, and the declaration must sit beside the predicate it mutates. This write is a two-line addition to policy/shell-retirement.rego landing in a reviewed PR against CLOUD-1302. Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE. There is no owning surface: #MUTANT rows are read from the module source itself and batten exposes no verb that writes one. R-RESTORE-IT does not apply either, since the file is not damaged; the change is a declaration that was missing from the start. Admits: b5eec5a0af1a244a95e0e372de28dcdb199ebb1df5ce9b7f4fa259785a8dda01 Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: policy/suite-subject-retirable.rego Admits-head: 6063049 Admits-epoch: 71bf7f9f4f378e71c73ceeea5eb44c0217d75bdca1c242d0f9cdfb31f03c5117 Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: Two numbers PR #794 landed stay wrong in the tree. ':147' states a 667.4s corpus that is now 660.5s, and ':158' states session-start at 97.8s, which matches no measurement that exists — the row's cold figure is 135.9s and the warm one is 6.8s. A reader classifying the exemption table is calibrated by both. Admits-answer-precondition: A registered .rego module has no owning surface that can write its header prose: batten offers no verb that edits a module comment. The write is a comment-only change to policy/suite-subject-retirable.rego landing in a reviewed PR against CLOUD-1302, and the predicate below it is untouched. Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE. There is no owning surface for a module's header comment; the prose is read from the module source. R-RESTORE-IT does not apply — restoring the file would restore the wrong numbers, which are what this change removes. Admits: e96e3aa4ccf27e2460fde52e56d0b5357d2e80a2ff4f775a8c8ff2c12bcfa36f Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: .serena/memories/toolchain-and-hooks.md Admits-head: 6063049 Admits-epoch: 71bf7f9f4f378e71c73ceeea5eb44c0217d75bdca1c242d0f9cdfb31f03c5117 Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: Both memories keep stating a correct rule while omitting the inference that trips over it. mem:toolchain-and-hooks names the two landable shapes for a governed file and never says which applies when you find a BUG in one — read as 'leave it alone', it makes every defect in that layer permanent. mem:workflow/board-states says In Review means merged and never says the consequence: such a row is landed, not occupied, so its open acceptance bullets are pullable. Both misreadings were measured this session. Admits-answer-precondition: NOT the usual one, and stated plainly rather than fitted to the question. The owning surface CAN express this change and WAS used: both files were written with Serena's edit_memory, and the mediated-call gate allowed those writes. What demands this block is the commit-level half (commit.rs judge_pending), which requires an articulation for every protected path a commit touches, whether or not the write needed an override. The write is a two-paragraph addition to each memory, landing in a reviewed PR against CLOUD-1302. Admits-answer-rejected-route: Neither route was rejected; R-USE-THE-OWNING-SURFACE was TAKEN, which is why this articulation does not fit the question. R-RESTORE-IT does not apply — nothing is damaged. The gate's question set presumes the write bypassed a surface; for .serena/memories/** written through Serena it cannot be answered as asked, and that contradiction is filed rather than papered over. Admits: 14eb1973fd24f18fe1092e42014b0cac84beef053e935f202b0aab519cb80b01 Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: .serena/memories/workflow/board-states.md Admits-head: 6063049 Admits-epoch: 71bf7f9f4f378e71c73ceeea5eb44c0217d75bdca1c242d0f9cdfb31f03c5117 Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: mem:workflow/board-states keeps saying In Review means already merged while never drawing the consequence a reader needs: such a row is LANDED, not OCCUPIED, so its declared still-open acceptance bullets are pullable work and its attached PRs are evidence of landed work rather than of a competitor. Measured this session on CLOUD-1218, which was declined on exactly that misreading. Admits-answer-precondition: NOT the usual one, and stated plainly rather than fitted to the question. The owning surface CAN express this change and WAS used: this file was written with Serena's edit_memory, and the mediated-call gate allowed the write. What demands this block is the commit-level half (commit.rs judge_pending), which requires an articulation for every protected path a commit touches, whether or not the write needed an override. The write adds one numbered entry to the memory's own 'three things that trip agents up' section, landing in a reviewed PR against CLOUD-1302. Admits-answer-rejected-route: Neither route was rejected; R-USE-THE-OWNING-SURFACE was TAKEN, which is why this articulation does not fit the question. R-RESTORE-IT does not apply — nothing is damaged. The gate's question set presumes the write bypassed a surface; for .serena/memories/** written through Serena it cannot be answered as asked, and that contradiction is filed rather than papered over.
…that drift PR #794 landed three `V-PORT-SUBJECT-*` verdicts and declared mutations for two of them. `V-PORT-SUBJECT-RETIRED` had none, and the gap was two-deep: the suite `#MUTANT-SUITE` names carried no case for that arm either. The load-time tier pinned the predicate and `ratchet.rs` pinned the case granularity, but neither is the declared suite, so a mutation of this arm had nothing to redden and could only ever have been reported as a survivor. `a_port_over_a_subject_that_died_is_refused` is that case. It discriminates because `tests/helpers.bash` is neither a `.bats` nor under `mise-tasks/`, so `governed_when_deleted` does not select it and its own deletion owes no arm — leaving the dying-subject arm the only one that can fire. Two numbers in `suite-subject-retirable.rego`'s header also came from that PR and were wrong. The corpus denominator is DELETED rather than refreshed: it moves every time a suite retires, so restating one is a number that goes stale silently. `session-start`'s seconds are removed for a different reason — 97.8s matched no measurement that exists, and the suite is the corpus's second-largest on a cold container and unremarkable on a warm one, so the honest place for a number is the row that owns both readings. Both memories gain the inference their own rules did not state. A defect in a governed program is a RETIREMENT row, never a block — "leave it alone" is the shape for a file needing no change, not an answer to one that does. And an In Review row is landed, not occupied, so its declared still-open acceptance bullets are pullable work. Refs: CLOUD-1302 Admits: d90a5f385ccca5b96d4a1196cc70273e2ec067f27aad9e66ba8c93fc13ff929a Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: policy/shell-retirement.rego Admits-head: 6063049 Admits-epoch: 71bf7f9f4f378e71c73ceeea5eb44c0217d75bdca1c242d0f9cdfb31f03c5117 Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: V-PORT-SUBJECT-RETIRED keeps its status as the one arm of three shipped by PR #794 whose mutation was never declared, so nothing proves its compiled-binary case discriminates. That leaves a predicate that can silently stop refusing, in exactly the class CLOUD-1267 withdrew 32 exemptions to close. Admits-answer-precondition: A registered .rego module has no owning surface that can write it: batten offers no verb that adds a #MUTANT declaration line, and the declaration must sit beside the predicate it mutates. This write is a two-line addition to policy/shell-retirement.rego landing in a reviewed PR against CLOUD-1302. Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE. There is no owning surface: #MUTANT rows are read from the module source itself and batten exposes no verb that writes one. R-RESTORE-IT does not apply either, since the file is not damaged; the change is a declaration that was missing from the start. Admits: b5eec5a0af1a244a95e0e372de28dcdb199ebb1df5ce9b7f4fa259785a8dda01 Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: policy/suite-subject-retirable.rego Admits-head: 6063049 Admits-epoch: 71bf7f9f4f378e71c73ceeea5eb44c0217d75bdca1c242d0f9cdfb31f03c5117 Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: Two numbers PR #794 landed stay wrong in the tree. ':147' states a 667.4s corpus that is now 660.5s, and ':158' states session-start at 97.8s, which matches no measurement that exists — the row's cold figure is 135.9s and the warm one is 6.8s. A reader classifying the exemption table is calibrated by both. Admits-answer-precondition: A registered .rego module has no owning surface that can write its header prose: batten offers no verb that edits a module comment. The write is a comment-only change to policy/suite-subject-retirable.rego landing in a reviewed PR against CLOUD-1302, and the predicate below it is untouched. Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE. There is no owning surface for a module's header comment; the prose is read from the module source. R-RESTORE-IT does not apply — restoring the file would restore the wrong numbers, which are what this change removes. Admits: e96e3aa4ccf27e2460fde52e56d0b5357d2e80a2ff4f775a8c8ff2c12bcfa36f Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: .serena/memories/toolchain-and-hooks.md Admits-head: 6063049 Admits-epoch: 71bf7f9f4f378e71c73ceeea5eb44c0217d75bdca1c242d0f9cdfb31f03c5117 Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: Both memories keep stating a correct rule while omitting the inference that trips over it. mem:toolchain-and-hooks names the two landable shapes for a governed file and never says which applies when you find a BUG in one — read as 'leave it alone', it makes every defect in that layer permanent. mem:workflow/board-states says In Review means merged and never says the consequence: such a row is landed, not occupied, so its open acceptance bullets are pullable. Both misreadings were measured this session. Admits-answer-precondition: NOT the usual one, and stated plainly rather than fitted to the question. The owning surface CAN express this change and WAS used: both files were written with Serena's edit_memory, and the mediated-call gate allowed those writes. What demands this block is the commit-level half (commit.rs judge_pending), which requires an articulation for every protected path a commit touches, whether or not the write needed an override. The write is a two-paragraph addition to each memory, landing in a reviewed PR against CLOUD-1302. Admits-answer-rejected-route: Neither route was rejected; R-USE-THE-OWNING-SURFACE was TAKEN, which is why this articulation does not fit the question. R-RESTORE-IT does not apply — nothing is damaged. The gate's question set presumes the write bypassed a surface; for .serena/memories/** written through Serena it cannot be answered as asked, and that contradiction is filed rather than papered over. Admits: 14eb1973fd24f18fe1092e42014b0cac84beef053e935f202b0aab519cb80b01 Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: .serena/memories/workflow/board-states.md Admits-head: 6063049 Admits-epoch: 71bf7f9f4f378e71c73ceeea5eb44c0217d75bdca1c242d0f9cdfb31f03c5117 Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: mem:workflow/board-states keeps saying In Review means already merged while never drawing the consequence a reader needs: such a row is LANDED, not OCCUPIED, so its declared still-open acceptance bullets are pullable work and its attached PRs are evidence of landed work rather than of a competitor. Measured this session on CLOUD-1218, which was declined on exactly that misreading. Admits-answer-precondition: NOT the usual one, and stated plainly rather than fitted to the question. The owning surface CAN express this change and WAS used: this file was written with Serena's edit_memory, and the mediated-call gate allowed the write. What demands this block is the commit-level half (commit.rs judge_pending), which requires an articulation for every protected path a commit touches, whether or not the write needed an override. The write adds one numbered entry to the memory's own 'three things that trip agents up' section, landing in a reviewed PR against CLOUD-1302. Admits-answer-rejected-route: Neither route was rejected; R-USE-THE-OWNING-SURFACE was TAKEN, which is why this articulation does not fit the question. R-RESTORE-IT does not apply — nothing is damaged. The gate's question set presumes the write bypassed a surface; for .serena/memories/** written through Serena it cannot be answered as asked, and that contradiction is filed rather than papered over.
Closes CLOUD-1268.
The class, re-derived from the tree
SubjectFacts::diedis.all(): every subject a dying.batssuite declared must be absent before the deletion is admitted. Re-derived here rather than inherited —— 16 suites declare a
# subject:that CLOUD-843 never retires:mise.toml,hk.pkl,batten.toml,clippy.toml,install.sh, a.claude/hooks/program,tests/helpers.bash, Rust source..all()can never hold for them, so those suites are undeletable by construction — 217.9s of a 1097.1s corpus, in a lane that runs--no-parallelize-within-filesand whose makespan therefore cannot fall below its longest suite.CLOUD-1156 landed the detector (
policy/suite-subject-retirable.rego) and closed; its own header at:47-51defers the recovery to "its own row", and no such row was filed. This is that row.Why this route
The module header establishes the other two and they stay refused: re-subjecting a suite edits a governed
tests/**/*.bats(V-SHELL-RULE-EDITED, one route, nobypass_env), and an in-file marker is an added line that is neither a truncation nor a repointing.The arm
// ported:is the exact mirror of// withdrawn:. That one is admissible only where the dying file's declared subject died; this one only where it lives. Between them, both answers to "what happened to the subject" have a spelling.It obliges more than
carried, never less:subject:field naming a path the dying file itself declared at base and the head tree still carries.That field is what clears the aggregate subject-alive term — by naming the survivor, rather than by a
carriedrow falsely claiming the case moved intohelpers.bash. The subject is read from the base# subject:header rather than taken from the author, which is the anti-fabrication term.Additive, not a loosening.
named_and_alivereadscarriedandsubsumedonly and is untouched, so CLOUD-1130's refusal over the four existing markers stands byte-for-byte.The discriminating pair is the whole commit
In
ratchet.rs, over the compiled binary:a_complete_port_over_a_surviving_subject_is_admitted— passes;the_same_port_with_one_case_unported_still_refuses— byte-identical fixture minus one arm, and it refuses twice: the unmapped case at the suite, and the aggregate subject-alive blocker because the path is then not fully mapped.Without the second this would be a hole and CLOUD-908's finding — "conserves files, not logic: six cases have no successor anything in the tree can name" — recurs by design.
Four more: a port whose subject died refuses (use
carried); one naming no survivor refuses; one naming a survivor the suite never declared refuses; anda_carried_arm_over_a_live_subject_still_refusesis the anti-vacuity mirror that would go red if this had relaxed CLOUD-1130 rather than added to it.Still to come on this branch
Commits 2–4 spend the spelling on
pre-commit-staging(23.3s),helpers(36.1s) andsession-start(135.9s) — 195.3s, 90% of the class — each deleting the suite, removing its row fromsuite-subject-retirable.rego'sexemptmap, and asserting the surviving subject's coverage in its new home. The rego andbatten.tomlhalves of the spelling land in this PR too; both are protected paths, and their refusal's own remedy is to change them under review, which is here.Notes for the reviewer
policy/shell-retirement.regois a protected path because CLOUD-833 derives everypolicyrow'smoduleinto the protected set — worth knowing before touching it.mise-tasks/replay.sh:349iteratescarried subsumed changed, so aportedarm is skipped rather than broken; it needs no edit (and is governed, so it could not take one). The cost — ported cases get no differential replay — is real and gets its own row.shell-retirement.rego's header claimsrules-driftholdsarm_markersto the TOML. It does not;mise-tasks/rules-drift.shcontains no reference to the arms. Nothing would have caught adding the marker in only one of the two places.Generated by Claude Code