Commit Graph

223 Commits

Author SHA1 Message Date
Levi Neuwirth 3328b2c0e2
P13-S16 post-acceptance reconciliation: the three documents §4a held back
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
2026-08-10 17:30:27 +02:00
Levi Neuwirth aee4ff92b7
P13-S16 EXECUTED: StaffGroup.members becomes a maintained projection
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
2026-08-10 17:18:20 +02:00
Levi Neuwirth 34232dc1a6
P13-S16 RATIFIED after twelve independent rounds; pins frozen, not dispatched
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
2026-08-09 20:55:00 +02:00
Levi Neuwirth 25b492575e
S16: ratification round 11 -- rederive m40 locators 2026-08-09 20:47:46 +02:00
Levi Neuwirth 63a2dc8ce7
S16: ratification round 10 -- remove the tally from item 1's own explanation
Whole-artifact review of a5f3013 returned one blocking finding.

§6 item 1 declared that no count is stated there and then stated one: "M7's
split into M7a and M7b makes ten executions." §3's table now has eleven
mutation rows -- M1 through M5, M6a/M6b, M7a/M7b, M8, M9 -- because M6 split
too. This is a live report requirement, not dated history, so an execution
report could reconcile against the wrong set.

The paragraph indicted itself: its closing sentence warned that "a count here
goes stale the next time a mutation splits", and then M6 split and the count
went stale exactly as predicted, with the warning still attached to it.

Item 1 now reads: no count is stated here, §3's table is the single origin,
read its rows. The parenthetical records both stale values -- the original
"nine mutations (M1-M9)" and the replacement tally -- without restating a
current one.

This is revision J's rule, applied to item 1 after J applied it to item 2: an
explanation of a removed count must not restate a count. Items 1 and 2 are
adjacent lines, and J swept one of them. The neighbour-not-swept failure, in
the very pair of items that produced the rule.

