Five corrections against CONTRACT_P13S16_PROJECTION.md, all against the
document rather than the code -- aee4ff9 is accepted and unchanged. Filed as
one amendment on the owner's decision because the findings are not
independent: two pairs share a root cause, and separate rounds would have
recorded symptoms while hiding the causes.
Root A -- the contract reasoned about MECHANISM where the question was what
the test ASSERTS. Findings 1 and 3. Both cells are right about the production
code and wrong about the observation, because a test that verifies its own
fixture is meaningful fails for a second reason no mechanism argument reaches.
Root B -- enumeration where completeness was required. Findings 2 and 4. Both
lists were built by reading one file. The contract already carries derive-do-
not-enumerate under pin 10a and 6 item 1, and broke it twice in its own
apparatus.
1. Invariant 21 does not detect the undo residue (0.6, pin 5a, pin 6b). It
abstains on dangling members by design; M5 shows invariant 10 firing
instead. The hole was already covered before this rung. u5's direct
members assertion is what signs pin 5 -- the fallback pin 6b itself names
-- so nothing is unsigned.
2. 3's M6a row names six failing tests; seven occur. The fifth all()
consumer is in tests/score_graph.rs, outside the four-in-generators.rs
list.
3. 3's t8d-under-M2 survivor cell is falsified -- it fails on non-vacuity,
not idempotence. The assertion must not be weakened: under M2 t8d is
genuinely vacuous. The other falsifiable cell, t9 under M1, was CONFIRMED.
4. Pin 10 cites four of the nine sites its instruction covers, and gate 6
cannot see core_spec.tex's "exactly 20 invariants" sentence.
5. cargo test --workspace truncates the failure set at the first failing
suite -- exactly the condition every mutation creates. 3's uniform rule
and gate 1 now specify --no-fail-fast.
Finding 6 is WITHDRAWN as false and retained as record. Pin 8's line numbers
were exact on the ratified tree 34232dc -- all four verified -- and only
stopped matching because this rung inserted ~1,500 lines above them. It had
been reported without the cited locations ever being measured. Writing the
amendment is what forced the check, which is an argument for consolidating
rather than filing six rounds.
Touch row 12 added, so spec/EVIDENCE_P13S16_EXECUTION.md is committed rather
than left untracked: the findings are conclusions, and the annex is the
evidence they were derived from, including the runs that falsified two of this
contract's own predictions. Its trailing whitespace is stripped so gate 4
passes, and it says so.
CLAUDE.md, the handoff and the ledger row are corrected in step -- all three
said "six findings", which is now the count before review rather than after.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Contract 4a deliberately kept these out of aee4ff9 because they describe the
state of the repository rather than the change, and staging them during
execution would have asserted that S16 had landed. It has, so they move now.
CLAUDE.md
- Green baseline 1577 -> 1583, still the single origin for the count.
- Added: use --no-fail-fast whenever anything is failing. The bare command
stops at the first failing suite, which is exactly the situation every
mutation creates -- S16's M6a read six failures over four suites bare and
seven over all forty-two with the flag.
- The authority is currently 1, not 0, and a base materialized before S16
must be rebuilt rather than reused.
- The bump rule now names BOTH classes it always covered: a change to a
reduction verdict OR to canonical reduced state. S16 carried one of each,
and the state-only kind is the easier to overlook while invalidating a
base just as completely.
- Two-tracks table: S16 LANDED, with a pointer to its unamended findings.
spec/HANDOFF_2026-08-07.md
- Chain state and §4.3 item 9 -> LANDED at aee4ff9, each retaining what it
said before, since the block is a record of what moved.
- The POST-S27 authority paragraph -> currently 1, both bump classes named.
- Records the two S16 findings that bite outside their own contract: the
--no-fail-fast truncation, and invariant 21 abstaining on dangling
membership rather than detecting the undo hole 0.6 attributed to it.
spec/PASS13_CANDIDATES.md
- The S16 row is appended to, not rewritten: ACCEPTED AND LANDED at aee4ff9,
superseding its own "EXECUTED ... NOTHING IS STAGED" sentence, RESOLVED,
and the six contract findings listed as outstanding follow-up.
The six findings remain unamended against CONTRACT_P13S16_PROJECTION.md. Its
pins are frozen, so each needs its own amendment and review round; recording
them at both ends is what keeps them visible until then.
spec/EVIDENCE_P13S16_EXECUTION.md stays untracked -- no touch row covers it,
and adding one is an amendment, not a keyboard decision.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Disposition A replaces genesis tranche G3a's disposition B. Staff.group was
already the sole authority, but members was stored exactly as carried and
neither maintained nor trusted, so both disagreeing states were permitted
outcomes. Neither is authorable any more.
- CreateStaffGroup refuses a non-empty carried members (ContainerNotEmpty).
This is an empty-container precondition on the carried value, NOT a
referential one, so unlike the sibling mints it is not graph-gated and
holds base-free too. t7's assertion inverts for exactly that reason.
- CreateStaff carrying group: Some(g) appends the staff to g's members in
the graph, idempotently; undo of a staff strips it back out.
- Graph invariant 21, StaffGroupMembershipAgreement, flags disagreement in
either direction between live objects via two independently removable
checks. It abstains on dangling membership -- an undeclared member is
invariant 10's concern, not a disagreement.
- staff_group_values keeps the carried value, and seed_from_graph reseeds it
with members emptied, closing the reload hazard that only appears after a
snapshot round trip.
- CURRENT_REDUCTION_ALGORITHM_VERSION 0 -> 1 with its Bumps entry, naming
both causes separately: CreateStaffGroup changes a reduction verdict,
CreateStaff changes canonical reduced state. Either alone requires it.
Bases materialized before this rung must be rebuilt, not reused.
Specification: operation_catalog.tex 0.15.0 and core_spec.tex's Revision
History; nine disposition-B prose sites rewritten, invariant 21 appended to the
Chapter 5 enumeration (count 20 -> 21), both PDFs rebuilt. No payload bytes
move, no schema or epoch moves, no vector artifact changes.
Evidence: 20 pins, 14 gates, 11 mutation executions. Baseline 1577 -> 1583
(six net-new tests). Both S27 tripwires fired on the bump and were updated to
independent literals, never to the constant.
Six findings reported against the contract rather than patched into it:
invariant 21's abstention vs the undo-hole attribution in 0.6/pin 5a/pin 6b;
M6a's failure set is seven, not six; t8d under M2 is falsified as a survivor;
pin 10 cites four of nine prose sites; cargo test --workspace truncates the
failure set without --no-fail-fast; pin 8's line numbers had drifted.
CLAUDE.md and spec/HANDOFF_2026-08-07.md are deliberately NOT in this commit
(contract 4a) and still describe the pre-bump state; their reconciliation is
post-acceptance work.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Ratification round 12 returned zero findings against 25b4925 -- the live
mutation-site locators, M7's field anchors, M6's structural mapping,
touch-table coverage, the gate and report consumers, and the expected-outcome
table all rechecked, with the revised m40 citations and the remaining named
mutation sites resolving against the tree. Ratified on the authority of the
repository owner.
Contract status block: RATIFIED, DISPATCHABLE, PINS FROZEN -- executed, not
edited; a defect found during execution is reported as its own amendment with
its own review round. The block's earlier promise to say RATIFIED when the
decision was taken is discharged, and it still states no round count, per
round 2's correction.
NOT YET DISPATCHED. Ratification and dispatch are separate acts, no execution
instruction has been given, and nothing is implemented -- so the ledger row
does NOT move to RESOLVED. The contract now distinguishes four states:
unblocked, ratified, dispatchable, resolved. This rung is the first three.
What ratification does not settle, recorded at the top of the contract:
- Two cells of §3's expected-outcome table -- t8d under M2, t9 under M1 -- are
PREDICTIONS from pins not yet executed, stated so they can be falsified. A
mismatch is a finding in the contract or the implementation.
- Every gate, test and mutation is specified and none has been run. Twelve
rounds went into the claim that they can be run and that their results would
be evidential; execution is what tests that claim.
- §4a's landing obligation is outstanding by construction: CLAUDE.md and the
handoff carry statements pin 12's bump falsifies, and must not be staged
during execution.
- The execution report is subject to independent review before completion is
accepted, as S27's was -- which turned a clean paper record into seven
post-execution amendments.
Round 11 is also recorded: pin 6's m40 locators had drifted to invariants.rs:6045,
the enclosing module's doc comment rather than m40's own. Fixed by the owner at
25b4925 to :6060-:6135 and gate 6 to :6063; verified against the tree.
The defect record, so ratification is not read as vindication: 32 findings
closed before it -- 19 in draft amendment 1 and revisions A-J, 13 across rounds
1-11. None was in the pins' substance. The maintenance rule, the refusal,
invariant 21, the undo strip and the authority bump have been stable since
draft amendment 1, and every single finding was in the evidence apparatus:
what observes a requirement, what channel carries an observation, who owns a
claim, and whether a locator resolves. That is where this contract was weak and
where execution should be read hardest.
Governing docs updated to the now-true state: CLAUDE.md's track head, the
handoff's POST-S27 chain row, and the S16 ledger cell, which supersedes its own
"has not been through adversarial review" sentence per the append-only
convention.
Documentation only: no .rs or .toml touched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
P13-S27 landed at 4df8e25. Four documents carried live statements that the
landing invalidated, and they had to move together: updating the ledger alone
would have left the active S16 contract contradicting it.
CLAUDE.md
- Track head: P13-S27 LANDED; P13-S16 unblocked, contract still DRAFT.
- The T1b/S27 collision is resolved. T1b is NOT thereby free -- it stays
blocked on Ruling B blocker (ii), versioned decode. A future
epiphany-bundle rung re-creates the collision on its own terms.
- Green baseline 1570 -> 1577, and marked as the single origin for the count.
- "One live constraint" rewritten: the blanket no-canonical-base prohibition
is lifted, replaced by the authority check (accepted when
reduction_algorithm_version equals CURRENT_REDUCTION_ALGORITHM_VERSION,
currently 0; CanonicalBaseRequiresRebuild on both read and write paths;
legacy epoch still refuses outright), plus the bump discipline and the
synthetic_for_fixture / production_caps split.
spec/HANDOFF_2026-08-07.md -- a dated snapshot, so it keeps its text and gains
a POST-S27 UPDATE block at the top that is the single place the new state is
given. Each invalidated site now points there instead of restating:
§1.2 constraint (dated record), the suspended conformance wiring (restored),
ReductionAuthorityUnavailable (deleted, replaced), §1.4 chain state, §2.6 and
§4.3 collision, §4.3 items 7 and 9. The three 1570 repetitions are replaced by
a pointer to CLAUDE.md -- a figure kept in four places goes stale in three.
spec/CONTRACT_P13S16_PROJECTION.md
- Status: DRAFT, UNBLOCKED 2026-08-09, NOT RATIFIED and therefore NOT
dispatchable. Pin 0's blocker is discharged; core_spec.tex:11614 is met.
Original status retained verbatim.
- Pin 11 amended: it mandated a ledger state of "blocked on P13-S27," which is
now false -- a pin requiring a false ledger state would put the contract in
contradiction with the ledger it governs. Its instruction to file S27 in the
same edit is discharged.
spec/PASS13_CANDIDATES.md -- appended to both cells, per the append-only
convention.
- S16: unblocked, with the "additionally needs pin-2a's disposition" sentence
explicitly superseded (settled from outside S27 by the format rung's pin 8);
unblocked is not dispatchable; first act is bumping the authority to 1.
- S27: accepted and landed, with the gate figures, and a correction to pin
10's own wording -- it said S16 becomes "dispatchable," but by this repo's
definition S16 is unblocked, not dispatchable. Same unblocked/dispatchable
conflation S27's round 1 committed.
Documentation only: no .rs or .toml touched, so the gates re-run against the
landed tree stand unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Ratified on the repository owner's authority. Nineteen adversarial review
rounds, 65 findings, 47 blocking, and a clean independent round at the end
-- the criterion named at round 11.
The pins are now frozen: executed, not edited. A defect found during
execution is reported, not patched in place.
Round 1's ratification was withdrawn and the distinction matters. It was
claimed after a single round, and round 2 found four more blocking defects
against the supposedly frozen text, two of them introduced by round 1's own
amendments. This one rests on a different footing.
Recorded at the top of the status block so it cannot be missed, what
ratification does not settle: M7's authority/base leg is unverifiable until
this rung is implemented, since BundleCapabilities and
CURRENT_REDUCTION_ALGORITHM_VERSION are its own deliverables; and every
gate, test and mutation is specified while none has been run. Nineteen
rounds went into the claim that they can be run and that their results would
be evidential. Execution is what tests that claim.
Execution is authorised under §6 with its boundaries unchanged: stage only
§2's files by explicit path, never git add -A, re-check HEAD before staging,
and never reset/restore/checkout/stash. The work is left STAGED, not
committed, and the execution report is subject to independent review before
completion is accepted -- covering in particular M7's three observations and
its control. The document's quality came from the independent rounds; the
report gets the same treatment.
The round-17 probe exception is marked superseded rather than deleted. Its
result falsified round 10 and is cited throughout M7, and its standing is
unchanged: evidence for M7's prerequisite, not a demonstration of
laundering, because it carried no base.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Round 17 (authored-side, 10 findings, 5 blocking) applied round 13's
could-this-pass-for-the-wrong-reason question to the two sections that had
never had it. Both yielded immediately.
Gate 6's derive alternative could never match. grep is line-oriented, so
[[:space:]]* cannot cross the newline rustfmt puts between #[derive(...,
Default)] and pub struct BundleCapabilities. Verified by running the exact
regex: the likelier violation returns 0 matches and the gate passes, while
being the sole mechanical guard on the pin-3 prohibition M4 exists for
because no test can catch it. Replaced with three checks, one of which
quotes the definition verbatim and so cannot pass vacuously.
Gate 6a was vacuous under a rename: pin 3b offered synthetic_for_fixture as
an example while the gate grepped for that exact literal. The name is now
pinned. Gates 2 and 3 named no toolchain in a repo whose CI records
1.95/1.97 lint divergence and whose default is 1.97.1; both are now
cargo +1.95.0. Gate 4's "staged list exactly §2" was unsatisfiable with a
conditional touch row, now subset-both-ways. Gate 1 requires 0 ignored,
gate 7 has a method, gate 5 quotes all three dependency tables.
Tests 1, 6, 7, 8 and 9 could all pass on a base-free bundle. Pin 5 makes
base-free the permissive case, base-bearing fixtures are the awkward ones to
build, and test 1 degenerated into test 4.
The unifying defect: a gate proving absence is only as strong as the string
it searches for. A regex that cannot match, a name that was an example, a
clause with no method -- all reporting success while checking nothing. The
remedy is §4's: require an artifact quoted and read, not a pattern matched.
Round 18 (independent, 2 findings, both blocking, both created by round 17)
caught the sweep's own defects. The base-presence rule grouped tests 8 and 9
as "the ones that commit", but test 8 introduces the base and must start
is_none() -- the rule was unsatisfiable, or satisfiable by a fixture that
made the test assert nothing. And test 6's construction was
self-contradictory: assigned the commit path while required to arrive as its
hand-built ancestor did, and bundle.rs:1866 calls craft_image_with_base at
:1869. Fixed by a per-test state table, and by swapping the routes so the
attribution becomes true rather than deleted.
Round 19 (independent): ZERO FINDINGS. The first clean round in nineteen.
Recorded so ratification is not read as vindication: 65 findings across 19
rounds, 47 blocking. Rounds 1, 2 and 17 were authored-side; the first two
produced a ratification that was withdrawn, and the third cost two defects
round 18 caught. The document's quality comes from the independent rounds.
A clean round is the criterion named at round 11 and the first convergence
evidence this contract has produced. It is not proof of correctness, and no
round has re-derived the whole document. Still open after any ratification:
M7's authority/base leg is unverifiable until S27 is implemented, those
being S27's own deliverables, and every gate, test and mutation is specified
but none has been run.
The ledger is brought current; it had stopped at round 15.
Still NOT RATIFIED, NOT DISPATCHABLE. That call is not mine to make.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against fa483cf. One finding, blocking, and it ran the
scan rounds 13 and 14 left outstanding.
M6 accepted "test 5 fails" and "test 9 fails" as its observations. A test
fails for every reason, not only the one under test, so an unrelated writer
rejection satisfies both exactly as well as the intended cause. M6 could
have reported success while demonstrating nothing about pin 3a's scope.
Both halves now require the mutated outcome itself. After removing pin 3a,
test 5's stale commit must be observed to succeed, and the bundle to reopen
at the new generation with the stale base present. After broadening pin 3a,
test 9's otherwise unchanged commit -- one that does not touch
canonical_base -- must be observed rejected specifically by the broadened
writer rule, named in the report, not merely erroring.
The scan is complete: M1 through M5b survive it, M6 did not. That the one
remaining instance was in M6 -- the mutation twice rewritten for
unexecutability -- is worth noting. A mutation can be made runnable and
still not be evidential.
The principle, stated once so it need not be rediscovered: the evidence a
mutation owes is the behaviour it changed, not the assertion it broke. A
broken assertion is a symptom with many possible causes; the changed
behaviour has one. Every mutation in section 4 now names an outcome rather
than a failure.
Section 7 item 4a's M6 row was widened to point at M6 rather than restate
"test 5 fails; test 9 fails", which had become the weaker of two statements
of the same requirement -- round 14's lesson applied before it could bite.
Still NOT RATIFIED, NOT DISPATCHABLE; that call is not mine to make.
Findings 9, 6, 6, 5, 4, 3, 3, 2, 2, 1, 3, 2, 1, 1, 1. Blocking 4, 4, 4, 4,
2, 3, 3, 2, 2, 1, 2, 2, 1, 1, 1. Fifteen rounds, none returning zero, but
the character of the findings has changed: round 13 found a kind never
looked for, round 14 a contradiction round 13 created, round 15 the last
instance of round 13's kind with the scan complete across every mutation.
The known unexamined surfaces are now enumerable, which they were not
before.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against f579172. One finding, blocking, and a
contradiction round 13 created.
The comparison method still said equal images "complete the observation and
require nothing further". That was written in round 9, when byte equality
was the whole of M7, and was not swept when round 13 added the writer-check
control. The contract therefore simultaneously required the control and
licensed omitting it, with the permissive sentence sitting earlier and
reading as the summary. Equality is now necessary but not sufficient:
observation 1 of three, control still required. That paragraph now
specifies how to compare, never what suffices.
A second instance was found while amending, and round 14 reported none. The
"informative in both directions" note read "if every field matches, the
refusal is justified" -- the same sufficiency claim in different words,
still carrying round 8's "every field" vocabulary that round 9 had replaced
with whole-image comparison. A search for "nothing further" or "sufficient"
cannot reach a sentence that says "matches". That is the defect CLAUDE.md
names, searching one spelling and concluding about all sites, met inside the
fix for a sweep failure. Neither the reviewer's search nor my first search
found it; a third pass on different terms did.
The round-13 lesson generalises further than round 13 stated. It is not
only that a requirement must be swept to every site. It is that the
permissive statement usually reads earlier than the restrictive one, because
requirements accumulate downward as a document is amended, and a reader
following the document in order stops at the first sentence that says
"done". Where a later round narrows what suffices, the earlier summary is
the site most likely to contradict it and least likely to be searched.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings 9, 6, 6, 5, 4, 3, 3, 2, 2, 1,
3, 2, 1, 1. Blocking 4, 4, 4, 4, 2, 3, 3, 2, 2, 1, 2, 2, 1, 1. Fourteen
rounds, none clean, but the last two are single-finding rounds and round
14's was created by round 13 rather than pre-existing. Against that, round
13's question -- what else, besides the intended defect, would make this
pass? -- has still not been asked of M1 through M6, M5a or M5b, and round 14
did not ask it either. That scan remains outstanding and is the largest
known unexamined surface.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against bff9c9a. One finding, blocking, and it inverted
M7's result.
M7 claimed the capability check "does not fire". Pin 3a requires commit and
commit_versioned to validate a newly emitted canonical base, which is
exactly what both B_raw and the parsed A commit. The check fires on both
paths and accepts, because the raw version equals the real authority. That
acceptance is the laundering result: the base is not slipped past an absent
check, it is admitted by a check working correctly that cannot tell a
coincidence from a rebuild.
As written, M7 was satisfiable by deleting pin 3a's writer check entirely --
a passing M7 demonstrating the exact opposite of its purpose.
M7 now requires three observations: A.image() equals B_fixed.image(); pin
3a's validation ran and accepted on both commits; and a control. The control
is required -- in the same run, same harness, repeat the import with a base
version deliberately not equal to the real authority and observe the commit
rejected with CanonicalBaseRequiresRebuild. The matching case succeeding
means something only once the mismatching case is seen to fail on the same
path, under the same removals.
M7's removals are now explicitly limited to the text refusals. Pin 3a is not
among them and may not be weakened: it is the thing under observation, not
an obstacle to it. Removing both boundaries would not be a stronger
mutation, it would be a different and empty experiment.
This is a new failure shape worth naming: an observation satisfiable by the
absence of the thing it observes. M7's earlier defects were about being
unrunnable, or comparing the wrong artifacts. This one would have run,
passed, and reported success on a tree where the writer check had been
removed. "The check does not fire" cannot distinguish a check that accepts
from a check that is not there, and only one of those is the finding.
Two dependent sites updated as pointers rather than restatements: section 7
item 4a's M7 row now owes every observation including the control, and item
1 notes the control's expected outcome is a rejection, so a reporter does
not read it as a problem.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings 9, 6, 6, 5, 4, 3, 3, 2, 2, 1,
3, 2, 1. Blocking 4, 4, 4, 4, 2, 3, 3, 2, 2, 1, 2, 2, 1. Thirteen rounds,
none clean. Round 13 is the narrowest since the probe, but it asked a
question no earlier round had asked -- not "can this run?" or "does this
compare the right things?" but "could this pass for the wrong reason?" --
and that question has not been put to M1 through M6, M5a or M5b.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against 74dc994. Two findings, both blocking, and both
the same defect -- a requirement stated without the decision it requires,
leaving execution to make a design choice silently.
The convergence loop was not actually bounded. It demanded a bound and
named no limit, so execution would have chosen when non-convergence becomes
failure, changing what the experiment means. Now pinned at one normalising
step: with B0 = B_raw and B(n+1) = serialize_document(document_from_bundle(Bn),
uuid), compute at most B1 and B2, permitted maximum n = 1, with a three-row
outcome table. B1 == B0 means B_raw was already fixed. B1 != B0 with
B2 == B1 is the expected case. B2 != B1 is a hard failure that must report
all three image lengths and the first differing offset.
The bound is one step because it is a property, not a tolerance.
document_from_bundle canonicalises, so serialize_document after
document_from_bundle must reach its canonical form in a single application.
If it does not, there is no canonical form, no principled reference
artifact, and M7 is invalid as a whole -- a finding about the projection
rather than a signal to iterate further. A loop that runs until it happens
to settle tests nothing; it reports how long it took. Raising the bound
needs its own amendment and review round.
M7's location was unchosen. "In a crate that can reach the real constant"
is true of two crates and decisive for neither, and render_text_document is
pub(crate) to epiphany-textproj, so epiphany-testkit could host M7 only via
an unpinned visibility change to another crate's public API. The harness is
now pinned to epiphany-textproj, which alone has both the renderer and, via
its epiphany-ops dependency, the real constant. It lands under existing
touch row 9; no new row.
render_text_document stays pub(crate). Handoff section 1.3 records it as the
one intentional hole in the text refusal, existing solely so a negative
vector can carry the spelling it asserts is refused. Widening it to host a
mutation that gets reverted would leave a permanently widened public surface
behind, which is how a temporary harness becomes an API change nobody
ratified. That improvisation is what execution would have reached for on
hitting the wall, which is why the decision belongs here.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings 9, 6, 6, 5, 4, 3, 3, 2, 2, 1,
3, 2. Blocking 4, 4, 4, 4, 2, 3, 3, 2, 2, 1, 2, 2. Twelve rounds, none
clean. The last two rounds found the same kind of defect -- a requirement
that reads as a decision but is not one -- so the next scan should hunt
remaining instructions that name a constraint without naming its value.
Everything M7 now specifies is pinned to a number, a crate or a named
artifact, which is a checkable property a round can test directly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against 39f2617, post-probe. Three findings, two
blocking. It confirmed the probe contained and its fixed-point result
decisive, and kept M7 blocked.
M7 still lacked a distinct normalized reference. Round 10 named one
artifact where the comparison needs two. Now: build B_raw under the real
authority; iterate derive-and-reserialize until B_fixed is a byte-level
fixed point; assert that property explicitly as a hard failure; and compare
the imported artifact only with B_fixed, never with B_raw. Otherwise an
envelope-order normalization difference stays indistinguishable from a
provenance result, and a comparison whose failure mode cannot be told from
its success condition decides nothing. The convergence loop is bounded and
must fail if it does not converge -- the probe saw one pass suffice for
three documents, which is not proof that one pass always suffices -- and
the iteration count plus whether B_raw was already fixed must be reported,
so a reader can tell the lucky case from the general one.
The claim was stated more broadly than any observation supports. M7 read as
though every direct bundle is byte-identical to its re-imported form. It is
not, and the probe measured 295 differing bytes proving so. Scoped now: M7
proves the text path carries no provenance marker after normalization, and
explicitly not that every direct bundle is byte-identical before it, since
the pre-normalization differences are document_from_bundle's canonical
envelope ordering and have nothing to do with provenance. Both sentences
must appear in the report; the unqualified version is false as written and
is the one a reader would otherwise carry forward.
That finding has consequences beyond M7. Its conclusion is the sole
evidence for a permanent capability loss -- the text refusal that moved
COMPANION_VERSION to 0.14.0 and took the corpus's canonical_bases from 2 to
0. Justifying a permanent refusal from a claim broader than the result
obtained is the same error as concluding instead of observing, one level up:
not a false observation, but a true one asked to carry more than it can.
Third, a clarification rather than a defect: the probe cannot pre-verify
M7's authority/base leg, which needs BundleCapabilities, capabilities() and
pin 3a's validation, all S27's own deliverables. That stays an execution
requirement after S27 implementation, with the probe as evidence for the
prerequisite and explicitly not as a demonstration of laundering, since it
carried no base. Recorded as a standing prerequisite table: the round-trip
leg is settled, the authority leg is not pre-verifiable by any review or
probe.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings 9, 6, 6, 5, 4, 3, 3, 2, 2, 1,
3. Blocking 4, 4, 4, 4, 2, 3, 3, 2, 2, 1, 2. Eleven rounds, none clean.
Round 11 broke the falling trend, and did so because the probe supplied
evidence that made a previously invisible defect findable -- a reason to
expect the next round to find more rather than less. The comparator is on
its fifth design: four falsified by reading, the fifth by execution and then
rebuilt on that evidence. It is the first with a measured result behind it
and the first whose precondition is asserted rather than assumed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Bounded scratch probe, authorised as an explicit narrow exception, run on a
branch that has been deleted. It falsified round 10.
Recorded as evidence in its own right: M7 cannot be executed until S27
lands. BundleCapabilities and CURRENT_REDUCTION_ALGORITHM_VERSION do not
exist in the tree -- they are S27's own deliverables -- and M7 step 1 needs
a base committed under the real authority. M7 is a mutation of this rung's
implementation, so it runs after the rung, not before. The probe therefore
tested the round-trip machinery M7 depends on, base-free, which removes no
refusal since both project_text_document and serialize_document gate on
canonical_base.is_some().
Result: the round trip is byte-preserving, but only from a fixed point, and
round 10's comparison did not compare from one. It compared A against a B
built from the input document, which is valid only when that document is
already a fixed point of document_from_bundle after serialize_document.
minimal_document(42) happens to be one, so the first probe passed and would
have been reported as success. minimal_document(99) was not. The
one-extension case diverged by 295 bytes from offset 352. Rebuilt from the
fixed point, all three cases are byte-identical at 1641, 1800 and 1894
bytes.
The non-idempotent field is envelopes, not extensions. Diagnosed field by
field: document_id, manifest_schema_version, lineage_id, profiles,
canonical_base, blobs and extensions -- including every TextChunk payload
-- survive exactly. document_from_bundle applies a canonical envelope
ordering, as its own test name says, so a document whose envelopes arrive in
any other order is not a fixed point and its operation-block bytes differ.
project_text_document into parse_document proved lossless: b_doc == d in
every case. The text leg was never the problem. The defect was entirely in
which artifact round 10 chose as the reference.
What M7 must add, for round 11 to ratify rather than for this probe to
assume: an explicit fixed-point normalisation and assertion before any byte
comparison, because otherwise a mismatch is round 10's own unclassifiable
third category.
Probe hygiene: the comparison was mutation-verified -- a different FileUuid
for A produced 20 differing bytes at offsets 32-47 and 60-63, observed, then
restored by hand-editing. That incidentally confirms round 9's point that
FixedHeader.file_uuid is byte-visible and round 8's enumeration had omitted
it. One file touched, 142 insertions, all inside cfg(test); no refusal
removed; no canonical base carried, so the live constraint was never
engaged; diff captured before the branch was deleted.
Four paper rounds refined this comparison and none found that it silently
depended on an unstated precondition. One execution found it in minutes, via
the case a reviewer would least likely hand-pick. Had the probe stopped at
the case round 10 implied, the contract would have been ratified on a
comparison that fails for most documents.
Still NOT RATIFIED, NOT DISPATCHABLE. Pins unchanged; the probe produced
evidence, not amendments.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against 0efd543. One finding, blocking, the smallest
round yet, and again in M7.
The whole-image comparison had no complete construction alignment. Round 9
named four things to align, but serialize_document also fixes document_id,
lineage_id, profile_declarations, every extension's fields and preserved
chunks, the envelope payloads, the staging order (base root, then extension
chunks, then the operation-envelope block), the manifest schema major and
epoch_max, and every chunk ref, hash and offset derived from those. So a
byte difference would have had a third possible cause -- the reference was
built differently -- which is neither permitted classification. The result
would have been unclassifiable, and a result that cannot be classified is
not an observation.
M7 is now a round trip. Build B validated under the real authority, export
it to text via document_from_bundle and the crate-private
render_text_document, parse that text back, re-serialize as A with B's
FileUuid, compare whole images. Alignment is inherited rather than
enumerated: every input serialize_document reads is already B's own, so no
list can be incomplete, and the setup-mismatch category is eliminated by
construction rather than by care. It is also the realistic form of the
threat -- export a validated document to text, re-import it, and observe
the re-imported container is indistinguishable from the original, having
validated only the base's number and never its provenance.
This was the third hand-enumerated "complete set" in this contract and the
third to be wrong on the day it was written: "every field that could carry
provenance" in round 8, "every field to align" in round 9, and round 9's
list again now. The rule earned across rounds 5 through 10 is one rule --
where a claim requires completeness, do not enumerate, derive. Tables
instead of counts, whole artifacts instead of field lists, one shared
origin instead of an alignment list.
Two further sites caught while amending: the restore instruction's refusal
count, invalidated for the third time by the restructure, and round 8's
disposition cell still reading as current. M7 now states no refusal count
anywhere -- three successive wordings each had a wrong one.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings 9, 6, 6, 5, 4, 3, 3, 2, 2, 1.
Blocking 4, 4, 4, 4, 2, 3, 3, 2, 2, 1. Ten rounds, none clean. Three
consecutive rounds have found one paragraph defective in a new way each
time. Findings are falling steadily and the last three have each been
narrower than the last, which is the first sustained convergence signal
here. Against that, M7 has never been executed and each of its four designs
looked correct when written.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against 01e76d1. Two findings, both blocking, both in
M7's comparator -- the text round 8 had just rewritten.
Test 10b is not the genuinely validated reference M7 nominated. Its
write-side capability is synthetic_for_fixture(0) and only its reopen uses
the real authority, so M7 would have compared one synthetic fixture against
another with the validated half of the claim absent.
This is a collision between two of the contract's own designs, not a typo.
Round 4 made 10b synthetic-on-write deliberately so M5b's two operands
would be provably independent, and that is exactly what disqualifies it
here. One artifact cannot be both independent of the real authority and
committed under it. Round 8 reused a fixture by name without re-reading
what it had been built to be -- a failure no amount of care about wording
would have caught. M7 now builds its own reference in epiphany-testkit,
committing a base under caps derived from the real constant so pin 3a
validates it on the way in.
The field enumeration could not support its conclusion. It claimed
"everything that could carry provenance" while omitting
FixedHeader.file_uuid -- the field it required to match -- plus the
superblock's generation, manifest_offset, manifest_length and
manifest_hash, and the whole manifest outside canonical_base. Replaced with
whole-image() byte comparison, any difference enumerated and classified
either as justified nondeterminism, normalized with its cause stated, or as
a provenance signal, which is a finding since the refusal may then be
stronger than it needs to be.
That finding retires a technique rather than an instance. A hand-written
list of "every field" is a claim about a struct's contents that is wrong
the moment the struct changes, and this one was wrong the day it was
written. Comparing the whole artifact cannot be incomplete. Same lesson as
tables over numbers, applied to the experiment instead of the prose.
Three further sites caught while amending: section 7 item 6 still said
"M7's three text refusals", surviving round 8's correction of that exact
count in two other places; item 4a's M7 row still named the superseded
method; and round 8's own disposition cell stated it as current. All now
point at M7 rather than restating it.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings 9, 6, 6, 5, 4, 3, 3, 2, 2.
Blocking 4, 4, 4, 4, 2, 3, 3, 2, 2. Nine rounds, none clean. Rounds 8 and 9
both found defects in the preceding round's rewrite of the same paragraph,
so M7 has been wrong in three distinct ways across three consecutive
rounds: unrunnable, wrong artifact, wrong method. The comparator is on its
third design and has never been executed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against 9829ae3. Two findings, both blocking, and the
first round to reach into a mutation's mechanics rather than its
bookkeeping.
M7 did not describe a runnable observation. It told execution to construct
a base-bearing TextDocument, which bypasses parse_document entirely -- so
the parser refusal it ordered removed was irrelevant, and the demonstration
was not the import laundering it is named for. project_text_document has
the signature &TextDocument -> Result<String, _>: it is the export
direction and is not on the import path at all, so "all three sides, since
removing one leaves the others refusing and the document never reaches the
writer" was false for it. And "byte-indistinguishable from one whose base
was genuinely validated" named no comparison artifact and no comparison
method.
M7 now requires text that is parsed, not a constructed document; removes
and restores only the parser and serializer refusals; names test 10b's
construction as the comparison artifact, built with the same FileUuid and
base bytes; and requires a field-by-field enumeration of the canonical_base
SnapshotRef, the superblock's reduction version, and the header's major and
epoch -- reported rather than concluded. It is informative in both
directions: a field that does differ is a provenance signal nobody knew
existed, and that is a finding rather than something to suppress.
The round-7 deduplication was incomplete. The status block still carried
"rounds 3 and 4 are closed" while declaring the history table the sole
authority for that. Deleted.
Finding 1 is the most substantive of any round so far, because every
earlier one was about text agreeing with other text. This is about whether
the experiment runs at all, and it did not. M7 has been in the contract
since round 1 and survived seven reviews, three of which specifically
re-derived mutations, because reading it never required tracing what calls
what. An observation stated in the right register can look complete for a
long time. "Indistinguishable" was a conclusion, not an observation --
which is the exact failure mode this rung exists to eliminate, sitting
inside its own demonstration.
While amending I caught a third instance unaided: section 7 item 4a's M7
row still said "all three refusals". Fixed by pointing at M7 rather than
restating, per round 7's rule.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings 9, 6, 6, 5, 4, 3, 3, 2.
Blocking 4, 4, 4, 4, 2, 3, 3, 2. Eight rounds, none clean. The M7 rewrite
is now the least-reviewed material in the contract, and its predecessor
survived seven rounds while being unrunnable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against c0d896c. Three findings, all blocking, and all
three the same defect -- a claim living in two places and fixed in one.
Section 7 item 4a was unsatisfiable. It required every mutation to name the
test it breaks, while item 1 four paragraphs above states that M4 is
observed to compile -- no test is possible, which is precisely why pin 3's
prohibition is a review rule -- and that M7's expected outcome is success.
A report obeying 4a literally could not be written, and the honest response
would have been to invent a test for one of them. 4a is now a table of what
each of the eight mutations owes, with M4 and M7 carved out.
Round 6's three-literal correction reached section 7 and not section 3.
Section 3 still said "both literals ... tidying either", so the contract
carried the fixed and the broken version of the same claim, reopening the
narrow-scope ambiguity round 6 existed to close. Section 3 no longer states
the count; it points at item 4b.
"Rounds 3, 4 and 5 were independent" went stale the instant round 6 closed,
sitting in prose beside the table whose own column records it. Deleted.
Three rounds, one lesson. Round 5 fixed the review totals and not the
amendment tally beside them. Round 6 fixed item 4b and not section 3's copy
of the same rule. Round 7 found the classification sentence duplicating the
table's column. The defect is duplication, and every previous remedy was
vigilance -- check the other sites too -- which has now failed three rounds
running.
The remedy adopted here is deletion, not diligence. Where a claim had two
homes, one is removed and replaced with a pointer: section 3 no longer
counts the literals, the history block no longer classifies the rounds, and
the status line no longer lists which rounds have closed. A copy that
cannot drift is one that does not exist.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings by round 9, 6, 6, 5, 4, 3, 3
-- flattened rather than still falling. Blocking 4, 4, 4, 4, 2, 3, 3, with
rounds 6 and 7 both 100% blocking and 100% in the previous round's text.
Seven rounds, none clean. The deduplication is the first structural remedy
for this defect and therefore the first with a reason to work, and it is
untested.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against 03c85dd. The first round where every finding
was blocking and every one was in the previous round's amendments.
The amendment tally went stale inside the block round 5 restructured to
prevent exactly that. Round 5 turned the review totals into a table and
left "amended five times ... rounds 1-4" as prose immediately above it.
There is no longer a separate amendment count: it is the number of rows.
Section 3's test-home correction was itself false. Round 5 wrote "tests 1-9
in epiphany-bundle", but test 7 is assert_reduction_serialization_stable,
which the same section names as testkit/src/roundtrip.rs. Two wrong
versions of that sentence, both written while fixing it. Replaced with a
per-crate table: 1-6/8/9 in bundle, 7 and 10b in testkit, 10a in textproj.
Section 7 item 4b protected one operand where test 10b has two. Replacing
both synthetic_for_fixture(0) and the committed base's
ReductionAlgorithmVersion(0) with the constant keeps the synthetic call
exactly where it is and fully restores the tautology -- and test 10b's Err
arm never executes in the unmutated run, so its literal cannot detect it.
Item 4b now enumerates all three fixture operands individually and requires
each quoted verbatim.
All three are one defect in different clothes: a fix applied to the site
named rather than to every site the claim covers. Sixth count-staleness
defect in six rounds; third range-correction that did not check its own
range.
The mechanism that works is structural, not vigilant. The review totals
stopped going stale when they became a table. The amendment count did not,
because it stayed prose. Item 4b stopped being under-specified when it
became a table.
Demonstrated a seventh time inside this amendment: the new table's Total
row was first written "6 amendments", a free-standing count three
paragraphs after the sentence declaring no such count exists, and already
wrong at seven rows. Caught before commit and replaced with "one amendment
per row". Prose invites a number and a table does not, so the defence has
to be the shape of the artifact rather than the attention of the editor.
Still NOT RATIFIED, NOT DISPATCHABLE. Findings by round 9, 6, 6, 5, 4, 3 --
falling monotonically. Blocking 4, 4, 4, 4, 2, 3 -- not falling. No round
has yet come back clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against df9e528. Four findings, two blocking -- the
first round in which blocking findings fell below four.
The status history still said "amended three times ... fifteen findings so
far, eight of them blocking". Those are the round-2 figures, left standing
through rounds 3 and 4 while the tables recording those very rounds sat
directly below them. Fifth count-staleness defect in five rounds, and it
was in the one block I edited every round. Replaced with a table so a round
appends a row instead of requiring a number to be found and re-derived.
Running tally is now 30 findings, 18 blocking.
Test 10b could not make the two-field assertion M5b requires. Section 3
said only "assert it opens", and under mutation that yields a bare Err or a
panic. A #[test] returning Result that returns Err asserts nothing about
that error's fields, so M5b's required observation of
CanonicalBaseRequiresRebuild { base, current } had no home in the test M5b
names. Both Result arms are now pinned, plus a third arm for the
wrong-error case -- without it an implementation returning a different
error under mutation still fails the test and the report reads as success
while observing nothing.
M5b's claim that the literals cannot be tidied without deleting the
synthetic capability was false. Keeping synthetic_for_fixture while passing
CURRENT_REDUCTION_ALGORITHM_VERSION as both its argument and the base
version preserves the fixture and fully restores the tautology. Retracted.
The protection is section 7 item 4b, the positive check that the literals
are still literals. Round 4 asserted a structural guarantee that did not
hold and thereby undercut the procedural check actually doing the work,
which is the same error as reasoning that a mutation would fail instead of
running it.
Section 3's preamble still said the tests were in epiphany-bundle after
round 4 added two that cannot be -- epiphany-bundle must not depend on
epiphany-ops, and reaching the real authority is the whole purpose of 10a
and 10b. Corrected, with each test's touch-table home named.
Still NOT RATIFIED, NOT DISPATCHABLE. Blocking findings by round are 4, 4,
4, 4, 2 -- the first movement in four rounds and the first weak evidence of
convergence, against the fact that every round since the third has found
blocking defects in text written to fix its predecessor.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against 53292f6. Five findings, four blocking. Round 4
accepted pin 3's capabilities() accessor as bounded -- the first new text
any round has passed -- and rejected both halves of M5 again.
M5b cited the wrong value, and this one is mine. roundtrip.rs:367 sits in
assert_score_serialization_stable, not assert_reduction_serialization_stable,
and it versions an acceleration snapshot, not a canonical base. The latter
has no base at all, because pin 3c suspended it. So the value round 3 told
the implementer not to touch was irrelevant to the authority check, and
mutating it could not have failed anything. Round 3 grepped
ReductionAlgorithmVersion across testkit/src/, saw a roundtrip.rs hit, and
attributed it to the function it was already thinking about without
resolving the enclosing item -- the same shape as section 0.4's .commit(
miscount, which round 1 had already recorded as a lesson. Recording a
defect is not the same as not committing it. The tautology diagnosis
stands; only its evidence was wrong.
M5b left the instrument unchosen. Round 3 said "the rung picks one" and
named two routes, one of which does not exist for the nominated crate:
craft_image_with_base is a private fn inside epiphany-bundle's cfg(test)
module. Now chosen, through public API only: build with
synthetic_for_fixture(0), commit a base carrying the literal 0, take the
bytes, reopen under the real constant. The operands are provably
independent and neither can be tidied into the other.
M5b had no test that could assert the error fields.
assert_reduction_serialization_stable returns () and reopens with .expect,
so a mismatch panics instead of yielding a matchable
CanonicalBaseRequiresRebuild { base, current }. Test 10b added, named and
returning a matchable Result.
M5a violated section 7 item 4a -- the rule round 3 added in the same edit.
It named no test, and its natural assertion compares
CURRENT_REDUCTION_ALGORITHM_VERSION with itself, which holds for every
value. Test 10a added, asserting against a deliberate literal. Round 3
diagnosed M5b's tautology and wrote the identical tautology into M5a in the
same edit, then added a rule and immediately broke it.
Both literals are load-bearing as literals. Section 7 item 4b now requires
confirming neither was rewritten as the constant -- tidying either makes
its mutation vacuous while every test stays green.
Minor: status prose said the pins were open to round 3's findings after
round 3 closed.
Still NOT RATIFIED, NOT DISPATCHABLE. Defect rate 9, 6, 6, 5 -- not
converging, and every blocking finding in rounds 3 and 4 was in text
written to fix the previous round.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Independent review against b842975. Six findings, four blocking. Every
blocking finding was a defect in text rounds 1 and 2 wrote.
Pin 3a still carried the rationale round 2 retracted. Section 0.4 says
there is no in-tree production base writer; pin 3a still said "0.4 shows
production code minting a stale document". The contract asserted a claim
and its negation. Rewritten onto the footing that survives: commit and
commit_versioned are public API and guard out-of-tree callers, not an
in-tree path. This is the third occurrence of fix-one-site-leave-the-
others -- round 1 fixed one spelling of a count, round 2 fixed section 0.4
and left the Rung type paragraph and touch row 2.
M5a had no observation mechanism. Pin 3 required the capability be stored
and nothing exposed it; Bundle has 17 public accessors and none for
capabilities, so no textproj test could inspect it. Bundle::capabilities()
is now pinned. That is new scope and is flagged as such for round 4.
M5b could not fail. If the supplied capability and the base version both
derive from CURRENT_REDUCTION_ALGORITHM_VERSION -- the natural
implementation, since roundtrip.rs:367 hardcodes ReductionAlgorithmVersion(0)
today -- both operands move together and the comparison passes for every
value of the constant. That is section 0.1's own tautology reproduced
inside the mutation built to detect it. The base version must now come from
a source that does not track the authority, and both operands' provenance
must be reported.
M6's replacement named a scenario with no test. Test 6 stops at opening, so
nothing asserted that an unrelated commit succeeds; an implementation
rejecting every post-base commit passed tests 2/5/6/8 and the broadening
had nothing to break. Test 9 added.
Cleanup: touch row 7 listed generators.rs as "call sites, real authority"
though it has zero Bundle::open/create calls, and its rng.range(0, 8)
versions are exactly the arbitrary wire values pin 3b assigns to synthetic
capabilities -- split to row 7a. Section 7's call-site attribution credited
round 1 where rounds 1 and 2 are both load-bearing.
The pattern is legible now and it is not about counts. Round 1 found stale
text, round 2 found unexecutable mutations, round 3 found that three
separate mutations were unrunnable in three different ways: M5a could not
observe, M5b could not fail, M6 had nothing to break. A mutation is only as
good as the test it breaks. Section 7 item 4a now requires, for every
mutation, the named test it breaks and the provenance of each operand.
Still NOT RATIFIED, NOT DISPATCHABLE, pins not frozen. Defect rate across
three rounds is 9, 6, 6 -- not converging. The newest text has had zero
adversarial passes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Round 1 claimed ratification after a single round. Round 2 then found four
more blocking defects against the supposedly frozen text, two of them
introduced by round 1's own amendments. A ratification a later round
falsifies that quickly was not one, and leaving the claim standing would
make the status field mean nothing.
Status is now NOT RATIFIED, NOT DISPATCHABLE, pins NOT frozen, awaiting an
independent review round 3 against b842975. Freezing follows ratification;
it does not precede it and does not survive a withdrawal. No execution work
may begin -- not implementation, not staging, not partial work against "the
settled pins."
Also disambiguated the two senses of dispatchable that round 1 conflated.
Unblocked means the dependency chain cleared, true since bc06706.
Dispatchable means ratified and frozen and ready to execute, false. Reading
the first as the second is how this came to be ratified after one round.
Both prior rounds were run by the same agent that authored the amendments
under review. Round 3 is the first that will not be.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
Round 1 ratified after a single round. Round 2, run against the frozen
contract, found four more blocking defects -- two of which round 1 created.
Ratification was premature and the status now says so.
Blocking:
The call-site correction was applied to section 0.4's table only. The "Rung
type" paragraph still said 57, and touch row 2 still said bundle.rs has 35
opens -- a figure that was never bundle.rs alone (it was bundle.rs plus
fuzz.rs, which has its own row) and is stale besides. bundle.rs has 23. The
reconciliation section 7 requires was impossible against those numbers.
Fixing one spelling of a count and leaving two others is the same defect
round 1 reported as finding 5.
Section 0.4 called project.rs:936 a production bundle writer. cfg(test)
starts at project.rs:630 and every Bundle call in the file is below it --
create at :983 and :1122, open at :1147. The writer-path correction stands
on serialize.rs alone, whose create and commit_versioned are above its own
cfg(test) at :284. Round 1 verified the editor-core claim in that paragraph
and inherited its neighbours.
M5 was unexecutable. serialize_document refuses base-bearing documents at
serialize.rs:151, before Bundle::create, so its output is necessarily
base-free; pin 5 and test 4 require base-free bundles to open at any
authority. Changing the constant cannot make a textproj production test
fail. Split into M5a (production wires the constant) and M5b (the authority
is load-bearing where a base exists, via testkit's restored base coverage).
M6's second half was unexecutable. open rejects a stale base, create
rejects a base-bearing manifest at bundle.rs:234, and commit validates what
it emits, so no caller can hold an open Bundle with a stale inherited base.
Replaced by broadening pin 3a rather than narrowing it, which is reachable.
The unreachability is itself reported: pin 3a's scope is forced, not
chosen, which is stronger than what the mutation was written to obtain.
Non-blocking: pin 3a's justification, that production code mints a
self-consistent stale document without calling open, is false in-tree --
zero production paths stage a base, since the format rung's pin 3b closed
the only one. It now rests on guarding the public commit_versioned API
against out-of-tree callers. And serialize.rs:157 is dead code orphaned by
the :151 guard, recorded as a finding and explicitly not repaired here.
Two of these were introduced by round 1: ruling M7's refusal permanent is
what made M5 unexecutable, and test 8 was added on the write side without
re-deriving M6 against the same reachability. An amendment is a change to
the system, not a patch to a line.
Round 3 is warranted before dispatch. The defect rate has not fallen -- 9,
then 6 -- and dispatchable is a claim requiring evidence of convergence,
not a status reached by running out of findings.
Documentation only; no code reads .md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
The contract had reached "dispatchable" with zero ratification rounds on
record, against the standing rule that contracts go through adversarial
review before dispatch. The format-epoch rung had four, and its fourth is
what produced pin 3c. This is S27's first.
Blocking:
Inherited obligation 2 -- M8's laundering demonstration -- was in neither
the test section nor the mutation plan, while that section's preamble
claimed all three inherited obligations were "stated as tests so they
cannot be discharged by prose". It was also ambiguous between temporarily
lifting the text refusal and permanently restoring the capability, which
differ by four touch rows and a COMPANION_VERSION bump. Ruled a mutation:
the refusal is permanent, and the demonstration is now M7, with its
expected outcome recorded as success rather than failure.
Section 0.4 claimed "commit has 57 sites (including 2 in
epiphany-editor-core)". That crate depends on core, ops and layout-ir --
not bundle -- and the word Bundle appears in its lib.rs zero times. The two
hits are self.commit(...) resolving to its own method. A textual .commit(
grep counted a same-named method in a crate that cannot reach Bundle. That
is the third instrument failure recorded in that one section, and it was
committed in the same paragraph as the method note warning about the
second.
Three independent stale list-counts: the test section's header said "names
all four" over seven items, gate 1 said "four tests added", and three
report items named five mutations, seven gate results and four tests. All
replaced with "every item in section N". The delta was never a simple
addition anyway -- three tests convert or extend existing format-rung
tests, which nets zero.
testkit/tests/requirement_labels.rs was absent from the touch table while
pin 9 may move CORE_REQUIREMENT_COUNT from 213. Pin 9 must now decide
explicitly whether it mints a label; touch row 12 carries the file
conditionally. This is the escapee CLAUDE.md names, and it escaped the
format-epoch rung too.
Non-blocking: locator drift since 381c498 (bc06706 grew bundle.rs by 338
lines; correction table added, and pin 5's own :396-:399 confirmed
unmoved); pin 2a's corpus evidence superseded by the 2 -> 0 rebuild;
Bundle::open( 57 -> 60, create confirmed still 32; gate 6a widened to
epiphany-testkit, which touch row 7 gives the real authority; and a missing
commit-side positive test, added as test 8 -- obligation 1 warns that
converting one branch leaves a hole, and that branch had none.
Pins are now frozen. Documentation only; no code reads .md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
spec/HANDOFF_2026-08-07.md: state of the spec / Pass-13 / format-epoch
thread at be244df, the live constraint that no bundle may carry a
canonical base until P13-S27 lands, the S28 -> S27 -> S16 chain with
S27's three inherited obligations, the working agreements that are not
derivable from the code, and the environment notes the other machine
needs (xelatex not pdflatex, the 1.95.0/1.85 toolchain pins, the
cargo fmt --all trap and why its --check form is safe).
Section 2 covers the parallel editor/T4 thread and is explicitly
bounded: those files were out of bounds for this session all along, so
it records only what shared git history shows plus leads to verify, and
says plainly that it is not a substitute for that session's own handoff.
It does name the one place the threads can collide — the canonical-base
interval — which neither side can see from its own side.
Ledger: P13-S27 and P13-S28 both still opened with "open" while their
resolutions sat further down the cell. S27 is UNBLOCKED and
dispatchable; S28 is IMPLEMENTED. The cells are appended to rather than
rewritten, so an opener can lag the truth by several rungs; the handoff
records that as a reading hazard.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
document_from_bundle refused a base-bearing bundle, but the public
project_text_document did not. A caller holding a directly constructed
TextDocument could therefore emit a (canonical-base ...) line that
parse_document then rejects — a projector able to produce what the
parser refuses, which is precisely the asymmetry pin 3b exists to close
and which req:textproj:roundtrip's second equation quantifies over.
The guard had been placed on the path the pin happened to name rather
than on every path a caller can reach, and the unguarded one was the
only reachable half: no live Bundle can carry a canonical base during
the S28 -> P13-S27 interval, so the bundle-side refusal cannot fire
today, while the document-side path is one public call away. The new
corpus vector proved the hole existed rather than closing it — it is
built by projecting a base-bearing document.
project_text_document now returns Result and refuses. A crate-private
render_text_document keeps the unchecked formatter for its one
legitimate caller, the canonical_base_present negative vector: a
negative vector still has to contain the spelling it asserts is
refused, and producing those bytes is not the same as permitting them.
Every other vector goes through the checked projector.
projecting_a_base_bearing_text_document_is_refused locks both halves —
that the public projector refuses, and that the private renderer still
emits the section, since the reject vector silently stops carrying its
spelling otherwise. Mutation-verified: removing the refusal fails that
test and nothing else. Restored by hand.
The corpus is byte-identical, so no vector regenerated. Workspace green
at 1570.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
FORMAT_MAJOR becomes 1 and FORMAT_MINOR restarts at 0. The decoder
stops being exact-major-only: it classifies three ways through a named
FormatEpoch carried on FixedHeader, so major 0 is decoded deliberately
as legacy rather than refused. Old readers already fail closed on an
unknown major, so that half needed no mechanism — which is why the major
is the right carrier, and why the header's immutability, fatal to
FORMAT_MINOR as a provenance field, is what makes it sound as an epoch
field.
The matrix: a major-0 bundle with no base may open; one carrying a base
is refused; one attempting to add a base is refused and told to repack.
That last row is the non-inheritance rule. Three errors, none of which
degrades to read-only: two permanent legacy/repack errors, and
ReductionAuthorityUnavailable, which is temporary, names P13-S27, and
must not say repack — a major-1 container is already the right epoch.
Until P13-S27 lands, both major-1 base boundaries are closed: opening a
major-1 bundle that already carries a base, and committing one into it.
Neither may be left open while the epoch asserts a validation that never
ran.
Text projection cannot mint a base. serialize_document staged a carried
base into a fresh bundle and build_manifest wrote it, so an old or
hand-authored document could be laundered straight through the boundary.
All three sides now refuse: projection, parsing, and a new dedicated
SerializeError variant — none of which existed to be "retained".
COMPANION_VERSION moves to 0.14.0 and the corpus is rebuilt to 20
vectors and ten rejection classes, with canonical_bases reach dropping
2 -> 0. That is a real capability loss and is recorded as one.
Corruption keeps precedence in both epochs: a corrupt major-1 base fails
as malformed, never as the temporary authority error a user would
reasonably retry.
All 11 mutations were run and observed, not reasoned about. M4 is the
signing one — with the legacy commit refusal removed, a legacy container
gains a base in place, which is exactly the counterexample that killed
FORMAT_MINOR. M11 confirms the third error is distinct while test 3
stays green, proving the mutation stayed inside the major-1 branches. M7
fails on both epoch halves. M8 falls through to
SerializeError::Bundle(ReductionAuthorityUnavailable), confirming the
text layer's own refusal is what the test asserts.
Two touch-table gaps surfaced during execution, both the same shape: a
.tex requirement addition moves hardcoded counts in
requirement_labels.rs, and the companion bump moves a second normative
version literal spelled version~0.13.0 rather than (0 13 0). Neither
file was in any touch table; the second was caught only because a test
exists for exactly that failure.
P13-S27 is unblocked — its pin 2a is resolved from outside, as its own
prohibition required — and inherits three obligations: both interim
refusals converted to validation, M8's deferred laundering
demonstration, and pin 3c's two suspended conformance assertions.
P13-S16 remains blocked on S27.
Workspace green at 1569.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
P13-S28 asked for a container property old readers cannot silently
accept and a later commit cannot inherit unchanged. The format major is
that property. FORMAT_MAJOR moves 0 -> 1, FORMAT_MINOR resets to 0, and
the decoder stops being exact-major-only: it classifies three ways
through a named FormatEpoch, deliberately decoding major 0 as legacy.
Old readers already fail closed on an unknown major, so that half needs
no new mechanism — which is why the major is the right carrier and the
header's immutability, fatal to FORMAT_MINOR as a provenance field, is
exactly what makes it sound as an epoch field.
The eight-row matrix carries the rule: a major-0 bundle with no base may
open, one carrying a base is rejected, and one attempting to add a base
is rejected and told to repack. That last row is the non-inheritance
rule. Legacy resolves to hard rejection, never read-only — a
pre-authority base is not a restricted-but-correct view.
Three things the review rounds found, none visible at filing:
It cannot stamp major 1 before S27's writer enforcement exists. Pin 3a
therefore closes both boundaries temporarily — opening a major-1 bundle
already carrying a base, and committing one into it — through a third,
temporary error that names P13-S27 and must not name repack, since a
major-1 container is already the right epoch.
Text projection launders provenance straight through the boundary:
serialize_document stages a carried base into a fresh bundle and
build_manifest writes it. Resolved as symmetric document-level refusal —
projection, parsing, and a new dedicated SerializeError variant. None of
the three existed to be "retained"; an earlier draft claimed otherwise
and was wrong. This forces COMPANION_VERSION to 0.14.0 and rebuilds the
committed corpus to 20 vectors and ten rejection classes, with
canonical_bases reach dropping 2 -> 0. That is a real capability loss
and is stated as one.
Corruption precedence binds in both epochs. A corrupt major-1 base must
still fail as malformed, never as the temporary authority error a user
would reasonably retry on a container that is in fact tampered with.
11 pins, 11 tests, 11 mutations, 15 touch rows, 7 gate items. S27's
contract is a mandatory touch: pin 8 resolves its open pin 2a — legacy
bases are refused by container epoch, never by version arithmetic.
Documentation only. Not implemented, not dispatched. S27 and S16 stay
blocked until this rung lands.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
S27 installs a reduction authority but cannot say what to do with a
base that predates it. A raw ReductionAlgorithmVersion is a bare u32
with no provenance, and the text-projection parser accepts an unbounded
one from a document, so no numeric convention — including a high epoch —
is safe from a hand-authored file declaring it.
FORMAT_MINOR fails too. The header never changes after creation and
commit publishes only a superblock, so a legacy bundle that commits a
freshly validated base keeps its old minor forever: rejecting minor-<=1
bases rejects one the authority just accepted, and accepting them leaves
S16's version ambiguous. Separately, a minor change may only append
append-safe discriminants, and current readers ignore minor entirely, so
the boundary would bind only readers that already comply.
What survives is the requirement: provenance must ride a container
property old readers cannot silently accept and a later commit cannot
inherit unchanged. S28 owns that, plus the old-reader rejection
boundary, legacy rebuild/repack behaviour, every writer path including
text projection, and the exact format-version consequences.
S16 and S27 both blocked on it; the chain is recorded in all three rows.
Ledger only.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Scoping disposition A found two things that move the rung's size in
opposite directions.
Cheaper: the refusal needs no new PreconditionFailureReason and no
schema-minor epoch. reduce.rs:1236's container_not_empty() helper
already covers "a create carrying children" by its own doc, and three
creates already call it for exactly this shape. create_staff_group is
the sole outlier.
More expensive: this is a canonical reduction-semantics change, not
merely a behaviour change. The same operation set now reduces to a
different Score, so core_spec.tex:11614 applies — canonical bases
materialized beforehand cannot be reused without rebuilding. That
requirement is currently unenforceable, so the contract is complete and
ratifiable as a plan but explicitly not dispatchable.
S27 is why. The version machinery is self-referential:
reduction_version_for sources a new superblock's value from the
canonical base's own self-report, and open compares it only against the
superblock that value seeded. The check is not vacuous — it catches a
corrupt base disagreeing with its superblock — but it necessarily
passes for a conformingly propagated stale base, which is the case the
requirement exists to prevent.
An earlier draft of pin 0 claimed no writer path existed at all. That
was false, and the way it was false is recorded in both the contract and
the S27 row: the search behind it looked for constructor calls, which
cannot find a path that propagates an existing value without
constructing one. The instrument could not observe the thing it was used
to rule out.
Docs only. No code, no spec sources, no implementation authorized.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
S8 carried a false mutation claim. It said flipping `is_none_or` to
`is_some_and` at the constant-tempo check killed no test; three tests
kill it — two in graph_reduction, one in convergence reporting the
witness verbatim. Executed and restored by hand. The original was
reached by reading only invariants.rs's own tests, which assert
`fires(...)` and survive the flip; the kill sites live in another crate.
The genuinely unconstructed spelling is the opposite one: `Constant`
with `Some(equal)` has no construction site anywhere.
S8's ratification also stops presenting normalize-on-encode as the
default. Folding one of two accepted byte forms violates
req:binfmt:decode-vectors' injectivity rule, and
req:binfmt:compression-none-parameter is the ratified precedent for
refusing exactly that leniency. A repair must reject one spelling or
keep both as distinct canonical values.
S16 had drifted in every code citation, some by hundreds of lines, and
never named what makes its fix expensive: t8b_both_permitted_stale_forms_hold
pins both stale forms as passing and documents disposition A's rules as
mutations that must break it. The fix is the mutation an existing test
exists to detect.
S25 files disposition B of S22 — corpus rows named for their variant.
Complementary, not a replacement: it reaches other implementations, but
its failure still reads as corpus staleness.
S26 files a doc comment claiming a core_spec repair that never landed.
A P13-S9 instance, and the sharpest: the side that is wrong about the
other is the grep-guarded side. Its evidence must not be repaired alone.
Locators only in this commit; no code, no spec, no contract.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
`operation_kind_tag_vocabulary!` generates `discriminant()`,
`from_discriminant()`, `catalog_name()`, `introduced_minor()` and
`PAYLOAD_FREE` from one list, and `PAYLOAD_FREE` carries variants only.
Every derived test therefore obtains a tag and its byte from the same
invocation and asserts `$disc == $disc`. It cannot disagree with the
macro, because it is the macro.
The kind side never had this problem: `OperationKind::discriminant()` is
a hand-written match, so two independent statements exist and
`operation_kind_wire_discriminants_are_golden` asserts they agree. This
adds the tag side's second statement — `tag_wire_discriminants_are_golden`,
a hand-typed 40-row literal table transcribed by reading the macro
invocation rather than derived from its output.
Coverage is computed, association is not: a 40-long array does not prove
forty distinct tags, so the table's totality over the vocabulary is
asserted separately, and the comment says why that is not circular.
Payload-free tags assert the whole canonical byte vector — which also
proves the length-1 property the retired test had and the kind-side
idiom lacks — while `Registered`, the one tag carrying a payload,
asserts `[0]` alone.
Retires `phase3_tag_discriminants_are_golden`, whose whole subject was
tag→byte for 24–29. Keeps the three assertions at payload.rs:3086,
reduce.rs:12744 and reduce.rs:15941: the table duplicates their tag→byte
subclaim but not the kind-and-tag pairings that contain them, nor G3b's
local mutation evidence.
Signed by the coordinated 32↔33 permutation — swapping the discriminant
literals *and* the declaration lines, so `PAYLOAD_FREE` still emits
ascending discriminants and every derived artifact stays byte-identical.
Before: 1558/0, silent. After: fails naming SetCanvasLayoutDefaults.
No wire, schema, specification or corpus change. Suite 1558/0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Filed as a deferral -- pickups unmodelled -- it is closer to a live defect, and
the tree already held the proof. m35 placed a first measure at offset 0 and its
successor half a whole note later under a whole-note signature and asserted
invariant 20 fires. That is a pickup. The test has been labelled "wrong distance"
since packet 2. create_measure applies the same rule as a refusal, now observed
end to end rather than cited: the successor comes back NoOp with
MeasureMeterMismatch. Authoring a pickup does not leave it unmodelled; it makes
the rest of the instance unauthorable.
Both refusals carry the same reason code, so the fixture is the only thing
separating them. Pickup and successor both declare None, which keeps clause 2
from running on either side and makes the observed refusal provably clause 3's.
The pickup's own mint is asserted Applied before the successor's NoOp, because a
fixture whose operations never execute produces a non-Applied result
indistinguishable from a refusal.
The exemption is narrower than every document said. A first measure escapes only
the predecessor-dependent checks -- invariant 20's boundary clause, and
create_measure's clauses 1 and 3 -- plus agreement when it declares None or a
matching signature, and only when its other preconditions hold. It can still be
refused for a dead parent or an unresolving anchor referent, and invariant 10 can
still flag it. Seven surfaces carried the loose form; one had hardened into
falsehood, claiming all three clauses are vacuous for a first measure when
clause 2 has no predecessor dependency at all.
core/DECISIONS.md is deliberately untouched. It already said "never flagged by
the boundary clause" -- the one site that drew the distinction correctly -- and
an earlier contract draft listed it as defective by matching the phrase without
reading its qualifier. The corrected ops entry now quotes that qualifier, and a
positive gate check protects it.
A mid-score partial enters successfully and its successor fails, so the scope is
boundaries following any partial measure, not partial measures. The root cause is
a missing quantity rather than a missing exemption: both rules compare the
start-to-start distance against the governing signature's full measure_duration
when it actually equals the predecessor's own content duration. Introducing that
quantity is a semantic rung; this one stops at its edge, with both function
bodies byte-identical.
P13-S24 is filed for the Chapter 3 splitter deferral, which shares the missing
partial-duration concept and is otherwise independent.
Executed against spec/CONTRACT_P13S19_PARTIAL.md, four mutations.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Invariant 20 has nine non-success paths, not the three P13-S18 recorded. Only
three are abstentions: agreement-Indeterminate, boundary-Indeterminate, and an
incomputable boundary delta. Two are delegated to invariant 10, two are vacuous,
one is inapplicable, one is P13-S19's pickup deferral. The entry had been
counting all of it as gap.
Delegation is proved, not asserted. Deleting invariant 10's per-measure arm
leaves the condition unreported by the entire workspace suite except by the two
tests that name it; the same holds for the instance-local-grid arm. A delegation
nobody discharges would have been an abstention with a better name.
Every abstention cell carries a paired positive control, because silence is the
same observation for all nine paths. Each test asserts zero violations on the
fixture that takes the claimed path, then changes only that path's dependency
and asserts the clause decides with the expected witness. The control has to
observe the clause the cell names: S8's first version restored the governing
search by moving prev, which broke prev<->x comparability and left the boundary
silent for a second reason, signing the cell by inference. Moving the grid edge
instead keeps both measures c4-comparable and the boundary clause itself fires.
S2 has no such option -- a WallClock delta is never computable -- so its control
legitimately observes prev's agreement, and that exception is S2's alone.
Three shapes claimed a clause pair no single measure exhibited: m0 carried a
resolving signature at index 0 and m1 carried None, so the pair was really
A4+B1 on one measure and A1+B4 on the other. A boolean over the whole invariant
cannot see that, which is how it survived the first pass.
No behaviour change. check_measure_meter_consistency's executable body is
byte-identical to f33673d at 4871 bytes, verified by brace-matching from the
signature rather than a sentinel; every red observation came from fixture data or
from invariant 10, never from invariant 20's own logic.
P11-C5 was never this residue's gate -- it is a re-anchoring proximity metric.
P13-S23 is filed for the real dependency: placing anchor pairs on a common
timeline and measuring musical distance wherever c1-c5 do not already yield
both. It owns two disjoint deficiencies, since c3 and c5 order without
supplying any delta.
Executed against spec/CONTRACT_P13S18_MATRIX.md, 18 cells and 10 mutations.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Adding Registered = 16 made the inventory six fragments -- 24-29, 34, 35-38, 39,
16, and 1 -- but the repair sentence still said "superseding the five scattered
fragments rather than adding a sixth". The count was right when written and went
stale in the same commit that lengthened the list it counts, which is the entry's
own subject matter arriving one row early.
Ledger-only. No code, wire, or specification change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Registered joins the semantic-lock inventory. Its corpus row is emitted under the
variant name at ops/src/vectors.rs:210 and its committed literal leads with 0x10
at spec/vectors/decode_vectors.txt:80, so the drift comparison binds the
association. The uncovered set narrows to 0, 2-15, 17-23, and 30-33.
Verifying that turned up a false clause of my own. The entry said the corpus's
tag coverage is unchosen and unmaintained. It is neither: vectors.rs:201-204
emits one row per tag straight from the vocabulary and states the reason -- a
hand-picked subset is how TransposeInterval shipped encoding to a byte its own
decoder rejected.
But the rows lock byte-to-byte, not variant-to-byte. Each is named
tag_{discriminant} and carries [discriminant], both derived from the value alone,
so tag_32 asserts that 0x20 round-trips and never that SetCanvasLayoutDefaults is
32. All forty rows are identical under a permutation; what moves is their order,
since PAYLOAD_FREE is declaration order. That is why the 32<->33 probe failed,
established from the committed file's ascending tag_NN rows rather than inferred.
Which sharpens the entry rather than weakening it: Registered's row has exactly
the property the numbered rows lack, because it is named for its variant. The gap
is that one row's discipline is not the vocabulary's.
Ledger-only. No code, wire, or specification change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Three citations in P13-S15 had drifted when the golden-lock comment was added:
the table (:2220 -> :2233), the_tag_vocabulary_is_complete (:2569 -> :2652), and
phase3_tag_discriminants_are_golden (:2645 -> :2728). The tag residue moves out
of P13-S15's closing sentence and into an open row of its own -- a residue
recorded only inside a resolved entry is a residue that gets lost.
P13-S22 was drafted claiming a tag permutation is invisible, with 32<->33 as the
demonstration. Running it falsified the claim, so the entry says what was
observed instead. Three permutations, three catches: 32<->33 and 2<->3 by the
frozen decode-vector corpus, 1<->2 by layout-ir's edit-barrier golden blob. Each
restored by hand; suite back to 1541/0 with payload.rs byte-identical to dcb28f0.
So the gap is narrower and different from the draft. Semantic tag-to-byte locks
cover 24-29, 34, 35-38, 39, and -- incidentally, in a blob comment -- 1. Tags 0,
2-23, and 30-33 have none. What defends them is byte-level goldens that embed the
tag by accident and report a permutation as corpus drift or a moved blob, never
as a moved wire discriminant. The coverage is real but unchosen and unmaintained
as coverage, which is the hand-maintained-table failure mode wearing a costume.
The entry carries a probe-design note, because the obvious next probes are now
known to fail and a probe that fails proves the lock exists rather than that it
is missing.
Ledger-only. No code, wire, or specification change. No DECISIONS.md entry: this
is test-coverage bookkeeping, not a semantic ruling.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
The OperationKind wire golden lock stopped at discriminant 29 while ten kinds
were appended past it -- TransposeInterval (30, Push 4a) through CreateMeasure
(39, G3b). Every one sat with no byte-level lock, and this is the one guard
written to catch exactly that class of stale hand-maintained table, so its own
staleness was the worst place for it. The table goes to 40 entries and locks
30-39 individually, each row asserting both that discriminant() has not moved
and that the byte leads the canonical encoding.
The mutation is the finding reproduced rather than argued for. Editing
discriminant()'s SetTuningContext arm 34 -> 44 fails the extended lock; with
that same mutation still applied, restricting the loop to &table[..30] -- the
exact pre-repair coverage -- passes. That is P13-S15, executed.
The sibling tag half needs no extension and did not get one.
the_tag_vocabulary_is_complete is derived, not hand-written: it computes the
bound from PAYLOAD_FREE's maximum instead of spelling it, so it already covers
30-39, and the vocabulary macro makes a tag without a discriminant a compile
error. One residue is stated in the ledger rather than papered over: density
plus round-trip does not pin which tag holds which byte, so a permutation
inside the dense range survives both tag tests. The same permutation on the
kind side is now caught. Closing the tag-side permutation gap is a separate
question and is not part of this rung.
No wire, schema-version, or specification change: this adds a guard over
assignments that were already normative. P13-S18 and P13-S19 remain open by
design.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
PreconditionFailureReason 14 (AcousticRealizationPinned) and 15
(TranspositionOutOfRange) entered the vocabulary at Push 4a and reached this
document at neither place that owed them. The bounded enumeration ran 13 straight
to G3b's 16, and Push 4a's own history row recorded only OperationKind 30 while
saying nothing about the two reasons it appended in the same epoch. The Operation
Catalog documented both at its 0.8.0 and effect.rs has carried both throughout;
only the wire specification was silent.
This is P13-S20's specification-side twin, and it is why that decoder could stop
at 13 unchallenged: an implementer reading only the wire specification would have
built exactly that decoder and been right. No version bump and no new history
row -- this records an assignment normative since Push 4a rather than making one.
The regression test checks both sites, each bounded to its own longtable row,
because either alone is satisfiable by the wrong thing: the G3b row and the
enumeration both discuss PreconditionFailureReason at length, and an unbounded
search would go green the moment any row mentioned the names. Each half was
observed red alone while the other stayed green. The Push 4a row is located by a
version-free separator marker, per the file's standing rule against encoding a
document version number anywhere in it.
The epoch-12 evidence hash is e64a4b7, not this rung's parent. G3b landed across
six commits, and the chain records introducing commits -- the commit where
kind/tag 39 enters payload.rs and reasons 16-18 enter effect.rs -- exactly the
distinction the 2026-07-28 correction draws between 7df5ca1 and 55eff00 for G2a.
d58eee8 completes the rung and introduces no discriminant; both are named, with
their roles stated, in the plan and in the contract's pin 15.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Kind 39 CreateMeasure and precondition reasons 16-18 reach the Binary Format's
kind table, tag table, payload layout, and reason table; graph invariant 20
reaches the core specification's enumeration, which now says twenty in all three
places it counts. Both normative listings in that document gain CreateMeasure --
earlier drafts of the contract named only the invariant, and prose fails silently.
Every version surface moves in pairs. Binary Format 0.15.0 -> 0.16.0, Operation
Catalog 0.12.0 -> 0.13.0, each with a changelog entry beside the title bump. The
Text Projection companion needed only the changelog: packet 1 bumped its header to
0.13.0 and stopped there, leaving the document claiming a version its own history
did not record. That was live from e64a4b7 until now, and no gate could see it.
Two public hooks exist that would otherwise look like leaks. epiphany-ops depends
on epiphany-core and never the reverse, so invariant 20 implements pin 6/6b's
comparable relation and musical delta a second time over the graph alone. Both
DECISIONS records name the divergence hazard that forces the duplication, name the
cross-crate agreement test as the hooks' only sanctioned use, and say so from each
side.
The monotonicity evidence chain gains only vocabulary-introducing events -- G2b
13c3d2f, G3a 6c5e69f, G3b -- and excludes G-minor and P13-S17 with the reason
stated: neither introduced an additive variant. The 2026-07-29 tie between G2b and
G3a is broken by ancestry, not timestamp.
P13-S18 (invariant 20's abstention residue) and P13-S19 (the pickup deferral) are
filed open by design. P13-S20 is recorded RESOLVED.
The genesis ladder G1 -> G2a -> G-minor -> G2b -> G3a -> G3b is CLOSED.
Executed against spec/CONTRACT_GENESIS_G3B_MEASURE.md rows 14a and 26-36,
mutation M71, which is now the contract's own guard: deleting the G3b Revision
History row fails the history test even though "genesis tranche G3b" still appears
twice in neighbouring prose.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
The Revision History chapter ran G2a straight to G-minor to G3a, with no row
for genesis tranche G2b anywhere -- so the accept-set raise
OperationEnvelopeBlock 2 to 3, the first accept-set move since G2a explicitly
recorded staying at 2, reached the normative tables and never the history.
G2b's own contract required that row; 13c3d2f edited 99 lines of
binary_format.tex and added none of it.
The stack is unpublished, so the chronology is restored rather than patched:
G2b lands as its own row between G-minor and G3a, G3a renumbers up, and the
PDF is regenerated.
The new epiphany-testkit guard makes recurrence detectable. Bare name-presence
would not have: with the G2b row deleted, "G2b" still occurs inside the chapter
in G3a's prose, so a substring guard would have been born green. The guard
requires a principal marker -- the rung name preceded by the row's separator --
strictly ordered across the four standalone-row rungs G2a, G-minor, G2b, G3a,
with G2b's content anchored inside its own row segment so G3a's row cannot
satisfy it. G1 is deliberately unguarded: it has no standalone row, being
recorded retroactively inside G2a's. No document version number appears in the
test, in its comments, or in this message.
Executed against spec/CONTRACT_GENESIS_G3A_UNDO_REPAIR.md Packet B.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Ruling, ratified 2026-07-29:
- Staff.group is the SOLE authority for membership.
- StaffGroup.members is a non-authoritative denormalized projection.
- G3a stores it but neither maintains nor trusts it.
- BOTH stale forms are permitted, equally: a missing member (s.group ==
Some(g) while g.members omits s) and a spurious member (g.members contains
s while s.group is None or names a different group). The earlier draft
named only the first, which left the spurious form reading as a bug rather
than a permitted state.
Withdraws the earlier draft's argument for B. "B adds no semantics while A
does" was wrong: B assigns authority to a field the specification left
unranked, which IS a semantic change. What B defers is enforcement, not
meaning. The honest advantage is narrower -- B adds semantics without adding
machinery, leaving the mint a mint.
Files P13-S16, which makes the contract's "filed gap" claim true; it was
false when written, since no such entry existed. The entry records both
stale forms, the disposition-A fix, candidate invariant 21, the re-carry
comparison question A must answer, and the standing instruction that
consumers read Staff.group and never StaffGroup.members for membership.
Remaining repairs:
- PLAN_GENESIS_OPS.md still claimed G3a "closes the staff-group half".
Narrowed to satisfiability, matching the contract.
- Boundary accounting normalized to six crossings across both documents: one
exhaustive-match site plus five literal/prose sentinels. The two classes
are counted together but named apart because they fail differently -- the
match site refuses to compile, while every sentinel stays green while
meaning something narrower than it says.
- t4 now runs four independent mutations, one per struct_codec! layout;
these are four separate layouts and one mutation signs one of them.
Collapsing is permitted only if the implementation consolidates them
behind a shared mechanism, and must be stated if it does.
- t8 split: t8 asserts satisfiability only; new t8b pins BOTH asymmetric
authoring orders as states the ruling permits, with a mutation each. A
test pinning one order leaves the other free to change silently.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Kind and tag 34, schema major 3, minor epoch 10. The last rung before G3, and
the one that closes P13-S13: the tuning context becomes operation-authored, so
it finally has a canonical carrier. The closure argument is the metadata
precedent, not the canonical base - the base embeds no graph values for any
field, and metadata has been durable purely through its operations since M2d.
The payload carries epiphany_core::TuningContextSettings, a five-field subset
of ScoreTuningContext, not the full graph type. ScoreTuningContext's codec
deliberately drops accidental_extensions, so a full-value payload would have
diverged between a live session, where accept stores the envelope as a value,
and the same document reloaded, where the field decodes empty. canonical_value!
could not have caught that: it compares bytes and never the originating value,
so a field that never reached the bytes is structurally invisible to it. The
subset makes the divergence unrepresentable instead of relying on a
normalization step nothing can enforce, and it costs no wire design - the
encoding is byte-identical to the existing five-field walk, which
tuning_context_settings_canonical_bytes_match_score_tuning_context asserts
directly. Reduction leaves accidental_extensions untouched.
SetTuningContext is the sole genesis payload born at major 3, because minimal
stamping is a function of each payload's value, so the accept-set raise is
charged to this one surface: OperationEnvelopeBlock 2 to 3. The doc comment
above it did not merely record the cap, it asserted that no operation payload
embeds the tuning context - a sentence this rung falsifies - so it is rewritten
rather than left beside a corrected constant.
Undo restores the seeded base settings, default or not, and the
never-authored versus authored-to-default distinction stays unobservable. An
earlier draft of the contract had that backwards; PLAN_GENESIS_OPS section 5
trap 5 withdrew it, and SetMetadata is the disproof.
Fixes two undefined references the interrupted run had not yet reached:
operation_catalog.tex referenced sec:evolution:major3, a label defined in
binary_format.tex, which LaTeX cannot resolve across documents. Replaced with
the sectionsc convention already used for every other cross-companion citation
in that file.
Gate: 1409 tests, clippy 0, fmt clean, conformance 8/8 including [7f], both
vector corpora regenerated, all four PDFs at 0 undefined references. The t5 and
t7 mutations were re-run independently and observed to fail as specified; the
remaining eight are not signed off, because the implementing run was stopped
before it reported them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Documentation only. No code change.
S15 records that operation_kind_wire_discriminants_are_golden declares
[(OperationKind, u8); 30] at payload.rs:1959, covering 0..=29 - so
TransposeInterval, CreateInstrument, SetCanvasLayoutDefaults and
SetSpellingPrecedence have no byte-level lock. Not a live incorrectness: all
four discriminants are currently correct and the .tex tables carry them
normatively. The gap is the absence of a guard.
Left open deliberately with no code change. The fix is mechanical, but a
golden-lock extension should land with its mutation evidence and nothing else
in the diff - and the mutation is to move one of the four and watch the
extended lock fail where it previously stayed green. The macro-guarded
OperationKindTag half is unaffected; this is the hand-written match, which is
the site Push 4a got wrong. Its sibling phase3_tag_discriminants_are_golden
wants the same check.
Closes S14 at ff9bd0f, and records the two things its filing did not
anticipate. The scope was never just OperationKind - OperationPayload,
ReanchorReason and PreconditionFailureReason all append - and the manifest
reaches OperationKindTag through edit_barriers with no envelope involved, which
supersedes the filing's "no companion bump" note. Op-block stamping did stay
projection-invisible as scoped; the bump came from the manifest attribute.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
All five findings verified against the tree; the recommended policy is
rejected and replaced with the ratified one.
Policy (b), minor = highest discriminant emitted, cannot represent an
operation block. An envelope also emits the outer OperationPayload
discriminant, and ResolveEquivocation is appended at 3 while carrying no
OperationKind at all -- so the ambiguity is inside one role and one block, not
between roles. Generalizing to "highest from any vocabulary" is worse: an old
kind 23 would numerically mask a new payload 3. binary_format itself enumerates
four independent minor-additive vocabularies. The rung's gating work is
therefore an audit of every append-only discriminant reachable from each
affected payload, which the first draft never scoped.
Ratified instead: a global additive epoch with content-minimal stamping, an
envelope's minor being the max across outer payload, primitive kind, and every
nested additive variant actually emitted. The maintenance objection is
answered by co-locating introduced_minor with each discriminant in an
exhaustive match with no wildcard, so an unassigned variant cannot compile --
the operation_kind_tag_vocabulary! reasoning. Per-major counters are rejected
too: mixed blocks do not compose after max_major.
Two of my conclusions were wrong. Op-block minors do not reach the text
projection -- block schemas are discarded there, and all seven accepted-corpus
schema forms belong to extension chunks or canonical bases -- so no companion
bump. I had also miscounted them as six by grepping lines rather than
occurrences. And the manifest-ID promise is not threatened: it is conditional
on the same manifest body, and a changed ChunkRef is a different body. Real
address churn, not a broken guarantee.
"Is the canonical base exempt" was the wrong binary question. It never emits
the op-kind discriminant, so it holds its minor until MaterializedState's own
bytes emit a later-added variant. Manifest::SCHEMA stays put; existing bundles
need no migration. Construction-site count corrected 62 -> 66.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
TransposeInterval is missing from both Core normative listings, which carry the
older Transpose and never gained its successor at kind 30. So the vocabulary
has drifted from its normative listings for two tranches, not one, and both
listings need four additions rather than two. The contract's grep list gains
TransposeInterval, and names the signature worth hunting: a spelled-out count
that disagrees with the enumeration beside it.
for_major does not return {major, 0} unconditionally -- V0 is {0, 1}, and only
V1 through V3 carry minor 0. Corrected in the contract, the plan, and P13-S14.
The finding is unchanged: the function accepts only a major, so no per-kind
additive minor can reach it.
Ladder order is now explicit as G2a -> G-minor -> G2b, with the reason. The
sweep is scoped to kinds 24-33, which is what exists once G2a lands; running
G2b first appends kind 34 and would either grow the sweep mid-flight or ship 34
carrying the defect the rung exists to retire.
Core is five live-text edits plus one historical annotation, not five edits.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
All four findings verified against the tree before fixing; all four hold.
The schema-minor MUST (binary_format.tex:2330) has never been implemented.
SchemaVersion::for_major accepts no minor and returns {major, 0}, and both
staging paths derive only the major, so kinds 24-27, 28-29, 30, and 31 already
carry no additive-version record -- and the requirement's own rationale is
exactly what the gap defeats: a reader meeting an appended discriminant cannot
tell a stale vocabulary from damaged bytes. Filed as P13-S14 and ruled a
separate rung after G2a, sweeping 24-33 in one retroactive pass rather than
blocking G2a on a debt eight kinds deep or paying for two partial sweeps. G2a
now says explicitly that it extends the violation by two, knowingly, and
forbids working around the absence.
s7 could not fail. WorkingSnapshot::restore reassigns the whole graph
independently of every write chain, so omitting a chain leaves stale history
while the field still rolls back -- the prescribed assertion passed under its
own mutation. Two framings of this test were wrong; the third asserts against
a later undo's predecessor, and the contract now requires the mutation be run
rather than reasoned about. s8's mutation was impossible as written: each
payload has one field, so there are no adjacent fields to swap. Swapping
discriminants 32/33 in both halves is the self-consistent mutation that leaves
round-trips green and kills correctly-named literal vectors.
The normative repair surface doubles: eleven sites across four documents, five
of them G1 debt. Core's normative OperationKind and OperationKindTag listings
are missing CreateInstrument as well as both new kinds; the catalog's
value-restoration family list is normative for undo and omitting a family is a
silent semantic gap; two spelled-out payload counts move. Since two independent
reviews each found sites the other missed, the list is a floor and the contract
now prescribes grepping the load-bearing phrases.
Also: core_spec said "two edits" and prescribed more, and the split-cost
accounting counted only Text Projection when G2b repeats the Binary Format and
Operation Catalog work too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
G2 was scoped as one packet of three LWW setters. Reading the frozen codec
walks rather than the type labels shows they do not sit at the same major:
SpellingPrecedence has never been versioned, CanvasLayoutDefaults is versioned
in the containing Canvas walk and not the leaf, and only ScoreTuningContext is
born at v3. So the accept-set raise — a one-way door — is charged to one
surface, not amortised across nine as the ruling's framing implied. G2 splits:
G2a is the two major-0 setters and touches epiphany-bundle not at all; G2b is
SetTuningContext alone, carrying the raise and the S13 close.
Withdraws plan trap 5. SetMetadata already answers it: Score::empty seeds
metadata exactly as it seeds tuning_context, the base ingest seeds the LWW
chain from it, and restoring that seed is correct for both never-authored and
authored-to-default. These are always-valued fields, not map keys, so the
Predecessor::Base/::Write distinction that matters for spellings and breaks
does not apply here.
Records the G1 lesson as a trap in its own right: an OperationKind variant is
not containable to core+ops, and the G2a contract budgets all three downstream
literal sites up front instead of discovering them mid-dispatch.
Corrects S13's amortisation claim, and states the closure argument properly —
the canonical base is a MaterializedState that embeds no graph values for any
field, so S13 closes on the metadata precedent, not on the base. Notes the
consequence: after G2b, pruning would discard authored state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
RULING_GENESIS_PERSISTENCE.md §3 was the tranche's stated blocker. Ruled:
identity stays on Score and stays canonically encoded, byte-equality claims
confine to MaterializedState, and from-empty reduction derives next_counter
from the log.
Scoping it turned up that the section understated the problem. Verified in the
tree: epiphany-ops has no `.identity` reference at all, so reduction never
advances the cursor; invariant 11 checks only the reserved replica, never the
counter against ids present; and every mint from score.identity today is under
cfg(test). Score::identity is an authoring cursor reduction never touches, and
this tranche is what activates the hazard -- under from-empty the cursor sits at
the seed while the log already holds that replica's ids at 0..N. Divergent bytes
were the lesser problem, and none of the three options originally listed fixed
the larger one.
The manifest option, previously recommended, is rejected on evidence:
req:format:manifest-id promises two conforming writers derive identical
ManifestIds, which a replica-scoped field in a shipped content-addressed
structure cannot honour. The two wire options each cost schema major 4 on the
role 3b-i just froze at 3, and neither corrects the cursor.
Also reconciles two records against 011c68a. DECISIONS.md flatly prohibited a
SetTuningContext operation, which the ruling now requires; the prohibition is
marked superseded and re-scoped to what it was aimed at -- no tuning-only fix,
no wire widening to compensate -- both of which still hold. PASS13-S13 moves
from blocked-on to resolved-by, naming which of the four dispositions was taken.
Flagged for the tranche, not fixed here: bundle.rs documents the
OperationEnvelopeBlock cap of 2 with the tuning-context rationale in prose, so
that comment becomes false when the cap moves.
Gate: requirement_labels 6/6. No .md here is include_str'd or compiled.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV