Commit Graph

207 Commits

Author SHA1 Message Date
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
Levi Neuwirth 01e76d1022
P13-S27 round 8: M7 was unrunnable and had been since round 1
Independent review against 9829ae3. Two findings, both blocking, and the
first round to reach into a mutation's mechanics rather than its
bookkeeping.

M7 did not describe a runnable observation. It told execution to construct
a base-bearing TextDocument, which bypasses parse_document entirely -- so
the parser refusal it ordered removed was irrelevant, and the demonstration
was not the import laundering it is named for. project_text_document has
the signature &TextDocument -> Result<String, _>: it is the export
direction and is not on the import path at all, so "all three sides, since
removing one leaves the others refusing and the document never reaches the
writer" was false for it. And "byte-indistinguishable from one whose base
was genuinely validated" named no comparison artifact and no comparison
method.

M7 now requires text that is parsed, not a constructed document; removes
and restores only the parser and serializer refusals; names test 10b's
construction as the comparison artifact, built with the same FileUuid and
base bytes; and requires a field-by-field enumeration of the canonical_base
SnapshotRef, the superblock's reduction version, and the header's major and
epoch -- reported rather than concluded. It is informative in both
directions: a field that does differ is a provenance signal nobody knew
existed, and that is a finding rather than something to suppress.

The round-7 deduplication was incomplete. The status block still carried
"rounds 3 and 4 are closed" while declaring the history table the sole
authority for that. Deleted.

Finding 1 is the most substantive of any round so far, because every
earlier one was about text agreeing with other text. This is about whether
the experiment runs at all, and it did not. M7 has been in the contract
since round 1 and survived seven reviews, three of which specifically
re-derived mutations, because reading it never required tracing what calls
what. An observation stated in the right register can look complete for a
long time. "Indistinguishable" was a conclusion, not an observation --
which is the exact failure mode this rung exists to eliminate, sitting
inside its own demonstration.

While amending I caught a third instance unaided: section 7 item 4a's M7
row still said "all three refusals". Fixed by pointing at M7 rather than
restating, per round 7's rule.

Still NOT RATIFIED, NOT DISPATCHABLE. Findings 9, 6, 6, 5, 4, 3, 3, 2.
Blocking 4, 4, 4, 4, 2, 3, 3, 2. Eight rounds, none clean. The M7 rewrite
is now the least-reviewed material in the contract, and its predecessor
survived seven rounds while being unrunnable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-08 10:49:10 +02:00
Levi Neuwirth 9829ae38df
P13-S27 round 7: the defect is duplication, so the fix is deletion
Independent review against c0d896c. Three findings, all blocking, and all
three the same defect -- a claim living in two places and fixed in one.

Section 7 item 4a was unsatisfiable. It required every mutation to name the
test it breaks, while item 1 four paragraphs above states that M4 is
observed to compile -- no test is possible, which is precisely why pin 3's
prohibition is a review rule -- and that M7's expected outcome is success.
A report obeying 4a literally could not be written, and the honest response
would have been to invent a test for one of them. 4a is now a table of what
each of the eight mutations owes, with M4 and M7 carved out.

Round 6's three-literal correction reached section 7 and not section 3.
Section 3 still said "both literals ... tidying either", so the contract
carried the fixed and the broken version of the same claim, reopening the
narrow-scope ambiguity round 6 existed to close. Section 3 no longer states
the count; it points at item 4b.

"Rounds 3, 4 and 5 were independent" went stale the instant round 6 closed,
sitting in prose beside the table whose own column records it. Deleted.

Three rounds, one lesson. Round 5 fixed the review totals and not the
amendment tally beside them. Round 6 fixed item 4b and not section 3's copy
of the same rule. Round 7 found the classification sentence duplicating the
table's column. The defect is duplication, and every previous remedy was
vigilance -- check the other sites too -- which has now failed three rounds
running.