Swept for other live mutation tallies: three remain, all inside dated revision
records or quoting superseded text (revision B's finding cell, round 7's
record, and item 1's own parenthetical). The live requirement is count-free.

Round 9's field-declaration anchors are confirmed sound by the reviewer: both
declarations are unique in graph.rs, and a B-wording revert leaves each
declaration available, so the needle assertion rather than the locator produces
the required output. That closes round 9's second finding on evidence rather
than on derivation.

Committed one round late: the shell tooling failed mid-round after the edit
landed, so this change sat uncommitted and was reported as such rather than
claimed as done.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 20:42:36 +02:00
Levi Neuwirth a5f3013044
S16: ratification round 9 -- harden the locator, not only the assertion
Whole-artifact review of 942f261 returned one blocking finding. A sweep of it
escalated a second.

1. The expected-outcome table recombined M7a and M7b as "its own grep guard;
   the other guard." That recreates the exact ambiguity M7's split existed to
   remove: a report can say "own guard failed" without establishing which guard
   failed or which survived -- and round 8's full-suite rule reports tests by
   name, so a row naming none cannot be checked against it.

   Split into two rows with the exact names. M7a fails
   t14_staff_group_field_doc_comment_states_sole_authority (graph.rs:2136)
   while t14_staff_group_members_field_doc_comment_states_non_authoritative_projection
   (:2160) must pass; M7b the reverse. Each quotes its needle-miss message and
   the doc_block that message dumps.

   M7 was divided in draft amendment 1 precisely because one mutation covering
   two guards could pass with the other still weak. The table re-merged them
   for brevity. A summary row is a restatement, and a restatement of a
   distinction can drop it.

2. Sweep: M7b's required output was unobtainable. Both guards locate their doc
   block by searching for a phrase from the doc text, and :2163's anchor is the
   disposition-B claim pin 10 rewrites. Once the anchor is updated to the A
   wording, M7b's revert to B makes .find() return None and
   .expect("StaffGroup.members's doc comment is present") panics -- naming no
   needle and dumping no block. The required observation would be an anchor
   panic pointing at absent text.

   Pin 10 now requires the slice to be located from the FIELD DECLARATION --
   pub group: Option<StaffGroupId>, and pub members: Vec<StaffId>,, which no
   wording changes -- extending backwards over the contiguous /// lines. The
   block then exists under either disposition and the only way to fail is the
   needle assertion, with message and block intact.

   This is the absence-grep lesson one level down. Pin 10 hardened the NEEDLES
   against wording both dispositions satisfy and left the ANCHORS matching
   wording only one disposition has. A guard whose locator depends on the text
   it inspects fails before it can report, and failing early looks like failing
   correctly: the test is red, the mutation "worked", and the evidence never
   existed.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 20:32:43 +02:00
Levi Neuwirth 942f261094
S16: ratification round 8 -- make the expected-outcome table evidential
Whole-artifact review of 2a445d1 returned one blocking finding: the table named
required survivors without requiring them to be run.

§6 consumed mutation output generally and no cell specifically -- t8c, t8d, u5,
pin 8's four, the structural gates -- and only M6 required its sibling's
verdict. "Report any mismatch" cannot detect a survivor that was never run: an
unrun test yields no mismatch and no evidence, so every survivor cell was an
unobserved claim, and the table read as evidential while being advisory.

One uniform rule now governs every mutation:

  1. full cargo test --workspace, with the COMPLETE observed failure set
     reported;
  2. the named failing tests' output, per the channel rules -- behaviour, not
     the fact of failure;
  3. each named required survivor's PASS VERDICT, by name;
  4. each named structural gate's output -- gate 8 under M1 and M8, gate 12
     under M6a/M6b, pin 10's guards under M7a/M7b.

An omitted named artifact is itself a finding, on the same footing as a wrong
outcome. §6 item 1 consumes the rule. M6's per-half list is now marked as the
general rule applied rather than a special case.

This is revision D's class -- a requirement nothing can fail -- reproduced by
the very table written to end the discovery model. Round 7 moved authorship of
the expected outcome from execution to the contract, which was right, and left
the outcome unobserved. A claim the contract owns is not thereby a claim
anything checks.

The finding also forced a distinction left implicit. The survivors column said
"notable", quietly meaning not exhaustive, so a uniform "run every named
survivor" rule had to say what IS exhaustive. Now stated: the MUST-fail column
is exhaustive, verified by requirement 1's full-suite run; the survivors column
is illustrative, naming the ones a reader would doubt, and everything outside
the failing column must survive whether named or not. Without the full-suite
run the failing column's completeness was unverified as well, so the fix closes
a second hole the finding did not name.

Three rounds running have the same shape: round 6 wrote a rule and exempted
three mutations, round 7 wrote a table and left it unrun, round 8 makes the
table evidential. Each fix was correct about what to specify and incomplete
about who observes it.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 20:28:36 +02:00
Levi Neuwirth 2a445d16be
S16: ratification round 7 -- the contract owns the expected-outcome table
Whole-artifact review of 80be47c returned one blocking finding: round 6's
blast-radius rule contradicted itself.

It required every mutation to state every expected failing test, then left M1,
M2 and M5 for execution to derive -- the discover-the-radius model it claimed
to eliminate, with the expected set depending on the executor's reading. And
execution cannot both author the table and certify its own result against it.

The cited surfaces were also insufficient, not merely incomplete. Round 6
listed touch row 8, pin 1a and pin 8. None owns t8c, which pin 3a defines four
sections away asserting g.members == [s] -- exactly the value pin 2 maintains,
so M2 breaks it. Any derivation from the stated surfaces would have missed it.
The instruction was unfollowable as well as misassigned.

§3 now carries the contract's own per-mutation expected-outcome table: failing
tests, notable required survivors with the reason each survives, and structural
gate outcomes, for all ten mutation halves. Dependency surfaces are cited and
now include pins 3a, 4a, 5a, 6a and 7 alongside pin 1a, pin 8, touch row 8, and
check_invariant = check_invariants(...).filter(...).

Execution re-derives the table against the staged tree and reports any
mismatch, in either direction, as a finding against the contract or the
implementation. No cell is a licence to ignore an outcome.

Notable entries the table now owns rather than leaving open: M1 fails gate 8,
since the refusal is what that gate reads for; M8 fails gate 8 as its only
signature and must break nothing behavioural; M6a and M6b both fail gate 12
because a call site is gone; t8c, t8d, u5 and pin 8's four all survive M1
because they carry members: [] so the refusal never fires for them.

Cells carrying a reason -- t8d under M2, t9 under M1 -- are derivations from
pins not yet executed, stated so they can be falsified. That is the division of
labour the finding asks for: the contract predicts, execution measures, and a
mismatch is a finding against whichever is wrong. The table has no totals, so
it avoids the stale-count class entirely.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 20:23:07 +02:00
Levi Neuwirth 80be47ca13
S16: ratification round 6 -- derive a mutation's blast radius, don't recall it
Whole-artifact review of 85429d6 returned one blocking finding: M6a's blast
radius was understated.

check_invariant is check_invariants(...).filter(...) (invariants.rs:313-:318),
so deleting the S->G dispatcher call silences that violation for every
consumer, not only the two tests M6a named. The full radius is six, each now
tabled with where it fails and why:

  m41...staff_names_absent_group          its own assert_eq! cardinality check
  invariant_21_negative_generator_...     same
  every_invariant_has_a_negative_generator  own assert! at generators.rs:994
  negative_generators_are_reasonably_targeted  own assert! at :1046
  every_invariant_shrinks_to_a_small_witness   INSIDE shrink, entry assert :933
  shrink_is_idempotent                         INSIDE shrink, same assertion

All six share one cause and all six are expected, not findings. The last two
panic with "shrink starting point must violate the target invariant", raised in
a function the mutation never edited, so they are to be reported as
shrink-entry failures rather than misread as a defect in shrink.

M6b's single expected failure -- m41b alone -- is now recorded as positive
evidence: the four all() consumers and the generator test all stay green
because every invariant-21 fixture is S->G, which confirms touch row 8's pinned
direction more directly than any assertion about the generator does.

Round 5 added the blast-radius rule and then enumerated the radius from memory.
Touch row 8 already lists those four consumers with these exact line numbers --
draft amendment 1 put them there as the two-crate root cause -- and M6a's
outcome was written without consulting the row that owns them. The document
knew; the mutation did not ask.

That is a new variety of the propagation failure. Revisions A-J recorded
corrections failing to reach a consumer; round 1 a declared peer; round 4 a
gate written later. This one is a fact recorded in one section not reaching a
requirement written in another -- nothing stale, nothing contradicted, and no
sweep for restated text would find it. It needed the question "what does this
section already know that this one should be using?"

So the fix is an obligation rather than a list: §3 now requires every mutation
to state its complete expected-failure set, derived from the recorded consumer
surfaces (touch row 8's four, pin 1a's three, pin 8's four), with any unlisted
failure treated as a finding in the contract or the implementation. M1's, M2's
and M5's radii are deliberately not enumerated here, since enumerating from
memory is what produced this finding; execution derives each and reports the
derivation.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 20:16:29 +02:00
Levi Neuwirth 85429d6243
S16: ratification round 5 -- the assert macro is part of the channel
Whole-artifact review of e48bb8d returned one blocking finding: M6 was not
covered by round 3's own channel rule.

Pin 6a requires an exact violation set without saying how, so a conforming
assert!(violations.len() == 1 && ...) satisfies it and prints nothing on
failure -- and that assertion is precisely what M6 trips. Gate 6 and §6 item 2e
use the passing-test model, source assertions plus ok. So M6 reverted to "the
named test failed", the signature this contract rejects.

Pin 6a gains a harness for m41, m41b and the generator test: bind
check_invariants to a local before any assertion; make the cardinality check an
assert_eq! on that local with the full violations vector in its diagnostic; and
make it the first assertion after the bindings, since it is the one M6 trips.
Gate 6 now confirms the macro. M6a/M6b quote the failing output plus the
sibling's pass verdict.

Round 3 wrote the channel rule and applied it to M1, M2 and M5 -- the
mutations named in that round's finding -- and not to M6, which has the
identical need. Round 3's text even carved M6 out, listing it among mutations
that "already met the standard": true of its behavioural observation, which
names the state, and false of its channel, which had none.

The macro is part of the channel, not a style choice. assert_eq! prints
left/right; assert! prints only its message. Under M6a the S->G arm is gone,
check_invariants returns empty for m41's fixture, and assert_eq! prints 0
against 1 with an empty vector -- that is "the violation went unreported",
quoted rather than inferred. With assert! the same requirement is met with no
evidence. Where a mutation's observation IS the compared value, the pin must
name the macro; the rule is now at the head of §3 rather than left to each
mutation.

A second gap closed with it. M6a also breaks the generator test, since that
fixture is S->G. Unstated, an executor either reports a defect that is not one
or ignores a failure it cannot classify. M6b leaving the generator green is now
recorded as positive evidence that touch row 8's pinned direction holds. A
mutation must state every test it is expected to break, or its blast radius is
discovered instead of specified.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 19:08:59 +02:00
Levi Neuwirth e48bb8d0b4
S16: ratification round 4 -- "the resulting value" is not a value when there are two reductions
Whole-artifact review of 3e0a4d3 returned one blocking finding in round 3's own
harness.

Pin 7a collapsed two fixtures into one binding. t8b runs TWO authoring orders
(§0.5) -- two reductions over two different groups -- but pin 7a bound "the
resulting StaffGroup.members" and one filtered invariant result. A single
members local satisfies the harness as written while leaving either mutation's
required observation absent, depending on which order it came from; and the
invariant result filtered from the wrong reduction is the wrong verdict, not a
missing one.

Pin 7a now binds four, before any assertion:

  1. spurious-order OperationEffect  (M1: becomes an applied effect)
  2. spurious-order members          (M1: the spurious membership in the graph)
  3. missing-order members           (M2: stays empty)
  4. missing-order invariant-21 violations (M2: the disagreement left behind)

Every assertion formats all four, so whichever assertion a mutation trips
carries both of that mutation's observations. Gate 14 must now establish WHICH
ORDER each binding came from rather than counting bindings. M1 and M2 name
their own order at every mention.

Round 3 fixed the channel and left the fixtures conflated. It correctly
established that a failing test has one output channel and that state must be
bound before the assertion a mutation trips, then described the state as though
t8b had one reduction. The ordering rule was right and the inventory was wrong,
which is why the harness looked complete: three plausible bindings, none wrong
on its face, and nothing in the pin revealing that two of them are per-order.

The generalisable form: a definite article asserts uniqueness exactly as
silently as a number asserts a total. "The resulting value" reads as precise
and hides the question of which one -- the singular-noun cousin of the count
defects this contract has been removing since revision A.

And gate 14 inherited gate 12's defect before gate 12's fix could reach it.
Gate 12 was rewritten in revision H because a four-line aggregate proved a
population and not a pairing; gate 14 was written in round 3 requiring "three
bindings" -- the same shape, one section over, three rounds later. Ratification
round 1 recorded a fix failing to reach a declared peer; this is a fix failing
to reach a gate written after it.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 18:57:18 +02:00
Levi Neuwirth 3e0a4d38c1
S16: ratification round 3 -- a failing test has exactly one output channel
Whole-artifact review of e43cd34 returned one blocking finding: three
mutations required runtime state that none of their prescribed artifacts is
required to emit.

M1 wants the applied OperationEffect and minted members; M2 the still-empty
members and invariant-21 verdict; M5 the post-undo members plus the
invariant witness. But pin 7 says only that t8b inverts, and gate 13 and §6
item 2f prescribe source assertions plus a normal pass verdict -- a
passing-test evidence model. A mutated test stops at its first failed
assertion, so state carried anywhere else is never printed, and M5's witness
assertion may not execute at all.

Fixed by pinning observation harnesses:

- Pin 7a: t8b binds the OperationEffect, the resulting StaffGroup.members and
  the invariant-21 verdict to locals BEFORE its first assertion, and formats
  all three into EVERY assertion's failure message.
- Pin 5a: u5 binds the post-undo g.members and the check_invariants
  violations with witness ids before assertion 2, and formats both into
  assertions 2 and 3.
- Gates 13 and 14 quote those diagnostics from source. M1, M2 and M5 quote the
  resulting failure output verbatim.

The finding is revision E's, one case over. Revision E chose "quote the source
assertion plus the pass verdict," which is correct for a PASSING test, since
that is all a passing test emits. Mutations need the failing case, and the
failing case has exactly one channel: the diagnostic of the assertion that
fired. Settling the first did not settle the second.

The ordering half would have survived a careless fix. Putting each observation
in "its own" assertion reads as tidy and is precisely wrong: M1 trips t8b's
spurious-order assertion and M2 the missing-order one, so a message carrying
only its own value disarms whichever mutation trips the other. In u5 it is
worse -- M5 trips assertion 2, making assertion 3's witness unreachable by
construction. The state a mutation owes must be bound before the assertion
that mutation trips.

Rather than pin this three times, §3 now heads with the general rule, which
also covers the mutations the review did not cite: where the observation is a
single value under assert_eq!, the default left/right diagnostic carries it,
and M3, M4 and M9 qualify provided they compare the verdict rather than
assert!(matches!(...)), which prints nothing -- the report must state which
form each uses. Where the observation is composite, or behind an assertion the
mutation makes unreachable, a harness is required.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 18:46:19 +02:00
Levi Neuwirth e43cd3410b
S16: ratification round 2 -- the status block stops describing the review
Whole-artifact ratification review of 5ec2ce0 returned one blocking finding.

The live status block still said this contract "has not been through
adversarial review rounds." That was true when written and false from the
first independent pass onward, and it sat in the "what remains before
dispatch" summary -- so a top-down reader received a false review-state signal
before reaching any record that contradicts it.

Replaced with a non-rotating pointer: the review records below are the review
state; the block states no count and no ordinal, and will say RATIFIED when
that decision is taken. Also sharpened the neighbouring sentence to name three
distinct states -- unblocked, ratified, dispatchable -- since conflating the
first two is the specific failure it cites from S27.

This is the status-block defect S27 spent amendments 4 through 7 removing,
reproduced here in its purest form. S27 established that a status line
describing the review must not describe the review: it must point at the
record that owns it, because every such line goes stale exactly when the
review advances, which is the one moment nobody is reading the status block.

What makes this worse than a stale count: a stale count reads as an error,
while "has not been through adversarial review rounds" reads as a verdict on
the artifact's maturity. A reader deciding whether to trust this draft would
have taken it as the answer, with ten revisions of independent review recorded
immediately below it.

And it is the whole-artifact question again. Rounds against edits ask "is this
change right?"; only a whole-artifact read asks "is anything the document says
about itself still true?" Round 1 found a missing permanent test that way;
round 2 found a false status claim. Both were invisible to every incremental
pass, and neither was in the content those passes were correcting.

Swept for other live review-state claims: none. The only remaining
"NOT RATIFIED" is the status line itself, which is the fact that changes at
ratification, and the false sentence survives only inside its own correction.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 18:38:27 +02:00
Levi Neuwirth 5ec2ce0bbd
S16: ratification round 1 -- pin 5 gains a permanent regression test
First independent round against the draft as a whole rather than against the
previous revision's edits. One blocking finding, and it is one that ten
revisions of amendment review did not surface.

Pin 5's staff-undo repair was signed by M5 alone. No named test performed
CreateStaffGroup(g, []) -> CreateStaff(s, group: Some(g)) -> undo the staff ->
assert the still-live g.members no longer holds s.

Verified that nothing existing supplies it:

- Pin 8's four tests are group-undo guards. u2tomb_a (reduce.rs:17125) does
  undo a staff, but its assertions are that the undo tombstones the
  referencer, that T1's undo then proceeds, and that "the group leaves
  Score.staff_groups" (:17187) -- it undoes the group too, so no live group's
  members is ever inspected.
- Gate 6's m41/m41b build materialized fixtures and never run the reducer's
  undo path.

Pin 5a adds u5_undoing_a_staff_strips_it_from_the_live_groups_members with
three assertions: the group is still live (without which the test can pass
vacuously on a score where the group was undone too -- exactly how u2tomb_a
misses this path), g.members lacks s by id, and check_invariants reports no
StaffGroupMembershipAgreement violation. Gate 13 runs it. §6 item 2f reports
it. M5 now breaks it by name and reports the changed state -- the post-undo
g.members still containing s, with the invariant-21 witness -- rather than
stating a condition.

The finding is revision C's, on the sibling pin. Revision C established pin
3a's rule that a mutation demonstrates the hazard once and only a test keeps
it demonstrated, and applied it to pin 6 and M6. Pin 5 and M5 have the
identical shape and were left alone, two paragraphs from the sentence "pin 6
is coupled to pin 5 and they split only together."

So the lesson is not "check mutations for permanent tests" -- that was already
learned. It is that a coupling stated in prose does not propagate a fix. Every
fix-propagation failure in revisions A-J was a correction reaching a CONSUMER
one hop late; this one failed to reach a declared PEER.

Why ten revisions missed it: each reviewed the previous revision's edits, so
the question asked was always "is this change right?", never "is anything else
the same shape?" A first whole-artifact round asks the second question.

Swept the other mutations for the same shape: M1/M2 break t8b, M3/M4 break
t8c/t8d via pins 3a/4a and gate 9, M6 breaks m41/m41b, M7a/M7b break the two
grep guards, M9 uses t7, and M8's structural gate 8 is explicitly the only
signature available for a deletion no behaviour observes. M5 was the only gap.

Also fixed before commit: gate 13 was first inserted before gate 12.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 18:32:22 +02:00
Levi Neuwirth 253249ec0b
S16 draft amendment 1 rev J: a correction that explains a count must not restate it
Independent review of 9e43994 returned one blocking finding in three live
consumers: adding gate 12 in revision G restored the tally defect this
contract had already removed twice.

Three sites still said §4 has "eleven gates, 1-11":

- revision C's disposition for its finding 3;
- gate 4's scope note;
- §6 item 2, immediately after the words "No count is stated here -- §4 is the
  single origin."

All three removed, not updated. The revision-C record now says only that the
4a. scope note was demoted. Gate 4's note identifies §4a without counting
gates. §6 item 2 keeps the pointer to §4 and adds only that lettered subchecks
report under their gate.

§6 item 2 is the one that indicts the method: it declared §4 the single origin
and restated a count in the same breath. Revision B removed "the nine gate
results" from that very item; revision C's correction then wrote the
then-current number into the explanation; revision G's new gate made it false
again.

The rule this makes explicit: a correction that EXPLAINS a removed count must
not restate the corrected value. Say what changed, not what the number now is
-- otherwise the record becomes a new instance of the defect it records, and
the next addition to the set falsifies the explanation instead of the
original. Every count this contract has removed was re-created by the prose
written to remove it.

The sweep confirms the rule is not "no numbers anywhere". A count at its
origin, immediately above the table enumerating the set -- pin 1a's three
revised tests, pin 8's four G3a tests -- is read off rather than restated, and
a change to the set edits the table and the adjacent word together. The defect
is a count living away from the set it counts.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 18:19:02 +02:00
Levi Neuwirth 9e43994def
S16 draft amendment 1 rev I: where a pin defines the artifact, the gate cites it
Independent review of 5d2db93 returned one blocking finding: gate 8's new
method named a boundary that made the gate impossible to pass or honestly
fail.

Revision H said to quote create_staff_group's production body "to the
#[cfg(test)] boundary." But create_staff_group begins at reduce.rs:4458,
create_part_definition begins at :4515 and carries its own
PreconditionFailureReason::TargetMissing at :4554, and the next #[cfg(test)]
is at :9576. So the literal read spans roughly 5,000 lines and always contains
the very path the gate says must be absent, while any shorter read violates
the stated boundary.

Gate 8 now quotes exactly pin 1's slice: create_staff_group's body,
brace-matched from its fn line to its closing brace, production source only.

Pin 1 had the boundary right the whole time -- "slice the create_staff_group
body (brace-matched from its fn line to its closing brace, production source
only)". Revision H invented a second, looser boundary instead of citing the
pin. That is revision A's failure in a new place: importing a
plausible-sounding rule rather than re-deriving from the source that owns it.
There it was an S27 conclusion; here a boundary borrowed from a different kind
of check. The #[cfg(test)] boundary is the right instrument for "is this call
site production or test", which is what §0.4 used it for; it is the wrong
instrument for "where does this function end."

The rule: where a pin already defines the artifact, the gate CITES the pin, it
does not redescribe it. A redescription is a second definition, and two
definitions of one artifact are a contradiction waiting for someone to read
the looser one.

Worth noting the failure kind. This was not a gate that passes when it should
fail -- revision H's usual shape -- but a gate with no passing state at all.
It would have surfaced at execution, with an agent forced to choose between
obeying the boundary and obeying the requirement, and whichever it chose would
have been reported as a pass.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 18:14:49 +02:00
Levi Neuwirth 5d2db937e9
S16 draft amendment 1 rev H: where a gate must establish a mapping, it cannot count
Independent review of 09d8439 returned one blocking finding. A sweep found a
second of the same family.

1. Gate 12's four-line aggregate could pass with one surface missing. Both
   definitions can exist (2 lines) while check_invariants calls
   check_staff_names_absent_group TWICE and check_group_lists_unowned_staff
   NEVER (2 lines). Four lines total, the stated "fewer than four fails" rule
   reports success, and M6b has no call site to delete.

   Replaced by four independent grep -c checks, each required to be exactly 1
   -- so a count ABOVE 1 now fails too, catching the doubled dispatch
   directly. Plus quoted context, because a count is not a mapping: each
   definition with its enclosing impl GraphIndex<'_> header, proving it is a
   method on the type check_invariants builds; each dispatch with the pub fn
   check_invariants header, proving the call is in the dispatcher M6 edits and
   not in a test or a second dispatcher.

   This is the contract's oldest defect class in new clothes. Revisions A-C
   removed counts that had gone stale; this one was never right -- an
   aggregate can be satisfied by the wrong distribution of the same total.
   Where a gate must establish a mapping, it cannot count. It has to check
   each element on its own, which is the structural sibling of the rule this
   document already carries: where a claim requires completeness, do not
   enumerate, derive.

2. Sweep: gate 8 asserted an absence with no method. "contains the
   empty-members refusal and no member-liveness/TargetMissing path" named no
   command, and a TargetMissing path can be spelled without either literal, so
   any grep would prove only that a chosen string is gone. Method pinned:
   quote create_staff_group's production body in full to the #[cfg(test)]
   boundary and read it, explicitly not a grep -- S27's gate-6a lesson and the
   reason its gate 6c quotes a definition rather than searching for it. M8
   signs exactly this gate, so a vacuous gate 8 leaves M8's deletion
   unobserved.

Both findings are gates that report success without observing what they
claim. One counted instead of pairing; the other asserted an absence with
nothing able to establish it. A structural gate needs a method, and the method
must distinguish the passing case from every failing one -- not merely from
the most obvious failing one.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 18:09:08 +02:00
Levi Neuwirth 09d8439c93
S16 draft amendment 1 rev G: pin the structure a mutation deletes
Independent review of 2818ced returned one blocking finding: M6 was
unexecutable against a conforming implementation.

M6 assumed two independently removable arms, but pin 6 and pin 6a specify
behaviour only. A single shared comparison -- one walk emitting a violation
whichever way Staff.group and StaffGroup.members disagree -- satisfies m41,
m41b, the generator test and gate 6, and leaves nothing for M6 to delete one
at a time. Deleting the shared check disables both directions, so M6's
required "one test fails while the sibling passes" observation cannot be
produced at all. M6 was executable only against one implementation style,
which nothing required.

Pin 6b added: the mutation surface is pinned as two GraphIndex methods
following the crate's existing idiom --

  fn check_staff_names_absent_group(&self, out: &mut Vec<InvariantViolation>)
  fn check_group_lists_unowned_staff(&self, out: &mut Vec<InvariantViolation>)

both emitting StaffGroupMembershipAgreement violations, both dispatched from
check_invariants. The names are pinned because gate 12 greps for them and M6
deletes them by name -- the same reason S27 had to pin synthetic_for_fixture
after finding its gate searched for a name offered only as an example.

M6 is now M6a and M6b, each deleting one named call site. Gate 12 added:
structural, proving both definitions and both call sites exist -- four quoted
lines -- BEFORE M6 is attempted, so the surface's absence is a finding rather
than a mid-run discovery. Fewer than four lines is a pin 6b violation.

This is precedent, not invention: check_invariants (invariants.rs:257-:282)
already dispatches 23 check_* methods for 20 invariants, so more than one
method per invariant is the crate's existing shape. A shared helper both
methods call is explicitly permitted -- the deletable call site is what M6
needs, not a duplicated walk.

The class is one S27 hit twice, its M5 and M6 both rewritten after review
found no runnable observation behind them. The tell is identical: a mutation
phrased as an edit to a structure the pins never required. Behaviour pins
constrain outcomes; a mutation deletes code. Where a mutation is the
signature, the structure it deletes must itself be pinned -- otherwise the
contract is satisfiable in a shape that makes its own evidence unobtainable.

Also fixed before commit: gate 12 was first inserted before gate 11, leaving
the sequence 10, 12, 11. Moved, and a stray double blank line collapsed.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 17:59:30 +02:00
Levi Neuwirth 2818ced229
S16 draft amendment 1 rev F: a transformation's output needs its input's guarantees
Independent review of abe2c35 returned one blocking finding, and it is both
prior revisions' lessons colliding.

The shrink leg had no observable direction or exactness guarantee. Row 8
requires the S->G fixture to survive shrinking, but:

- the named generator test asserted only on the raw violating_score(...);
- the shrunk score was checked solely by
  every_invariant_shrinks_to_a_small_witness (generators.rs:1003), whose
  !check_invariant(&small, inv).is_empty() is membership in ONE
  GraphInvariant variant -- and both directions of invariant 21 are the same
  variant, so a shrunk witness that flipped to G->S-only passes it. Because it
  calls check_invariant (singular) rather than check_invariants, a shrunk
  witness that gained an unrelated second defect passes too;
- §6 item 2d still said "quote the shrunk witness," which a passing test
  cannot emit.

So a shrunk witness that changed direction, or acquired a second defect while
retaining invariant 21, satisfied every assertion and every gate.

Fixed: the named test now asserts the same three properties TWICE -- on the
raw fixture and again on shrink(&that, StaffGroupMembershipAgreement): exactly
one violation and it is StaffGroupMembershipAgreement, the witness naming the
S->G ids, and G->S asserted satisfied. Gate 6 requires both legs. Item 2d
rewritten to revision E's source-assertion-plus-pass-verdict model. Item 2e
extended to both legs. Row 8's description of the existing shrink tests now
says plainly that they establish only that SOMETHING still fires, and that
direction and exactness after shrinking come solely from the named test's
shrunk leg.

Two lessons collided here. Revision E established that a gate must name
evidence its artifact produces and fixed gate 6 -- stopping one hop short of
item 2d, which is the fix-propagation failure revisions A-D kept recording.
And the underlying gap is revision D's: a requirement, "survives shrinking,"
with nothing able to fail it.

The generalisable rule now recorded: shrink is a TRANSFORMATION, and a
transformation's output needs the same guarantees asserted of its input.
Requiring a fixture to "survive" a transformation establishes only that
something survived. Every property the input was pinned for must be
re-asserted on the output, or the transformation is free to change what the
fixture proves.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 17:51:21 +02:00
Levi Neuwirth abe2c359f7
S16 draft amendment 1 rev E: a gate must name evidence its artifact produces
Independent review of cae1d32 returned two blocking findings and one stale
rationale. Both blocking findings are in requirements revision D itself wrote,
and both are revision D's own closing lesson turned back on it.

1. Row 8's new generator test had no name, so nothing consumed it. Gate 6
   named only m41 and m41b; §6 item 2d asks for shrink evidence. Omitting the
   test entirely would still compile, satisfy all four all() loops, and pass
   every named gate.

   Named invariant_21_negative_generator_breaks_staff_to_group_only, with its
   three assertions spelled out: exactly one violation and it is
   StaffGroupMembershipAgreement, the witness naming the S->G ids, and the
   G->S direction asserted satisfied. Added to gate 6 and to new §6 item 2e.

   This is revision D's own lesson unapplied to itself: it closed by
   distinguishing a rule with no consumer from a rule with no observer, then
   wrote a requirement with neither. An unnamed artifact cannot be gated,
   because every gate here names what it checks.

2. Gate 6 demanded runtime evidence the prescribed tests cannot emit. It said
   to quote check_invariants' full return and witness ids, but these are
   assert!-style tests in m40's shape and cargo test prints ok, not local
   values. Obeying it literally would need unpinned --nocapture
   instrumentation added purely to produce a report, or source inference
   presented as observation.

   Evidence model now chosen explicitly: quote the SOURCE assertions plus the
   pass verdict. A passing exact-set assertion IS the observation -- the
   assertion text says what was checked, the verdict says it held. This
   follows S27's gate 6c, which quotes a struct definition rather than
   grepping for it: a quoted source construct is read, not inferred. It also
   adds no code to epiphany-core written solely for a report.

   The requirement was right and the mechanism was borrowed from gates that
   run commands and read stdout. A gate must name evidence the prescribed
   artifact actually produces; otherwise execution improvises, and improvised
   instrumentation is unpinned scope arriving through the report.

3. Gate 4's rationale still said row 11 is "conditional," which revision D
   changed to decided-unused. A fourth site under pin 10a said "carrying it
   conditionally costs nothing" -- found by sweep. Both updated. The subset
   rule itself is unaffected; only its rationale needed the current term.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 17:42:22 +02:00
Levi Neuwirth cae1d32794
S16 draft amendment 1 rev D: a requirement no assertion can fail is not a requirement
Independent review of 25473a1 returned two blocking findings. A sweep
escalated one of them into a third. Both reported findings are the same
failure in different clothes: a requirement stated with nothing able to fail
it.

1. Pin 10a still deferred the label decision to execution -- twice reworded,
   never decided. The facts were readable in the .tex source the whole time:
   core_spec.tex:6529-:6648 is ONE requirement box carrying the single label
   req:graph:score-graph-invariants, with exactly 20 \items inside it.
   Invariant 21 is a 21st \item within that box, so pin 6 mints nothing. Pin
   10 rewrites prose plus a Revision History row and version bump, so it mints
   nothing either.

   DECIDED: neither document mints a label; touch row 11 is UNUSED and must
   not be staged; no counter moves. If execution finds otherwise that is a
   finding against this contract, not a keyboard decision. The counter table
   is retained for that case and for the next rung. Row 11 is kept rather than
   deleted because CLAUDE.md names the file as a recurring escapee -- a row
   reading "deliberately unused, and why" survives review; an absent row looks
   like an oversight.

   "Decide and report" reads like rigour and is its opposite: it makes the
   staged set and counter expectations depend on a choice made at the
   keyboard, so the touch table can be wrong in either direction and the
   report will agree with whatever happened.

2. Pin 6a required each fixture to violate its own direction only, and nothing
   could observe that. The prescribed model, m40, asserts only
   check_invariants(&s).iter().any(...) -- any() cannot see a second unrelated
   defect -- and gate 6 checked the target verdict and the opposite direction
   but never the absence of invariants 1-20. So a fixture carrying an
   unrelated second defect satisfied every stated gate and mutation outcome.

   Each m41/m41b must now assert the EXACT violation set: exactly one
   violation, StaffGroupMembershipAgreement, witness naming that direction's
   staff and group ids, opposite direction asserted satisfied. Gate 6 reports
   check_invariants' full return for both.

   Borrowing a test's shape imports its blind spots along with its virtue. m40
   was cited for its dispatch property, which is real and still applies;
   nothing about invariant 20 ever turned on exactness.

3. Sweep: the same blind spot covers touch row 8's generator, and worse.
   negative_generators_are_reasonably_targeted bounds kinds:
   BTreeSet<GraphInvariant> at <= 3, but both directions of invariant 21 are
   the SAME variant -- they collapse to one element, so no existing test can
   observe direction at all; the other three all() loops assert only
   !is_empty(). Row 8 now requires a dedicated permanent test that the
   generator violates S->G and not G->S.

Also fixed: revision D's block was first inserted inside revision C's,
orphaning C's closing paragraphs after it. Reordered, and the cross-revision
pattern paragraph moved to the end and extended.

That paragraph now carries rev D's converse: the fix-every-site rule asks who
READS a corrected rule; rev D asks what OBSERVES each requirement. Findings 2
and 3 were invisible to every sweep that looks for restated text, because
nothing was restated. A rule with no consumer goes stale; a rule with no
observer was never enforced at all.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 17:22:31 +02:00
Levi Neuwirth 25473a1bc5
S16 draft amendment 1 rev C: a mutation is a test's signature, not its substitute
Independent review of 0a5b936 returned two blocking findings and one factual
error. The first two are one issue: invariant 21 mandates two directions, and
only one -- unspecified -- had durable evidence.

1. Neither direction had permanent named coverage. Pin 6 asked for "a score
   violating only invariant 21" (singular), gate 6 asked for one score, the
   generator carries one, and M6 observed both directions only while mutated.
   A mutation is reverted, so the restored suite could ship with one branch
   untested.

   Pin 6a added: two permanent, direction-isolated tests --
   m41_check_invariants_dispatches_invariant_21_staff_names_absent_group (S->G)
   and m41b_check_invariants_dispatches_invariant_21_group_lists_unowned_staff
   (G->S) -- each required to SATISFY the direction it does not break. Gate 6
   requires both verdicts. M6 now breaks those exact tests, one each, and
   requires the sibling to still pass; the surviving test passing is what
   proves the arms independent rather than one arm catching everything.

   This contract already stated the rule and did not apply it to itself: pin
   3a says "a mutation demonstrates the hazard once; only a test keeps it
   demonstrated." M6 was carrying both directions on mutation alone, three
   sections below that sentence.

2. "One named direction" delegated a design decision to execution. Either
   choice changes the generated witness and the shrink evidence, so reporting
   it afterward is not specifying it. Pinned to S->G in touch row 8, with the
   reason: smallest corruption of valid_score (drop the staff id from
   group.members, leave staff.group intact), matching every other arm's
   doctrine, and the exact shape pin 2's append failing produces -- which is
   what M2 observes.

   Three fixtures now have three distinct purposes: row 8's generator (S->G,
   survives shrink), pin 6a's two direction-isolated tests, and M6 as their
   signature. None stands in for another.

3. §6's revision-B history said §4 has "twelve entries -- 1-11 plus 4a," a
   false identity. The item numbered 4a. was a scope note with no command and
   no output -- it could not be "a gate result" -- and it collided with §4a,
   the landing-obligation section. Demoted out of the gate numbering into gate
   4's body. §4 now has eleven gates, 1-11, and §4a is unambiguous.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 17:15:33 +02:00
Levi Neuwirth 0a5b93688b
S16 draft amendment 1 rev B: a correction propagates one hop and stops
Independent review of 3096c54 returned three blocking findings, all in
revision A's text, and each is a rule revision A had just corrected surviving
one step downstream of where it was fixed.

1. §6 item 2c still said "all three counters and their new values" -- the rule
   pin 10a corrected in the same revision. Third site of one false claim: the
   pin, then touch row 11 (caught by rev A's sweep), then the report item that
   READS the pin. Now points at pin 10a's table and requires naming which
   document minted the label.

2. §6 still demanded "the nine gate results" while §4 carries twelve entries
   (1-11 plus 4a). Revision A removed the identical tally from item 1 for
   mutations and left its neighbour on the next line standing. Count removed,
   §4 named as origin, 11a-e identified as subchecks of one gate rather than
   five separate results.

3. Touch row 8 still required violating_score's fixture to violate "both
   directions" while M6 requires direction-isolated fixtures -- incompatible
   evidence models in one contract. A both-direction generator remains
   reported after either M6 arm is deleted, so it cannot sign that arm's
   absence. Row 8 now specifies one named direction plus shrink survival; pin
   6/M6 own two separate isolated fixtures. violating_score returns one Score
   per variant and could not have carried both regardless.

Found by sweeping and fixed with them: gate 7 and §6 item 4 both said "the
four pin-8 tests." Correct today, but the same construction -- a count
restated away from its origin, and inconsistent with the two tallies just
removed. Pin 8's table named instead.

The pattern across revisions A and B is sharper than any single finding: a
correction propagates one hop and stops. Rev A fixed pin 10a and left touch
row 11; the sweep caught row 11 and stopped before §6's consumer. Rev A
removed item 1's mutation tally and left item 2's gate tally on the next line.
The fix-every-site rule is not satisfied by fixing the site and its obvious
neighbour -- it requires asking who READS the corrected rule.

Noted, not changed: §6's items run 2, 2b, 2c, 2d, 2a because 2a predates the
new items. Cosmetic, and renumbering would break pin 12's and gate 10's
references to item 2b.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 16:45:50 +02:00
Levi Neuwirth 3096c54d09
S16 draft amendment 1 rev A: stop importing S27 conclusions unre-derived
Independent review of d06e2f7 returned six findings, five blocking, all in
draft amendment 1's own text. A sweep found a seventh: the same false claim at
a second site.

1. Report item 2d asked execution to decide a static fact the draft could
   read. shrink (generators.rs:932) does NOT match GraphInvariant -- it calls
   check_invariant(score, inv). The unverified claim was made twice, in item
   2d and in touch row 8. Both corrected. Item 2d replaced with the real
   obligation: invariant 21's fixture must survive shrinking (:1025), since
   shrink asserts on entry that its input still violates the target.

2. Pin 10a's "all three counters move if either document mints a label" is
   false. CORE_REQUIREMENT_COUNT is asserted only against core_spec.tex
   (requirement_labels.rs:259); a label in operation_catalog.tex moves the two
   suite counters only. Replaced with a per-document table.

   Sweep finding: touch row 11 carried the same false sentence and was left
   standing while pin 10a was fixed -- the fix-one-site defect, committed
   inside the edit that fixed the other site. Row 11 now points at pin 10a
   rather than restating it.

3. Gate 11 permitted the exact tautology it exists to prevent. "Updated, not
   silenced" does not forbid replacing the literals with
   CURRENT_REDUCTION_ALGORITHM_VERSION -- the tidiest-looking update, after
   which both operands move together and M5a/M5b are vacuous. Rewritten as
   11a-e requiring independent literal 1 values, never the constant, each
   quoted. S27 round 3 caught this substitution and roundtrip.rs:882 forbids
   it by name.

4. Gate 11 omitted roundtrip.rs:947, test 10b's mutation-only Err arm. Left at
   0, M5b aborts on the base comparison before reaching the two-field panic
   that is its required observation -- failing at the wrong assertion while
   observing nothing. Added as 11d, with 11e for the literal-preservation
   comments whose reasoning is what stops the next rung making substitution 3.

5. §6 demanded "the nine mutations (M1-M9)" while M7's split makes ten
   executions. Count removed; §3 is the single origin.

6. Pin 12 said no gate catches a missed bump except the tripwires, written in
   the same amendment that added gate 10, which compares the value against
   HEAD directly. Split: gate 10 guards this bump, 11a-e guard the wiring,
   only the general future case stays undetectable.

Tightening folded in with finding 1: M6's two fixtures must each violate ONE
direction only. A fixture disagreeing in both is still reported after either
arm is deleted, so the mutation appears to fail correctly while signing
nothing. The same trap applies to touch row 8's generator, whose all()-driven
consumers only ask whether 21 is reported.

Findings 1, 2, 3 and 6 share one root cause: an S27 conclusion applied without
re-derivation. S27's "name all three counters," its "no mechanism can detect a
semantics change," and its literal-independence rule are true statements about
S27; two are false or incomplete here and one was dropped where it was needed.
A ratified contract is reusable as a source of questions, not of answers.

Still DRAFT, still unratified. No implementation work has begun.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 16:39:12 +02:00
Levi Neuwirth d06e2f7266
S16 draft amendment 1: fourteen findings from ratification reconnaissance
Fourteen findings, thirteen blocking, against the draft BEFORE its first
ratification round. Nine from the recon pass, five from a second sweep of the
same defect classes. The contract is a DRAFT, so these are edits to an
unratified plan, not amendments to frozen pins.

Root cause, and the one that changes the rung's shape: invariant 21 is a
TWO-crate change. violating_score (epiphany-core/src/generators.rs:498)
matches GraphInvariant exhaustively, so the new variant does not compile
without an arm, and four all()-driven tests (:991, :1004, :1025, :1042) then
require a real generator rather than a stub. The contract had treated the enum
extension as local to invariants.rs. Nothing in its §0 inspection would have
surfaced this -- it appears at compile time, after execution begins.

Touch table gained five rows:
- epiphany-ops/src/lib.rs -- the bump and its Bumps entry. The rung's defining
  act had no pin, no touch row, no gate and no report item; it existed only as
  a note inside pin 0's discharge. Now pin 12, touch row 7, gate 10, item 2b.
- epiphany-core/src/generators.rs -- the root cause above.
- epiphany-testkit/src/roundtrip.rs and epiphany-textproj/src/serialize.rs --
  S27's two tripwires. Test 10b panics by design once the authority moves;
  test 10a asserts the literal 0 and its own doc says it is expected to fail
  when S16 bumps. Both fail gate 1 with no row to fix them in -- the same
  shape as S27's own gminor.rs failure. Gate 11 requires they be updated, not
  silenced: a tripwire accepting both values rebuilds the tautology S27
  existed to remove.
- requirement_labels.rs -- conditional, the escapee CLAUDE.md names by name.
  Pin 10a now forces an explicit decision on whether pin 6 or pin 10 mints a
  label; this rung touches both counted documents, and all three counters move
  if either does.

Gates: 2 and 3 now pin +1.95.0 (CI gates on it; this machine defaults to
1.97.1). Gate 3 formatted two crates of four and would have reported clean
over the two the new rows added. Gate 1 gained the 1577/0/0 baseline, three
delta buckets, and a 0-ignored requirement. Gate 4's "exactly §2" was the
formulation S27's round 17 found unsatisfiable with a conditional row.

Mutations: M1, M2 and M4 accepted "the named test fails" as their whole
signature; each now names the behaviour the mutated build produces -- the
applied spurious mint, the still-empty members, the re-carry misverdict. M3,
M5, M6 and M9 already met the standard. M7 covered two independently guarded
doc blocks while reverting one, so it could pass with the other guard still
weak; split into M7a and M7b, each quoting its own needle's non-match.

Locators: pin 8's four tests were identified by INTERIOR line numbers, a dozen
lines into each body, anchored to nothing searchable -- now named. t6/t7/t9
re-derived to :16158/:16231/:16461, with the trap recorded that reduce.rs has
two t6/t7 families and grepping "fn t6" lands on the wrong one.

New §4a, landing obligation: the bump falsifies live statements in
CLAUDE.md:106 and the handoff's POST-S27 block. Both are explicitly NOT staged
during execution -- staging them would assert the rung had landed while it
awaited acceptance -- and are required as post-acceptance reconciliation the
report must list as outstanding. Pin 11's ledger row is different and is
staged: a ledger records what a rung did; those two state what is true now.

Report item 2d requires execution to determine whether shrink() also matches
GraphInvariant exhaustively. Deliberately not guessed -- guessing about an
exhaustive match is what produced the root-cause finding.

Findings 5-8 are all defects S27 had already found and fixed in its own gate
set; this contract predates those corrections and inherited none of them. The
next contract drafted here should start from S27's §5.

No implementation work has begun. Still DRAFT, still unratified.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 16:26:12 +02:00
Levi Neuwirth d2e43b4204
S16: separate enforcement from detection in the pin-0 supersession
The supersession declared pin 0's "no mechanism to detect a
reduction-semantics change" false because version mismatches are now
rejected. That conflates two different claims, and it contradicted this same
contract's requirement 3 thirty lines below, which says no mechanism can
detect a missed bump. CLAUDE.md, the handoff, and epiphany-ops's own
authority doc all state the correct version.

Only one of the two claims moved:

- Declared-version mismatch -- a base whose recorded
  reduction_algorithm_version differs from the running authority -- is now
  ENFORCED, refused with CanonicalBaseRequiresRebuild on read and write.
- A semantics change is STILL UNDETECTABLE. Nothing compares the semantics
  the code implements against the number it declares, and nothing can.

So S27's enforcement is conditional on the bump discipline, not a substitute
for it. If this rung changes CreateStaffGroup's verdict and the bump is
missed, every base it produces declares 0, matches an authority still reading
0, and passes every check S27 installed -- the enforcement fires correctly on
a number that is itself wrong. That is exactly why pin 0's requirement 3
inverts into a mandatory bump rather than dissolving: S16's bump to 1 is the
human-enforced half of the guarantee, and the only half that applies to
itself.

Changes:
- The falsified-claims table splits the row in two: the accepted-stale-base
  consequence is false now; the no-detection claim is marked STILL TRUE.
- New "Enforcement is not detection" section states the split as a table so
  the two cannot collapse into each other again.
- The discharge marker before pin 0 no longer lists no-detection among the
  falsified claims and warns not to read the discharge as closing that gap.
- Pin 11's retained blockquote had the same defect: it was annotated "every
  claim in this quoted block is now false," but "no mechanism comparing
  either against the semantics it actually implements" is still true -- S27
  compares a declared number against a declared number. Annotation now
  separates what is false from what stands.

Documentation only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 15:46:53 +02:00
Levi Neuwirth af378d2d0f
Handoff: make the POST-S27 block genuinely the sole source
The top block claimed to be "the only place" the new state is given, then
§1.4, §2.6, §4.3 and §1.5 restated current S27/S16/collision status anyway.
Rather than weaken the claim to match the text, the later sites are reduced to
closure pointers -- duplicated live state is the defect this whole sequence
has been about.

- §1.4 now gets the same treatment as §1.2: the ORIGINAL pre-S27 chain diagram
  is restored as a dated record under a section-level supersession marker, and
  the in-place rewrite is removed. This also covers the rest of §1.4, which was
  already stale in ways nothing had marked -- S27's "still DRAFT, now
  dispatchable" line and the three inherited items it now discharges.
- §2.6 and §4.3's collision notes reduced to "superseded -- see the collision
  row," with a pointer to §2.3, which remains the correct home for what
  actually blocks T1b and is unaffected.
- §4.3 items 7 and 9 reduced to closure pointers.
- §1.5 was a site nothing had touched: it stated S27 as UNBLOCKED and
  dispatchable as current fact. Now marked as an as-of-2026-08-07 snapshot
  with the ledger named authoritative per row.

No new state is stated anywhere below the top block; every later mention is a
supersession or closure marker. Documentation only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 15:43:09 +02:00
Levi Neuwirth 9153623aa1
Post-S27 docs: scope the supersessions properly in handoff and S16 contract
Follow-up review found the previous reconciliation half-done in two places.
Documentation only; the accepted S27 code is untouched.

spec/HANDOFF_2026-08-07.md -- it declared CLAUDE.md the sole origin for the
green baseline and then stated the number twice anyway, once in its own update
table and once in §3.5. Both replaced by pointers; the figure now exists in
exactly one file. The §1.2 marker also said everything following it was
pre-S27 while two post-S27 notes sat inside that section. The notes are
deleted and their substance folded up into the top block's table rows -- the
permanent acceleration_snapshots warning onto the conformance row, the
"may not degrade to read-only" carry-over onto the errors row -- so §1.2 is
now purely a dated record. The marker is also scoped to §1.2 rather than
"everything after," which would have wrongly claimed §1.4 onward.

spec/CONTRACT_P13S16_PROJECTION.md -- pin 0 still carried live pre-S27
instructions: no authority exists, no mechanism detects a stale base,
ids.rs:288's catalog claim is false, this rung cannot execute, the ledger
stays blocked on P13-S27, and file S27. A status-and-ledger update did not
reach any of them.

- Pin 0 now carries a discharge marker BEFORE the pin, not only after it, so a
  top-down reader meets the correction before the false claims.
- The discharge answers each falsified claim individually in a table, and
  replaces all three numbered requirements. Pin 0's deliberate narrowing --
  that no history audit was done, so the stronger "never detectable" claim
  must not be written -- survives and still binds.
- Requirement 3 inverts rather than disappears: stale bases are now rejected
  and S27 owns those tests, so this rung must not add a second detection path;
  what it must do instead is bump CURRENT_REDUCTION_ALGORITHM_VERSION to 1.
- Pin 11's live "File P13-S27 in the same edit" instruction is struck inline,
  not only in its preamble, and the retained reasoning is properly blockquoted
  with every claim in it marked false.
- §6 report requirement 2a required confirmation that nothing was added
  detecting stale bases -- the opposite of what is now correct. Rewritten to
  require the version bump with its Bumps-list entry, no second detection
  path, and the unchanged operation_catalog.tex rebuild note.
- "The P13-S16 row is marked blocked on P13-S27" corrected; "does NOT move to
  RESOLVED" is retained, since it is still true and is the distinction that
  matters -- unblocked, dispatchable and resolved are three different states.

Line-number citations throughout the S16 contract predate S27's 795-line
bundle.rs change and are NOT re-derived here; that is recorded as part of
ratification rather than silently patched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 15:39:50 +02:00
Levi Neuwirth 8df798d907
Post-S27 doc reconciliation: CLAUDE, handoff, S16 contract, both ledger cells
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
2026-08-09 15:24:21 +02:00
Levi Neuwirth 4df8e257f3
P13-S27: accept reduction authority implementation 2026-08-09 15:05:58 +02:00
Levi Neuwirth 83df0a01be
P13-S27: record execution review 8 (CLEAN) and the invariant's terminating case
Execution review 8 returned zero findings against 480a299 -- the first clean
round since execution, and the second in the document's history.

This is a RECORD, not an amendment. It changes no pin, gate, test, mutation,
touch row or staged file. It appends a history row, marks the last
ratification-time bullet satisfied, and adds two things a clean round is the
only way to reach:

1. The invariant's terminating case. The locator amendment 7 fixed assumed
   every review produces an amendment -- review N produced amendment N. A
   clean review produces none, so a reader following the rule would look for
   an "amendment 8" that does not exist. Now: if the last execution review
   row shows 0 findings, no amendment followed and no pass is outstanding;
   the chain has closed. Same class as the Total-row locator defect, and
   reachable only once a round came back clean.

2. The history preamble's "every amendment is a row ... the amendment count
   IS the number of rows" was already false when written. The converse does
   not hold: round 19 returned zero findings and produced no amendment, so
   the identity broke the moment that row was added. Rows are events;
   0-finding rows produced no amendment. Corrected in the preamble and in
   the Total row's note.

What the clean round establishes and does not: it is round 11's criterion --
convergence evidenced, not findings exhausted -- and it is the stronger of
the document's two clean rounds, because what it reviewed had been executed,
gated and measured rather than only argued. It is not proof of correctness.
It reviewed amendment 7; no round has ever re-derived the whole document.

Established as of this record: the implementation is unchanged since
amendment 1's comment correction; gates 1-3 re-run cold against that exact
tree under amendment 4 (1577 passed / 0 failed / 0 ignored, 42 suites; clippy
and fmt clean on pinned 1.95.0); gates 4, 4a and §2 rules A/B re-run under
amendments 2 and 4; M7 ran with its three observations and control, examined
by three independent reviews with nothing returned against it; and every
finding across all eight reviews was in this contract, not in the 21 staged
files.

What remains is the owner's acceptance decision. This document does not make
it. Round 1's ratification was claimed by the author after a single round and
withdrawn; that precedent is why this record stops at the evidence.

Implementation still staged, still not accepted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 14:40:49 +02:00
Levi Neuwirth 480a299438
P13-S27 amendment 7: a single source is created by deleting the others
The independent review of amendment 6 returned two findings; the sweep found
a third. Three findings, all blocking. All three are failures of the
invariant amendment 5 introduced and amendment 6 refined.

1. The invariant contradicted five older standing instructions. It says only
   the most recent amendment needs a pass, while amendments 1-5 each still
   ended "this amendment needs another independent pass" -- five live
   commands, all false -- plus amendment 2's order to re-run gates 4 and 4a,
   already carried out twice.

   All closers rewritten as dated records: "Status when written (CLOSED) ...
   its pass closed as execution review N." The invariant now states outright
   that the amendment blocks carry no live status and none may be added.

2. The invariant's locator could not identify the pending amendment. It said
   read "the last row" of the history table, but the literal last row is
   Total, and the last review row names "execution review 6" -- an event,
   not an amendment. The rule could not be followed to an answer.

   Fixed: the last execution review row, immediately above Total, and the
   amendment it produced carries the same number -- review N produced
   amendment N, one per row, by construction.

3. Sweep: amendment 6's own closer had the same defect. The review named
   amendments 1-5; amendment 6's said "amendment 6 needs the next
   independent pass" -- true when written, false the moment amendment 7
   existed. Fixing only the five would have rebuilt the contradiction on
   this commit. Six closers, not five.

Finding 1 is the failure mode at its clearest. Amendment 5 removed a count
and wrote an invariant to own it; amendment 6 refined the invariant; neither
swept the five places already answering the question the invariant claimed to
own. A single source of truth is not created by declaring one -- it is
created by deleting the others. That has now had to be learned three times:
for counts, for figures in general claims, and now for instructions.

Finding 3 generalises the review's own scope gap: a correction that fixes
every currently-false instance of a claim but leaves the one instance that is
currently true has scheduled its own recurrence, because the true one goes
false on the next event. Correct by class, not by current truth value.

Amendment 7 touches no pin, gate, test, mutation, touch row or staged file --
a scope claim, not an inferred gate result. Implementation still staged,
still not accepted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 14:35:21 +02:00
Levi Neuwirth 3354e10bd9
P13-S27 amendment 6: which figures are allowed to look stale
The independent review of amendment 5 returned two findings; the sweep found
a third. Three findings, one blocking. All three are defects amendment 5
introduced while fixing staleness, which matters more than any of them
individually.

1. Blocking. Amendment 5's new meta-claim was false, and its own findings
   disproved it. It said every post-ratification amendment after the first
   was prompted by defects in THE PREVIOUS amendment's text. Amendment 5's
   findings were a status block amendment 3 left, a gate instruction
   amendment 2 wrote, and three pieces of ratification-time text predating
   execution -- none written by amendment 4.

   Widened to "the previous amendment's text, or earlier text a previous
   correction failed to sweep." The narrow version was load-bearing: it was
   the document's own account of why it keeps needing amendments, and it
   pointed the next reader at the last amendment rather than at every prior
   correction that stopped short of a full sweep. The corrected claim is the
   one that would have predicted amendment 5's own findings.

2. Live tallies reintroduced immediately below the no-restatement invariant
   -- "five reviews ... have now closed" and "The five amendments now have
   one diagnosis" -- both stale at the next pass, three lines under the rule
   forbidding them. Replaced with a table pointer and non-numeric phrasing.

3. Sweep: a third live tally in the same block, "four rounds of amendment
   traffic can read as instability." Made non-numeric.

Finding 2 is the pattern at its limit case: a rule violated three lines below
its own statement. That is not inattention -- "the amendments now share one
diagnosis" does not feel like a count while being one.

So amendment 6 states the rule execution reviews 5 and 6 each had to
rediscover, and which no statement of existed to apply: a figure recording
what a round found or did is historical and never updated; a figure inside a
general claim about the document's present state is live and must not be
written at all, wherever it sits, including inside an amendment block.
Location does not decide it; tense and scope do.

Two further self-inflicted defects caught before this commit: amendment 6's
own prose used "the last two reviews" and "two reviews running," both of
which read as live on any later reading. Made explicit.

Amendment 6 touches no pin, gate, test, mutation, touch row or staged file --
a scope claim, not an inferred gate result. Implementation still staged,
still not accepted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 14:20:27 +02:00
Levi Neuwirth c07a18000b
P13-S27 amendment 5: every fix that held was a deletion
The independent review of amendment 4 returned three findings, all stale
current-status prose. Sweeping found two more of the same kind. Five
findings, four blocking. No pin, gate, test, mutation or staged file is
touched.

1. The top status block said "Three independent reviews ... amendments 1, 2
   and 3 ... Amendment 3 ... needs its own independent pass" -- written while
   amendment 4 was being added three screens below, and stale before that
   commit landed. Count-staleness by restatement again, and the second
   occurrence inside the status block itself.

   Fixed by REMOVING the count and the amendment number, not by updating
   them. The block now states an invariant that cannot rot: the most recent
   amendment always needs the next pass; read the last table row for which
   one that is. No amendment number appears there.

2. "Gates 4 and 4a must be re-run and re-reported" stood at the top after
   both had been re-run, twice. An instruction outliving its execution, so
   the document's opening demanded work its own record showed complete. Now
   past tense with both runs named. Instructions go stale the same way
   counts do -- worth recording, because every prior staleness finding here
   was a count or a claim, never an imperative.

3. "What remains open after ratification" was still pre-execution text,
   asserting M7 unverifiable and that no gate, test or mutation had run.
   Marked as the ratification-time record, bullets struck with their
   execution outcomes, and the one still-open bullet identified as the only
   one.

4. Sweep: a SECOND copy of that block sat higher in the document -- "What
   ratification does NOT settle, stated at the top so it is not missed" --
   with identical staleness. Being higher it was read first, so the opening
   of the contract told a reader nothing had run. Same treatment, and the
   duplicate bullet the two blocks shared is merged rather than corrected
   twice.

5. Sweep: "No execution work may begin" read as live. It sits in the Probe
   RESULT subsection, three subsections past the SUPERSEDED BY RATIFICATION
   marker covering the exception, so it was the last thing before the
   history table. Marked lifted-at-dispatch.

Findings 4 and 5 give a rule this document had not stated: a supersession
marker governs the section it heads, not every later restatement of what it
superseded. Both blocks and the prohibition were downstream of markers that
already existed and still read as current.

The five amendments now have one diagnosis. Amendment 1 fixed a missing
surface; 2 through 5 each fixed duplicated state -- a count, a figure, a
disposition, a status claim, an instruction -- restated in a second place and
updated in only one. Every structural fix that has held was a deletion: the
history table replacing prose tallies, row 13's count, pin 3's 57, the
rung-type figures, and now the status block's count and amendment number.
Every fix that was a more careful restatement has failed.

Two self-inflicted defects caught before this commit: a paragraph three
lines under the new invariant enumerated "amendments 2, 3, 4 and 5" and would
have gone stale at the next one, and the correction itself asserted a
fragile new ordinal ("the sixth time"). Both rewritten without enumeration.

Gates untouched and not re-inferred: gates 1-3 stand on amendment 4's cold
re-run, gates 4/4a and §2 rules A/B on amendments 2 and 4. Stated as a scope
claim, not an inferred gate result. Implementation still staged, still not
accepted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 14:08:47 +02:00
Levi Neuwirth 1c0a6f02dc
P13-S27 amendment 4: an inferred gate result is not a gate result
The independent review of amendment 3 returned two findings; sweeping the row
adjacent to the second found a third. Three findings, all blocking.

1. Gates 1-3 were no longer evidenced against the final staged tree, and two
   claims asserted otherwise. Amendment 1 corrected the false writer comment
   IN CODE, after the gates had run. Amendment 3 then wrote both "the
   implementation has survived all three reviews unchanged" and "gates 1-3
   stand on an unchanged staged tree." Both false.

   A comment cannot change behaviour, but the gate is specified over the
   staged artifact, not over one a reader is invited to infer is equivalent.
   This is the substitution CLAUDE.md forbids by name -- "reasoning that a
   mutation would fail signs nothing" -- committed in the document whose
   subject is a check that was a tautology because nobody had measured it.

   Both claims corrected, and gates 1-3 re-run cold after cargo clean -p on
   all four touched crates:

     gate 1  1577 passed / 0 failed / 0 ignored, 42 suites, cargo exit 0
     gate 2  1.95.0, exit 0, 0 warning/error lines, all four crates
             observed re-Checking-ed, so not a cache replay
     gate 3  1.95.0, exit 0

   The 1577 is unchanged from execution, which is the expected outcome for a
   comment fix -- but it is now measured rather than predicted, and that
   distinction is the finding.

   Method note: both re-runs were first captured through tail, which
   truncated the aggregate counts and the Checking lines -- the same
   truncated-evidence failure §0.4 records as its second instrument failure.
   Caught and re-run with full capture before reporting. A gate result read
   through tail is not a gate result.

2. Round 9's finding-1 disposition still gave M7's reference home as
   epiphany-testkit, superseded in round 12 -- which found
   render_text_document is pub(crate) to epiphany-textproj and pinned the
   harness there. Supersession pointer added, following the convention round
   8's cell already uses.

3. Sweep: round 9's finding-2 disposition had the same defect. Its clause
   "with any difference enumerated and classified rather than assumed" was
   superseded in round 10, which found a byte difference would have a third
   cause outside both permitted classifications. Pointer added naming rounds
   10, 11, 13 and 14 as the chain that replaced it.

Findings 2 and 3 are the shape amendments 2 and 3 kept finding: a statement
true when written, left standing unmarked once a later round overruled it. A
disposition column is a history; unmarked, it reads as instruction.

Gates 4, 4a and §2 rules A/B re-run rather than inferred: staged 21, gate 4
--check clean, parse.rs/vectors.rs/text_projection.tex absent,
COMPANION_VERSION (0, 14, 0) both sides.

Amendment 4 changed no pin, no gate mechanic, no touch row and no staging
rule. Implementation still staged, still not accepted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 14:02:41 +02:00
Levi Neuwirth 727f9393a2
P13-S27 amendment 3: one omission, five sites, three amendments
The independent review of amendment 2 returned three findings. Sweeping each
one's other sites turned up three more, two of them inside pin 3 -- the pin
execution reads to build the type. Six findings, five blocking. Every one is
a defect in a previous amendment's text or in text a previous correction
should have swept; none is in the implementation.

1. The 39-site derivation did not derive from its cited source. It claimed
   §0.4's surface and used open 19+2 / create 15+3, which are the post-S27
   staged counts; §0.4's table gives 18+2 and 14+3, and §0.4 alone cannot
   yield 39 because two of the sites are S27's own. Rewritten as a three-leg
   table that names the pre/post-S27 transition and attributes both added
   sites to test 10b (roundtrip.rs:897, :928). The result was right and the
   derivation was false, which is the worse failure: a wrong number gets
   caught by recounting, a wrong derivation teaches the next reader to
   recount wrongly.

2. The "rung type" paragraph still named two constructors at 60 and 32
   sites -- the fourth live site of the omission. create_versioned named,
   and the figures removed rather than corrected. This paragraph has now
   been left behind by a §0.4 correction twice: round 1 left it saying 57,
   amendment 1 left it naming two constructors.

3. Sweep: pin 3 said "required at both constructors" and named only open
   and create. Fifth site, and the first inside a pin.

4. Sweep: pin 3 carried "their 57 call sites are unchanged" -- a figure
   round 1 withdrew from §0.4 on finding its basis was a .commit( token
   grep counting epiphany-editor-core's same-named method. §0.4 states no
   number; the pin kept the withdrawn one through nineteen rounds and two
   amendments. It also reproduces against nothing: the only non-Bundle
   commit receiver is editor-core's own method (2 sites), so Bundle-typed
   counts are exact -- 58 at 381c498, 60 at 96b40b2, 60 pre-S27, 65 staged.
   Number removed, not replaced.

5. Sweep: the single synthetic site was attributed to M7. It is test 10b's
   fixture, and round 9's finding is precisely that test 10b is not a
   validated reference M7 can use -- which is why round 12 pinned M7's
   harness to epiphany-textproj. No M7 artifact exists in the staged tree.

6. Status said amendment 2 changed "two touch rows"; it changed one, row 13.

So: one omission, five sites, three amendments, and two amendments that each
declared it closed while it was live in three more places. Amendment 3
deletes two figures and one count-bearing clause rather than correcting
them.

The review independently reproduced gate 4a -- both companion values
(0, 14, 0) despite moving line 70 to 72 -- the first time a gate this
document added was verified by other than its author.

No gate needs re-running: amendment 3 changed no staging rule, gate mechanic
or touch row. Implementation still staged, still not accepted; amendment 3
changed pin 3 and needs its own independent pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 13:52:59 +02:00
Levi Neuwirth 28cd991502
P13-S27 amendment 2: a touch table and an absence rule are one allowlist
The independent review of amendment 1 returned four findings, every one of
them in amendment 1's own text rather than in the implementation it ruled
on. Sweeping each finding's other sites turned up a fifth the review did
not reach. Five findings, four blocking.

1. Touch row 15 stages crates/epiphany-textproj/src/lib.rs while two other
   clauses call that exact file deliberately absent and make gate 4 fail if
   it is staged. The staged tree therefore failed the contract as amended,
   and the execution report called gate 4 clean because it checked staging
   against §2's table and not against the absence rule below it.

   That file is where COMPANION_VERSION lives (:72), so its absence WAS the
   mechanical guard on the ruling's "COMPANION_VERSION stays 0.14.0". Row 15
   removed the guard silently. Fixed by splitting the absence sentence into
   the two unrelated rules it conflated, and by adding gate 4a, which
   compares the constant's value instead. Running it demonstrates why: the
   constant moved from line 70 to 72, so any diff-keyed check reports a
   change that did not happen.

   Rule A is also now explicit that it covers ONE of M7's three edit sites.
   serialize.rs and project.rs are staged under row 9, and absence cannot
   test a file that is supposed to be present.

2. "Direct construction at all 23 sites" is 39. The 23 is exactly touch row
   2's count of in-crate open sites in bundle.rs -- one file, one
   constructor -- restated as a cross-crate total over three. Corrected, and
   converted into a derivation from §0.4's surface so it can be rechecked
   without hand-counting.

3. Row 13's "92 converted sites" is 60 open + 32 create: the
   two-constructor figure, missing create_versioned's 3, inside the very
   amendment added to close that omission. The count is deleted rather than
   corrected -- the row needs "two crates", and any figure >= 1 makes the
   re-export unavoidable. Complete pre-S27 surface is 95.

4. Found by the sweep, not the review: §7 item 5 still had the report
   reconcile against open 60 + create 32. A report obeying it literally
   would re-derive the incomplete surface and call it a match. Also marks
   those figures pre-S27, since S27's own tests move the tree to 66/33.

5. "Touch rows 13 and 14" for the helper roots; they are 14 and 15.

Three of the five are count defects inside an amendment whose own subject
was a count defect, and two reproduce the exact omission it was written to
close. So amendment 2 deletes one count and derives the rest rather than
restating them more carefully; restating carefully is what rounds 1-7 tried.

Gate 4's earlier clean result is withdrawn -- measured against half of §2.
Gates 4, 4a and rules A/B re-run and pass. Gates 1-3 stand: the staged tree
is byte-identical to the one they ran against. Implementation still staged,
still not accepted; amendment 2 needs its own independent pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 13:25:52 +02:00
Levi Neuwirth faea317d4a
P13-S27 amendment 1: §0.4 missed a third constructor; four files had no touch row
The first independent review of the staged execution returned five findings,
three blocking. The pins were frozen at ratification, so these are an
amendment with its own review round rather than patches.

Section 0.4 never counted Bundle::create_versioned -- a third public
constructor whose signature this rung changes, three sites, and zero
mentions across nineteen review rounds. It searched Bundle::open( and
Bundle::create( and concluded about "the writer surface". That is the fourth
instrument failure recorded in that one section, and the same shape as the
first three: a count taken from one spelling and generalised. The first
could not see a propagating path, the second asserted a universal negative
from head-truncated output, the third resolved a method name without
resolving its type, and this one enumerated two of three constructors.

That omission was the root cause of the second finding. testkit/gminor.rs
calls only create_versioned, so it never appeared in any surface count and
never got a touch row. Gate 4 failed during execution and caught it, along
with three more files in no row: bundle/src/lib.rs, whose re-export pin 3
makes unavoidable since 92 converted sites in three crates cannot name a
type the crate does not export, and the two crate-root capability helpers.
Touch rows 13 through 16 added.

production_caps() was unpinned design scope, not merely a missed path, and
in epiphany-testkit it landed as new public API. Ruled under pin 3b:
sanctioned, name pinned, visibility pinned per crate. pub(crate) in
epiphany-textproj, a production crate whose five uses are all in-crate, so
this rung adds no public API there. pub in epiphany-testkit, a test-support
crate whose integration tests and benches are external consumers and cannot
reach pub(crate). The direct-construction alternative is recorded as
considered and rejected: it adds no API but repeats the same wrap 23 times,
and "explicit" was never the same thing as "repeated".

Row 12 named one counter where a label addition necessarily moves three:
core requirements, suite requirements, suite labels. Execution found the
other two through four failing tests in that file.

The new writer comment was false, and this is the finding to carry because
it is a false rationale attached to correct behaviour. It said
self.manifest.canonical_base is always None at the commit-side check, but
test 9 deliberately performs an unrelated second commit on an inherited Some
base. What actually holds is narrower: an inherited base can be present but
never stale, because open refuses a stale one and create refuses a
base-bearing manifest. So narrowing pin 3a to "any stale inherited base" is
unobservable while broadening it to "any base-bearing commit" is very
observable and wrong. The scope is forced on one axis and a real choice on
the other, and the comment collapsed the two. Corrected in the staged code.
The contract itself never made the claim -- section 7 item 10 says "stale
inherited base", which is exactly right.

Review confirmed M7 internally coherent against the final tree: B_raw
requiring one normalisation step matches the probe history, and the
mismatched-base control reaches the staged writer check and produces the
required error. No additional M7 contradiction found.

The staged implementation is NOT accepted. This amendment needs another
independent pass first. The implementation remains staged and uncommitted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-09 11:57:04 +02:00
Levi Neuwirth 6b17023a51
P13-S27 RATIFIED after nineteen review rounds; pins frozen, dispatched
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
2026-08-08 22:18:46 +02:00
Levi Neuwirth 1316300196
P13-S27 rounds 17-19: the §3/§5 sweep, its two defects, and the first clean round
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
2026-08-08 21:52:08 +02:00
Levi Neuwirth fa5716ef49
P13-S27 round 16: four mutations still took a broken assertion as evidence
Independent review against a230c6f. Four findings, all blocking. Round 15
stated a rule covering every mutation and applied it only to M6.

M1 accepted test 2 failing, which an unrelated open error satisfies after
pin 5's comparison is removed. It now requires the stale, self-consistent
base to be observed opening successfully under the mismatching capability.

M2 accepted test 3 failing, which any non-malformed result satisfies without
showing corruption was reclassified as staleness. It now requires the
corrupt fixture to be observed returning CanonicalBaseRequiresRebuild with
both fields reported.

M3 accepted test 4 failing, which an error on either no-base open satisfies.
It now requires the base-free fixture to be observed rejected by the wrongly
widened check. Because a base-free bundle has no base version, the base
field is named explicitly as the superblock's no-base default,
ReductionAlgorithmVersion(0) from reduction_version_for, and that synthetic
source is prohibited from entering shipped no-base validation -- without
that prohibition M3 could be read as licensing a defaulted base comparison
in real validation, which would contradict pin 5.

M5a accepted test 10a failing, which a serialization failure satisfies
without the authority ever being read. It now requires the returned bundle's
stored capability to be observed equal to the deliberately changed
authority.

M4 and M5b survive the correction: M4's changed behaviour is compilation,
and M5b already required its specific error with both fields.

Round 15's claim that the scan was complete is marked FALSIFIED IN ROUND 16
at its original location, so a reader going in order meets the correction
where the claim was rather than several paragraphs later. That is round 14's
lesson applied to round 15's text.

Recorded against interest: round 15 reported that M1 through M5b survived
its scan, and I entered that in the contract and the ledger without checking
a single one. Believing a negative result without asking what it would miss
is the failure CLAUDE.md names, and it took a further round to undo.

Verified before commit: all four findings re-derived against the tree; the
history table's columns sum independently to 53 and 40; section 7 item 4a's
rows were swept in the same amendment rather than left behind, the first
time in sixteen rounds that happened unprompted; no unqualified
scan-complete claim survives anywhere; diff --check clean; no crate changes.

Still NOT RATIFIED, NOT DISPATCHABLE, pins open, no execution authorised.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-08 17:54:54 +02:00
Levi Neuwirth a230c6fe38
P13-S27 round 15: a mutation owes the behaviour it changed, not the assertion it broke
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
2026-08-08 17:17:14 +02:00
Levi Neuwirth fa483cfbc9
P13-S27 round 14: the permissive sentence read earlier than the restrictive one
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
2026-08-08 17:03:01 +02:00
Levi Neuwirth f579172143
P13-S27 round 13: M7 could have passed by deleting the check it observes
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
2026-08-08 16:41:05 +02:00
Levi Neuwirth bff9c9aab8
P13-S27 round 12: two requirements that named a constraint but not its value
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
2026-08-08 16:27:54 +02:00
Levi Neuwirth 74dc994bf2
P13-S27 round 11: M7 gets a normalized reference and a narrower claim
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
2026-08-08 14:57:18 +02:00
Levi Neuwirth 39f261774a
P13-S27 probe result: the round trip needs a fixed point, and round 10 had none
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
2026-08-08 13:33:49 +02:00
Levi Neuwirth 5aed861e31
P13-S27: grant one narrow, explicit exception to "no execution work"
Authorises a bounded mechanical probe of M7's experiment on a disposable
branch, for evidence only, before review round 11. Granted before use
because the prohibition is otherwise absolute.

Scope is the part of M7 runnable against the tree as it stands: whether a
base-free Bundle -> text -> Bundle round trip reproduces the original
image() bytes. That is M7's load-bearing assumption after round 10 and the
thing four paper designs never established. Result and complete diff
recorded, branch discarded, nothing merged.

Explicitly not authorised: any S27 implementation (no BundleCapabilities,
no capabilities(), no pin 3a validation, no CanonicalBaseRequiresRebuild,
none of tests 1 through 10b); any staging or commit on main beyond this
contract's own rows; any pin, test, gate, mutation or touch-table change
arising from the probe without its own review round. The probe produces
evidence, not amendments.

Recorded as evidence in its own right: M7 as written cannot be executed
until S27 has landed. BundleCapabilities and
CURRENT_REDUCTION_ALGORITHM_VERSION do not exist in the tree -- they are
S27's own deliverables -- and M7 step 1 requires a base committed under the
real authority. M7 is a mutation of this rung's implementation, and
mutations run after the rung, not before it. The probe therefore tests the
round-trip machinery M7 depends on, not M7.

The probe is base-free, so it removes no refusals: both
project_text_document and serialize_document gate on
canonical_base.is_some(). It touches none of pin 3b's guards, cannot leave
one unrestored, and leaves the live no-canonical-base constraint intact.

Still NOT RATIFIED, NOT DISPATCHABLE. Pins unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-08 13:06:48 +02:00
Levi Neuwirth 0202eecf57
P13-S27 round 10: derive the alignment instead of enumerating it
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
2026-08-08 12:56:57 +02:00
Levi Neuwirth 0efd543b97
P13-S27 round 9: M7's comparator had the wrong artifact and the wrong method
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
2026-08-08 12:31:05 +02:00