The remedy adopted here is deletion, not diligence. Where a claim had two
homes, one is removed and replaced with a pointer: section 3 no longer
counts the literals, the history block no longer classifies the rounds, and
the status line no longer lists which rounds have closed. A copy that
cannot drift is one that does not exist.

Still NOT RATIFIED, NOT DISPATCHABLE. Findings by round 9, 6, 6, 5, 4, 3, 3
-- flattened rather than still falling. Blocking 4, 4, 4, 4, 2, 3, 3, with
rounds 6 and 7 both 100% blocking and 100% in the previous round's text.
Seven rounds, none clean. The deduplication is the first structural remedy
for this defect and therefore the first with a reason to work, and it is
untested.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-08 10:42:16 +02:00
Levi Neuwirth c0d896c64d
P13-S27 round 6: three findings, all blocking, all in round 5's text
Independent review against 03c85dd. The first round where every finding
was blocking and every one was in the previous round's amendments.

The amendment tally went stale inside the block round 5 restructured to
prevent exactly that. Round 5 turned the review totals into a table and
left "amended five times ... rounds 1-4" as prose immediately above it.
There is no longer a separate amendment count: it is the number of rows.

Section 3's test-home correction was itself false. Round 5 wrote "tests 1-9
in epiphany-bundle", but test 7 is assert_reduction_serialization_stable,
which the same section names as testkit/src/roundtrip.rs. Two wrong
versions of that sentence, both written while fixing it. Replaced with a
per-crate table: 1-6/8/9 in bundle, 7 and 10b in testkit, 10a in textproj.

Section 7 item 4b protected one operand where test 10b has two. Replacing
both synthetic_for_fixture(0) and the committed base's
ReductionAlgorithmVersion(0) with the constant keeps the synthetic call
exactly where it is and fully restores the tautology -- and test 10b's Err
arm never executes in the unmutated run, so its literal cannot detect it.
Item 4b now enumerates all three fixture operands individually and requires
each quoted verbatim.

All three are one defect in different clothes: a fix applied to the site
named rather than to every site the claim covers. Sixth count-staleness
defect in six rounds; third range-correction that did not check its own
range.

The mechanism that works is structural, not vigilant. The review totals
stopped going stale when they became a table. The amendment count did not,
because it stayed prose. Item 4b stopped being under-specified when it
became a table.

Demonstrated a seventh time inside this amendment: the new table's Total
row was first written "6 amendments", a free-standing count three
paragraphs after the sentence declaring no such count exists, and already
wrong at seven rows. Caught before commit and replaced with "one amendment
per row". Prose invites a number and a table does not, so the defence has
to be the shape of the artifact rather than the attention of the editor.

Still NOT RATIFIED, NOT DISPATCHABLE. Findings by round 9, 6, 6, 5, 4, 3 --
falling monotonically. Blocking 4, 4, 4, 4, 2, 3 -- not falling. No round
has yet come back clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-08 10:25:26 +02:00
Levi Neuwirth 03c85ddb2c
P13-S27 round 5: the tally went stale in the block edited every round
Independent review against df9e528. Four findings, two blocking -- the
first round in which blocking findings fell below four.

The status history still said "amended three times ... fifteen findings so
far, eight of them blocking". Those are the round-2 figures, left standing
through rounds 3 and 4 while the tables recording those very rounds sat
directly below them. Fifth count-staleness defect in five rounds, and it
was in the one block I edited every round. Replaced with a table so a round
appends a row instead of requiring a number to be found and re-derived.
Running tally is now 30 findings, 18 blocking.

Test 10b could not make the two-field assertion M5b requires. Section 3
said only "assert it opens", and under mutation that yields a bare Err or a
panic. A #[test] returning Result that returns Err asserts nothing about
that error's fields, so M5b's required observation of
CanonicalBaseRequiresRebuild { base, current } had no home in the test M5b
names. Both Result arms are now pinned, plus a third arm for the
wrong-error case -- without it an implementation returning a different
error under mutation still fails the test and the report reads as success
while observing nothing.

M5b's claim that the literals cannot be tidied without deleting the
synthetic capability was false. Keeping synthetic_for_fixture while passing
CURRENT_REDUCTION_ALGORITHM_VERSION as both its argument and the base
version preserves the fixture and fully restores the tautology. Retracted.
The protection is section 7 item 4b, the positive check that the literals
are still literals. Round 4 asserted a structural guarantee that did not
hold and thereby undercut the procedural check actually doing the work,
which is the same error as reasoning that a mutation would fail instead of
running it.

Section 3's preamble still said the tests were in epiphany-bundle after
round 4 added two that cannot be -- epiphany-bundle must not depend on
epiphany-ops, and reaching the real authority is the whole purpose of 10a
and 10b. Corrected, with each test's touch-table home named.

Still NOT RATIFIED, NOT DISPATCHABLE. Blocking findings by round are 4, 4,
4, 4, 2 -- the first movement in four rounds and the first weak evidence of
convergence, against the fact that every round since the third has found
blocking defects in text written to fix its predecessor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-08 01:50:38 +02:00
Levi Neuwirth df9e528e99
P13-S27 round 4: the M5 pair was defective a third time
Independent review against 53292f6. Five findings, four blocking. Round 4
accepted pin 3's capabilities() accessor as bounded -- the first new text
any round has passed -- and rejected both halves of M5 again.

M5b cited the wrong value, and this one is mine. roundtrip.rs:367 sits in
assert_score_serialization_stable, not assert_reduction_serialization_stable,
and it versions an acceleration snapshot, not a canonical base. The latter
has no base at all, because pin 3c suspended it. So the value round 3 told
the implementer not to touch was irrelevant to the authority check, and
mutating it could not have failed anything. Round 3 grepped
ReductionAlgorithmVersion across testkit/src/, saw a roundtrip.rs hit, and
attributed it to the function it was already thinking about without
resolving the enclosing item -- the same shape as section 0.4's .commit(
miscount, which round 1 had already recorded as a lesson. Recording a
defect is not the same as not committing it. The tautology diagnosis
stands; only its evidence was wrong.

M5b left the instrument unchosen. Round 3 said "the rung picks one" and
named two routes, one of which does not exist for the nominated crate:
craft_image_with_base is a private fn inside epiphany-bundle's cfg(test)
module. Now chosen, through public API only: build with
synthetic_for_fixture(0), commit a base carrying the literal 0, take the
bytes, reopen under the real constant. The operands are provably
independent and neither can be tidied into the other.

M5b had no test that could assert the error fields.
assert_reduction_serialization_stable returns () and reopens with .expect,
so a mismatch panics instead of yielding a matchable
CanonicalBaseRequiresRebuild { base, current }. Test 10b added, named and
returning a matchable Result.

M5a violated section 7 item 4a -- the rule round 3 added in the same edit.
It named no test, and its natural assertion compares
CURRENT_REDUCTION_ALGORITHM_VERSION with itself, which holds for every
value. Test 10a added, asserting against a deliberate literal. Round 3
diagnosed M5b's tautology and wrote the identical tautology into M5a in the
same edit, then added a rule and immediately broke it.

Both literals are load-bearing as literals. Section 7 item 4b now requires
confirming neither was rewritten as the constant -- tidying either makes
its mutation vacuous while every test stays green.

Minor: status prose said the pins were open to round 3's findings after
round 3 closed.

Still NOT RATIFIED, NOT DISPATCHABLE. Defect rate 9, 6, 6, 5 -- not
converging, and every blocking finding in rounds 3 and 4 was in text
written to fix the previous round.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-07 23:41:15 +02:00
Levi Neuwirth 53292f6ddb
P13-S27 round 3: three mutations were unrunnable in three different ways
Independent review against b842975. Six findings, four blocking. Every
blocking finding was a defect in text rounds 1 and 2 wrote.

Pin 3a still carried the rationale round 2 retracted. Section 0.4 says
there is no in-tree production base writer; pin 3a still said "0.4 shows
production code minting a stale document". The contract asserted a claim
and its negation. Rewritten onto the footing that survives: commit and
commit_versioned are public API and guard out-of-tree callers, not an
in-tree path. This is the third occurrence of fix-one-site-leave-the-
others -- round 1 fixed one spelling of a count, round 2 fixed section 0.4
and left the Rung type paragraph and touch row 2.

M5a had no observation mechanism. Pin 3 required the capability be stored
and nothing exposed it; Bundle has 17 public accessors and none for
capabilities, so no textproj test could inspect it. Bundle::capabilities()
is now pinned. That is new scope and is flagged as such for round 4.

M5b could not fail. If the supplied capability and the base version both
derive from CURRENT_REDUCTION_ALGORITHM_VERSION -- the natural
implementation, since roundtrip.rs:367 hardcodes ReductionAlgorithmVersion(0)
today -- both operands move together and the comparison passes for every
value of the constant. That is section 0.1's own tautology reproduced
inside the mutation built to detect it. The base version must now come from
a source that does not track the authority, and both operands' provenance
must be reported.

M6's replacement named a scenario with no test. Test 6 stops at opening, so
nothing asserted that an unrelated commit succeeds; an implementation
rejecting every post-base commit passed tests 2/5/6/8 and the broadening
had nothing to break. Test 9 added.

Cleanup: touch row 7 listed generators.rs as "call sites, real authority"
though it has zero Bundle::open/create calls, and its rng.range(0, 8)
versions are exactly the arbitrary wire values pin 3b assigns to synthetic
capabilities -- split to row 7a. Section 7's call-site attribution credited
round 1 where rounds 1 and 2 are both load-bearing.

The pattern is legible now and it is not about counts. Round 1 found stale
text, round 2 found unexecutable mutations, round 3 found that three
separate mutations were unrunnable in three different ways: M5a could not
observe, M5b could not fail, M6 had nothing to break. A mutation is only as
good as the test it breaks. Section 7 item 4a now requires, for every
mutation, the named test it breaks and the provenance of each operand.

Still NOT RATIFIED, NOT DISPATCHABLE, pins not frozen. Defect rate across
three rounds is 9, 6, 6 -- not converging. The newest text has had zero
adversarial passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-07 23:31:00 +02:00
Levi Neuwirth b741e487e8
P13-S27: ratification withdrawn, held for independent round 3
Round 1 claimed ratification after a single round. Round 2 then found four
more blocking defects against the supposedly frozen text, two of them
introduced by round 1's own amendments. A ratification a later round
falsifies that quickly was not one, and leaving the claim standing would
make the status field mean nothing.

Status is now NOT RATIFIED, NOT DISPATCHABLE, pins NOT frozen, awaiting an
independent review round 3 against b842975. Freezing follows ratification;
it does not precede it and does not survive a withdrawal. No execution work
may begin -- not implementation, not staging, not partial work against "the
settled pins."

Also disambiguated the two senses of dispatchable that round 1 conflated.
Unblocked means the dependency chain cleared, true since bc06706.
Dispatchable means ratified and frozen and ready to execute, false. Reading
the first as the second is how this came to be ratified after one round.

Both prior rounds were run by the same agent that authored the amendments
under review. Round 3 is the first that will not be.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-07 23:20:41 +02:00
Levi Neuwirth b842975919
P13-S27 review round 2: six findings, four blocking, two self-inflicted
Round 1 ratified after a single round. Round 2, run against the frozen
contract, found four more blocking defects -- two of which round 1 created.
Ratification was premature and the status now says so.

Blocking:

The call-site correction was applied to section 0.4's table only. The "Rung
type" paragraph still said 57, and touch row 2 still said bundle.rs has 35
opens -- a figure that was never bundle.rs alone (it was bundle.rs plus
fuzz.rs, which has its own row) and is stale besides. bundle.rs has 23. The
reconciliation section 7 requires was impossible against those numbers.
Fixing one spelling of a count and leaving two others is the same defect
round 1 reported as finding 5.

Section 0.4 called project.rs:936 a production bundle writer. cfg(test)
starts at project.rs:630 and every Bundle call in the file is below it --
create at :983 and :1122, open at :1147. The writer-path correction stands
on serialize.rs alone, whose create and commit_versioned are above its own
cfg(test) at :284. Round 1 verified the editor-core claim in that paragraph
and inherited its neighbours.

M5 was unexecutable. serialize_document refuses base-bearing documents at
serialize.rs:151, before Bundle::create, so its output is necessarily
base-free; pin 5 and test 4 require base-free bundles to open at any
authority. Changing the constant cannot make a textproj production test
fail. Split into M5a (production wires the constant) and M5b (the authority
is load-bearing where a base exists, via testkit's restored base coverage).

M6's second half was unexecutable. open rejects a stale base, create
rejects a base-bearing manifest at bundle.rs:234, and commit validates what
it emits, so no caller can hold an open Bundle with a stale inherited base.
Replaced by broadening pin 3a rather than narrowing it, which is reachable.
The unreachability is itself reported: pin 3a's scope is forced, not
chosen, which is stronger than what the mutation was written to obtain.

Non-blocking: pin 3a's justification, that production code mints a
self-consistent stale document without calling open, is false in-tree --
zero production paths stage a base, since the format rung's pin 3b closed
the only one. It now rests on guarding the public commit_versioned API
against out-of-tree callers. And serialize.rs:157 is dead code orphaned by
the :151 guard, recorded as a finding and explicitly not repaired here.

Two of these were introduced by round 1: ruling M7's refusal permanent is
what made M5 unexecutable, and test 8 was added on the write side without
re-deriving M6 against the same reachability. An amendment is a change to
the system, not a patch to a line.

Round 3 is warranted before dispatch. The defect rate has not fallen -- 9,
then 6 -- and dispatchable is a claim requiring evidence of convergence,
not a status reached by running out of findings.

Documentation only; no code reads .md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-07 23:10:33 +02:00
Levi Neuwirth 39287f8f43
P13-S27 ratified: review round 1, nine findings, four blocking
The contract had reached "dispatchable" with zero ratification rounds on
record, against the standing rule that contracts go through adversarial
review before dispatch. The format-epoch rung had four, and its fourth is
what produced pin 3c. This is S27's first.

Blocking:

Inherited obligation 2 -- M8's laundering demonstration -- was in neither
the test section nor the mutation plan, while that section's preamble
claimed all three inherited obligations were "stated as tests so they
cannot be discharged by prose". It was also ambiguous between temporarily
lifting the text refusal and permanently restoring the capability, which
differ by four touch rows and a COMPANION_VERSION bump. Ruled a mutation:
the refusal is permanent, and the demonstration is now M7, with its
expected outcome recorded as success rather than failure.

Section 0.4 claimed "commit has 57 sites (including 2 in
epiphany-editor-core)". That crate depends on core, ops and layout-ir --
not bundle -- and the word Bundle appears in its lib.rs zero times. The two
hits are self.commit(...) resolving to its own method. A textual .commit(
grep counted a same-named method in a crate that cannot reach Bundle. That
is the third instrument failure recorded in that one section, and it was
committed in the same paragraph as the method note warning about the
second.

Three independent stale list-counts: the test section's header said "names
all four" over seven items, gate 1 said "four tests added", and three
report items named five mutations, seven gate results and four tests. All
replaced with "every item in section N". The delta was never a simple
addition anyway -- three tests convert or extend existing format-rung
tests, which nets zero.

testkit/tests/requirement_labels.rs was absent from the touch table while
pin 9 may move CORE_REQUIREMENT_COUNT from 213. Pin 9 must now decide
explicitly whether it mints a label; touch row 12 carries the file
conditionally. This is the escapee CLAUDE.md names, and it escaped the
format-epoch rung too.

Non-blocking: locator drift since 381c498 (bc06706 grew bundle.rs by 338
lines; correction table added, and pin 5's own :396-:399 confirmed
unmoved); pin 2a's corpus evidence superseded by the 2 -> 0 rebuild;
Bundle::open( 57 -> 60, create confirmed still 32; gate 6a widened to
epiphany-testkit, which touch row 7 gives the real authority; and a missing
commit-side positive test, added as test 8 -- obligation 1 warns that
converting one branch leaves a hole, and that branch had none.

Pins are now frozen. Documentation only; no code reads .md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-07 22:55:26 +02:00
Levi Neuwirth 96b40b2d96
P13-S27 amended pre-dispatch: pin 10's escape clause was unsatisfiable
The status header still read "BLOCKED on the format-epoch rung ... has not
yet landed". That rung landed at bc06706 (fix be244df), and the ledger row
has said UNBLOCKED since. Corrected, recording the prior status rather than
erasing it.

Fixing only the header would have left the contradiction it points at. Pin
10 instructs the ledger writer that P13-S16's row opens only "unless 2a is
ratified and tested within this rung" -- but pin 2a's own prohibition
forbade being amended into a disposition from inside this contract, so the
only route it permitted was resolution from outside, which is what the
format-epoch rung's pin 8 did. The clause's literal condition could never be
satisfied by the one path 2a allowed, and read literally pin 10 would record
S16 as still blocked on a settled disposition.

Amended so ratification is sourced correctly. The "tested" half is
deliberately NOT waived: no other rung exercises this authority, so testing
is discharged by S27's own inherited obligations -- converting both interim
refusals to real capability validation -- and the ledger row may not record
S16 as open until those land with this rung.

Pin 2a's original analysis stays verbatim; its resolution block says so
explicitly. Touch row 11 already carries PASS13_CANDIDATES.md for pin 10, so
the amendment adds no touch row. Documentation only -- no code reads .md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
2026-08-07 22:25:27 +02:00
Levi Neuwirth 49b512b314 CLAUDE.md: the entry point an agent actually reads
The handoff was comprehensive as a document and unreachable as a
bootstrap. An agent starting cold on a new machine reads CLAUDE.md
automatically; it would have to be told to open spec/HANDOFF_2026-08-07.md,
and the rules this work actually ran on lived only in conversation and
in an agent memory directory that git does not carry.

So the method is now a tracked file and the handoff is the state it
assumes. CLAUDE.md carries what an agent must not learn by discovering
it: contracts are frozen after ratification and defects are reported
rather than patched in place; the touch table is the staging allowlist,
with the two files that keep escaping it named; mutation-first, and a
compile error is not a test failure; verify subagent claims by re-running,
because agents here have misattributed failures and guarded the wrong
path; never git add -A, never reset/checkout/stash against a tree another
session may share; never cargo fmt --all, since it crosses into spikes/
through path dependencies; xelatex not pdflatex; the green baseline; and
the live no-canonical-base constraint that makes correct refusals look
like bugs until P13-S27 lands.

The handoff gains §0a pointing at it, and saying plainly what an agent
does not inherit — the memory directory and the conversation — so a thin
inheritance is stated rather than papered over.

The editor/T4 track's half of these rules is recorded as observed from
its contracts; that session should review it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-08-07 13:40:48 -04:00
Levi Neuwirth 263f40d9a3 Handoff §2: the editor track read from its sources, not inferred
The boundary on the editor/T4 files was lifted for this handoff, so §2
stops being a list of leads and becomes an assessment. Read
PLAN_EDITOR_APP.md, CONTRACT_EDITOR_T4_SPIKE.md revision 6, the spike's
DECISIONS.md, and the spike tree.

Where the spike stands: round 0 complete with iced eliminated, round 1
complete with both surviving candidates passing, round 2 built but not
run — apparatus and candidatekit landed, no round2-evidence directory,
no verdict document. Rounds 3, 3b, 4 and 5 not started.

Two machine-specific facts a hardware change puts at risk, neither
recoverable from the documents alone. The spike's harness refuses to
report PASS unless it finds both a discrete and an integrated Vulkan
adapter, and the integrated one's figures are what decide round 4 — so
a different GPU configuration does not just change the numbers, it
breaks comparability with round 1's completed results. And the
accessibility rounds need two settings that are off by default; without
them AT-SPI enumerates zero applications and the result reads as a
candidate limitation when it is an environment absence.

Checked the one place the threads could collide: the spike path-depends
on layout-ir, core, glyphs, determinism and ops, not on epiphany-bundle,
and no editor crate depends on it either. The no-canonical-base interval
cannot reach T4's measurements. The threads collide only when T1b opens,
since it and P13-S27 both land in bundle.rs — recorded in §4.

§4 now sequences both threads, and the two items that had to happen
while this machine still exists are marked done or assigned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-08-07 13:38:10 -04:00
Levi Neuwirth 7909cf09cc Handoff §0: the transfer manifest, and what git will not carry
The first version answered "what is the state of the work" but not
"what actually has to move", which is the question a machine change
asks. Audited it instead of assuming.

Most of the risk turned out to be already retired: spikes/ is tracked
(106 files), the editor-t4 worktree is clean with zero uncommitted and
zero untracked, there are no stashes, and every commit on every local
branch is already on origin. There is no unpushed work on this machine.

What a clone still will not give you, now enumerated: the gitignored
root HANDOFF.md (18KB, not regenerable, deliberately kept out of git),
.claude/settings.local.json, and — outside the repository entirely —
the 21-file agent memory directory both threads have been accumulating
track notes in.

One real exposure found: the branch ref editor-t4-packet2b exists here
and not on origin, which has only refs/heads/main. Its commits are
reachable through the f33673d merge so nothing is lost, but the pointer
is local and should be pushed before this machine is wiped.

§4 is restructured into before-wiping, on-arrival, and then-work, since
two of those steps have to happen while this machine still exists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-08-07 13:33:06 -04:00
Levi Neuwirth ada751cc9f Handoff for the machine move, and two stale ledger openers
spec/HANDOFF_2026-08-07.md: state of the spec / Pass-13 / format-epoch
thread at be244df, the live constraint that no bundle may carry a
canonical base until P13-S27 lands, the S28 -> S27 -> S16 chain with
S27's three inherited obligations, the working agreements that are not
derivable from the code, and the environment notes the other machine
needs (xelatex not pdflatex, the 1.95.0/1.85 toolchain pins, the
cargo fmt --all trap and why its --check form is safe).

Section 2 covers the parallel editor/T4 thread and is explicitly
bounded: those files were out of bounds for this session all along, so
it records only what shared git history shows plus leads to verify, and
says plainly that it is not a substitute for that session's own handoff.
It does name the one place the threads can collide — the canonical-base
interval — which neither side can see from its own side.

Ledger: P13-S27 and P13-S28 both still opened with "open" while their
resolutions sat further down the cell. S27 is UNBLOCKED and
dispatchable; S28 is IMPLEMENTED. The cells are appended to rather than
rewritten, so an opener can lag the truth by several rungs; the handoff
records that as a reading hazard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-08-07 13:20:52 -04:00
Levi Neuwirth be244df6a0 Pin 3b's projection refusal was asymmetric: close the reachable half
document_from_bundle refused a base-bearing bundle, but the public
project_text_document did not. A caller holding a directly constructed
TextDocument could therefore emit a (canonical-base ...) line that
parse_document then rejects — a projector able to produce what the
parser refuses, which is precisely the asymmetry pin 3b exists to close
and which req:textproj:roundtrip's second equation quantifies over.

The guard had been placed on the path the pin happened to name rather
than on every path a caller can reach, and the unguarded one was the
only reachable half: no live Bundle can carry a canonical base during
the S28 -> P13-S27 interval, so the bundle-side refusal cannot fire
today, while the document-side path is one public call away. The new
corpus vector proved the hole existed rather than closing it — it is
built by projecting a base-bearing document.

project_text_document now returns Result and refuses. A crate-private
render_text_document keeps the unchecked formatter for its one
legitimate caller, the canonical_base_present negative vector: a
negative vector still has to contain the spelling it asserts is
refused, and producing those bytes is not the same as permitting them.
Every other vector goes through the checked projector.

projecting_a_base_bearing_text_document_is_refused locks both halves —
that the public projector refuses, and that the private renderer still
emits the section, since the reject vector silently stops carrying its
spelling otherwise. Mutation-verified: removing the refusal fails that
test and nothing else. Restored by hand.

The corpus is byte-identical, so no vector regenerated. Workspace green
at 1570.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-08-07 13:06:40 -04:00
Levi Neuwirth bc06706e41 Container major 1: the format epoch carries base provenance
FORMAT_MAJOR becomes 1 and FORMAT_MINOR restarts at 0. The decoder
stops being exact-major-only: it classifies three ways through a named
FormatEpoch carried on FixedHeader, so major 0 is decoded deliberately
as legacy rather than refused. Old readers already fail closed on an
unknown major, so that half needed no mechanism — which is why the major
is the right carrier, and why the header's immutability, fatal to
FORMAT_MINOR as a provenance field, is what makes it sound as an epoch
field.

The matrix: a major-0 bundle with no base may open; one carrying a base
is refused; one attempting to add a base is refused and told to repack.
That last row is the non-inheritance rule. Three errors, none of which
degrades to read-only: two permanent legacy/repack errors, and
ReductionAuthorityUnavailable, which is temporary, names P13-S27, and
must not say repack — a major-1 container is already the right epoch.

Until P13-S27 lands, both major-1 base boundaries are closed: opening a
major-1 bundle that already carries a base, and committing one into it.
Neither may be left open while the epoch asserts a validation that never
ran.

Text projection cannot mint a base. serialize_document staged a carried
base into a fresh bundle and build_manifest wrote it, so an old or
hand-authored document could be laundered straight through the boundary.
All three sides now refuse: projection, parsing, and a new dedicated
SerializeError variant — none of which existed to be "retained".
COMPANION_VERSION moves to 0.14.0 and the corpus is rebuilt to 20
vectors and ten rejection classes, with canonical_bases reach dropping
2 -> 0. That is a real capability loss and is recorded as one.

Corruption keeps precedence in both epochs: a corrupt major-1 base fails
as malformed, never as the temporary authority error a user would
reasonably retry.

All 11 mutations were run and observed, not reasoned about. M4 is the
signing one — with the legacy commit refusal removed, a legacy container
gains a base in place, which is exactly the counterexample that killed
FORMAT_MINOR. M11 confirms the third error is distinct while test 3
stays green, proving the mutation stayed inside the major-1 branches. M7
fails on both epoch halves. M8 falls through to
SerializeError::Bundle(ReductionAuthorityUnavailable), confirming the
text layer's own refusal is what the test asserts.

Two touch-table gaps surfaced during execution, both the same shape: a
.tex requirement addition moves hardcoded counts in
requirement_labels.rs, and the companion bump moves a second normative
version literal spelled version~0.13.0 rather than (0 13 0). Neither
file was in any touch table; the second was caught only because a test
exists for exactly that failure.

P13-S27 is unblocked — its pin 2a is resolved from outside, as its own
prohibition required — and inherits three obligations: both interim
refusals converted to validation, M8's deferred laundering
demonstration, and pin 3c's two suspended conformance assertions.
P13-S16 remains blocked on S27.

Workspace green at 1569.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-08-07 12:51:14 -04:00