From 103f885afa2cd66e47b91f87b426fe1c66731374 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 16 Sep 2026 14:03:34 +0200 Subject: [PATCH] Record Cut 6b's landing and Soul pass, and fold in the Cut 6c spec Cut 6b landed in three commits and Soul's whole-key probe found no collision across 212,450 adversarial keys. Three checks were unpinned (the underscore half of the escape, the composer's root check, the 64-byte boundary) and are in a fix batch with Soul's own surviving mutants as their killers. Two map claims were wrong and are corrected: nesting depth follows from the subject's local rather than being five, and a validated date passes raw because it is already a label. The Cut 6c spec is folded in as reissued against the landed grammar, with the supersession fixture only the new grammar makes nameable and the mutation entries pointed at the shared harness the fix batch is factoring out. Co-Authored-By: Claude Fable 5.1 --- notes/eureka-pipeline-state-cut.md | 356 +++++++++++++++++++++++++++-- 1 file changed, 337 insertions(+), 19 deletions(-) diff --git a/notes/eureka-pipeline-state-cut.md b/notes/eureka-pipeline-state-cut.md index 7d6b3f08..eb29dc21 100644 --- a/notes/eureka-pipeline-state-cut.md +++ b/notes/eureka-pipeline-state-cut.md @@ -34,9 +34,13 @@ pause saying exactly why it stopped there. `b6f6e802`, `80db5db6`, `3ee78e05`, second fix batch at `9b68d83c`, `4cccb45c`, `4a654351`. `epiphany-pipeline` is a leaf library Huginn can depend on without `epiphany-core`. -- **Cut 6b in Hands** against `4a654351`. The second fix batch's Soul pass found - the same invariant open one level up for the third time, so the key grammar - is redesigned rather than patched a fourth time. +- **Cut 6b landed** at `602ffd9f` (deletes), `1bddd2ac` (grammar), `95ee551a` + (mutation suite); fix batch in Hands. The second fix batch's Soul pass had + found the same invariant open one level up for the third time, so the key + grammar was redesigned rather than patched a fourth time. Soul's first pass + on the grammar found no collision in 212,450 adversarial keys and four + unpinned checks. +- **Cut 6c specified** against `95ee551a`; waits on the 6b fix batch. - **Target rewritten** at `5fb4eb22`. **Cut 6c is the last cut inside Epiphany.** Cuts 7-16 build Huginn's Rust @@ -448,6 +452,69 @@ in this repo and in Ghostlight: Cut 6b's suite is the first with a control (M0) and the rule is now in the Eureka skill. +**Cut 6b landed** at `602ffd9f` (the three key-shape exceptions deleted; +does not build, by design), `1bddd2ac` (one grammar for every kind; 20 tests, +0 warnings) and `95ee551a` (`tools/eureka-cut6b-mutations.ps1`, the first +suite with a no-op control). Source outside tests 774 → 726, tests 734 → 881, +no schema, dependency, kind, field or epoch moved. Hands' spec discrepancies, +all kept: `local` takes `&[&str]` rather than a fixed array because the +Resolution and Finding arms carry a parent's parts; the whole-local bound +refuses `InvalidFormat` to match the reader; `key_segment` is a pure escape +and each caller validates its own field first; two "unchanged" tests carried +literal keys that moved; and `{CAMPAIGN}:resolution:R8` is now asserted +*accepted* with the Q11 rationale in its doc comment, so a future runtime +guard is visible. + +**Soul's first pass on the grammar** (Fable, script +`soul-cut6b-mutations.ps1` in the session scratchpad, M0 green twice) built a +whole-key injectivity probe: 212,450 distinct keys across all thirteen kinds +with adversarial slugs, repos, labels and dates and resolutions nested to +depth four, **zero collisions**, every key three segments, every key reading +back to its own kind and identity, 157,010 resolution keys recovering exactly +their subject. `self` collides with nothing as a slug, a label or a campaign. +Hands' M1-M6 all killed on rerun; Soul's own S1, S6, S7, S8, S9 killed; S3 +(`splitn(3, ':')`) survived as an equivalent mutant because `label_text` +refuses a colon in the third segment anyway. Three survived for real: + +- **F2 (medium): the escape's `_`→`__` half is pinned only through an + `OrgRepo`.** A mutant escaping only `.` when the value has no `/` survives, + and hand-offs to `a_db` and to `a.b` then share a key. That is the pass-2 + collision class, one edit from reopening. +- **F3 (medium-low): the composer's root check is pinned for one byte.** Under + `trim_end_matches('.')`, campaign slug `eureka-state.` composes a key the + reader refuses, and the write validator recomputes and compares without + reading back, so a document is admitted under an id no `PipelineRef` can + name. +- **F4 (medium-low): the 64-byte boundary is unpinned on both sides.** + Fixtures sit at 55 and 66+, so a `> 65` mutant survives and the writer + admits a 65-byte local the reader refuses. The code is right; the pin was + missing. + +And four findings that are not code defects: **F1**, the "depth at most five" +claim is false (corrected above); **F5**, a dotted finding label now refuses as +`finding.key` rather than `finding.label`, consistent with every other kind +and accepted as the behaviour; **F6**, the authority map overstated the escape +rule for `Date` (corrected above); **F7**, Hands' "twelve fixed call sites" is +eleven literal slices plus two computed vectors, the Finding one fixed in +practice by `parent_cut` pinning the verdict local to two parts. **F8**, +pre-existing and informational: a cut-report key drops the spec revision +(a standing ruling) and a verdict key drops the report attempt (implied, not +stated). `pipeline_id` accepting `c:campaign:notself` and the like is grammar +versus reachability, admission's job, as the spec says. + +The stale Cut 6 script entries M5 and M12-M15 match zero anchors at HEAD and +the script throws at its line 234 rather than reporting a kill. Loud, as the +rule requires. Target dir: Hands' growth to 9,279 was one debug profile; +Soul left 8,991 because cargo rotated out one of Hands' incremental sessions, +which cannot be recreated and is not a deletion. + +**The fix batch is in Hands:** pin F2, F3 and F4 with Soul's S2, S4 and S5 as +the mutations; state the depth arithmetic in the arm comment and the test; and +factor the mutation harness into one `tools/eureka-mutations.ps1` with a +built-in M0 and per-cut entries files, deleting the stale Cut 6 entries with a +note naming the 6b mutation that now pins each rule. Cuts 5, 6, 6b and 6c +would otherwise carry four copies of the same scaffold. + ## Probes and source reads this pass No cargo build ran this pass. Every new mechanism claim below was settled by a @@ -1174,8 +1241,11 @@ successor because there is nothing left to guess. Roots take the reserved constant `self` as local; a reader recovers a root's identity from segment 1 and never consults it. A resolution is keyed inside its subject's root with the subject's kind and local as its own local. Nesting is -bounded by construction: each level costs eleven bytes of `resolution.` against -the 64-byte local, so depth is at most five, and `pipeline_id` does not recurse. +bounded by construction, not by a guard: a nested local is +`11 * (depth - 1) + len(subject local)` bytes against the 64-byte bound, so a +one-byte subject local nests six deep and `question.Q1` five, and +`pipeline_id` does not recurse. *(Corrected after Soul F1: this first said +"at most five"; the bound is the local, and the depth follows from the subject.)* **The one escape, generalised.** `repo_segment` (`:619-636`, `_`→`__`, `/`→`_-`, `.`→`_d`, injectivity verified by Soul) becomes `key_segment` and @@ -1258,8 +1328,10 @@ stays. - **Derived state:** the key is derived, never stored. `pipeline_id` is the key read backwards and holds no state. `declared_kind`'s inference is deleted. - **Forbidden writers:** no arm of `pipeline_key` may `return` a key; no local - part may be a raw `Slug`, `Short`, `OrgRepo` or `Date`; nothing may infer a - kind from an id's shape; reachability ("does this document exist", "may this + part may be a raw `Slug`, `Short` or `OrgRepo` (a validated `Date` is + `[0-9-]{10}`, already a label, and passes raw; Soul F6 corrected the first + wording, which claimed every non-label value was escaped); nothing may infer + a kind from an id's shape; reachability ("does this document exist", "may this kind be resolved") stays with admission in `huginn-mind` per the resolution matrix above. Cross-field rules stay out of `Bounded`. - **Shared paths:** `pipeline_key`, `pipeline_id`, `PipelineRef::validate` @@ -1340,16 +1412,261 @@ stored-document re-key. ## Cut 6c. The Ghostlight shapes -Specified 2026-09-16 (zero new kinds: two unit enums, one new value type, one -deleted, five fields, three retypings; six of thirteen schemas regenerate; no -kind widens, so the epoch holds; about −17 source, +115 including 75 test -lines). Rulings taken: Soul measures every promise and `Unproven` carries the -ones it could not reach; `Fixed { commit: Sha }` is admitted with its referent -outside the document set; multi-supersession closes as `Vec[8]`, -cardinality being an admission rule and not a shape, with Q10 asked against -Cut 8. **The full spec is reissued by Imagination after Cut 6b lands** and is -folded in here then; until it is, the operative text is -`scratchpad/cut-6b-spec.md` under that earlier name. +- **Repo/branch:** Epiphany `codex/eureka-pipeline-state`. Depends on Cut 6b + (landed at `1bddd2ac`, mutation suite at `95ee551a`) and its fix batch. + Blocks Cut 8. Lands before Cut 8 (ruling C) and is the last cut inside + Epiphany before the pause. +- **Anchors.** Every `file:line` below is against `epiphany-pipeline/src/lib.rs` + at `95ee551a`, 1,608 lines, twenty tests, re-found by content after the key + grammar shifted everything from the old `:526` down. The 6b fix batch lands + on `lib.rs` before Hands starts, so **re-anchor by content again**: every + anchor is a `struct`, `impl`, `fn` or sample opener that greps cleanly. +- **Reissued** 2026-09-16 by Imagination against the landed grammar. Three + edits from the first issue: anchors re-found; the Keeps claim about keys + rewritten; one fixture added that only the new grammar makes available, a + `Superseded` entry naming a resolution by the key it has. Deletes, adds, + `Promise`, the two unit enums, `StructuralDelta`, M17/M19/M20/M21, the + authority map and the subtraction estimate carry over; M16 and M18 keep + their rule and gain sharper forgeries; M22 is new. + +**Why this cut exists, and why now.** Ghostlight's independently run campaign +(D9) named six pains. Four were already built: finding identity, the ledger +derivation, cut status and the direction of the supersession relation are +covered by keys, joins and `PipelineResolution` as they stand. What is left is +one genuine hole (promises), two fields wearing one shape (ruling authority, +finding origin), and four retypings that are breaking, not additive. Under +ruling 8 a retyping costs an epoch bump the moment a pinned reader exists. +Nothing reads these schemas today: a grep for `SubtractionEstimate`, +`MutationRecord`, `ResolutionOutcome`, `VerdictClaim`, `StructuralDelta` and +`subtraction_estimate` over Epiphany finds `lib.rs`, the four schema files +that embed them, and one prose mention in this map; over `F:\Projects\Huginn` +and the Eureka skill checkout it finds nothing (source read). A whole-drive +search timed out, so any other tree is unchecked. Cut 8 pins a git rev and +closes the window. **The four retypings cost nothing today and an epoch +tomorrow.** + +**Rulings carried in:** A, Soul measures every promise and `Unproven` carries +the ones it could not reach; B, `Fixed { commit: Sha }` is admitted with its +referent outside the document set; C, this lands before Cut 8. +Multi-supersession is `Vec[8]`, cardinality being admission's +(Q10 asked against Cut 8). Q11 A: nesting stays. Q12: `OrgRepo` untouched; the +tightening is its own commit and is not folded in. No kind widens, so +`epiphany.pipeline.epoch.v1` holds. **Zero new kinds.** + +### Deletes first + +| Path | Lines | What dies | +|---|---:|---| +| `lib.rs:290-294` | 5 | `SubtractionEstimate` and the two-line comment on its list default. Its consumer becomes `StructuralDelta`. | +| `lib.rs:388-396` | 9 | `impl Bounded for ResolutionOutcome`. Replaced whole, not patched: every arm changes referent type, and a patched impl is how a length-only check survives. | +| `lib.rs:826-828` | 3 | The cut-spec sample's `SubtractionEstimate { … }` literal. | +| `lib.rs:296` | 1 | `MutationRecord`'s `mutation: Line` field, rewritten in place as `location`/`before`/`after`. | + +The comment at `:298-299` names the dead type and is reworded to stand alone. +No file or schema file dies; `index.json` is untouched because no kind is +added and no type id renamed. Deletes go before any field is added: if +`SubtractionEstimate` and `estimate: StructuralDelta` coexist at any commit, +the cut has two estimate shapes. + +### Keeps + +- **All thirteen kinds, `pipeline_key`, `pipeline_id`, `local`, `key_segment` + and the epoch.** Keys moved in Cut 6b and are settled; this cut moves none + further, because it adds, retypes or removes no field a key is derived from. + The check is mechanical: `git diff --stat -- schemas/cultnet/` at the + end names exactly the six regenerated schema files. `index.json` carries no + hashes (its entries are id, kind, wire contracts, version, type, title and + path, and the derivation test asserts that shape), so it is byte-identical. +- **`PipelineRef` and its `Bounded` impl (`:363-376`).** It becomes + load-bearing for four more referents. It already parses the id against its + declared kind through `pipeline_id`, whose kind-segment check (`:553-555`) + refuses a mismatch; that is why retyping 1 is cheap and what the new fixture + rides on. +- **The whole key suite**, `keys_read_back_as_ids_of_their_kind` included. All + twenty tests stay unchanged in name and assertion. They are blind to this + cut, which is why it carries its own tests. +- **`Short`** stays the type for full-id fields already parsed at key + derivation (`cut_report.cut_spec`, `verdict.cut_report`, `finding.verdict`, + `cut_spec.rulings`, `ruling.answers`). Retyping those is a larger cut. +- **The outcome-invariance assertion** in `keys_are_derived_and_mismatch_refuses` + (`:1029-1037`): a subject has one resolution key whatever the outcome. + +### Adds + +Two `unit_enums!` entries and one `value_types!` entry. No kind, module, +dependency or target. + +``` +RulingAuthority { Operator, Standing, Defaulted } +FindingOrigin { Introduced, PreExisting } +pub struct Promise { label: Label, text: Line } +``` + +`Promise` is not a document and has no key; it is identified by its report's +id plus its label, as `TargetInvariant` is by its target's (`:276`). It is not +resolvable and does not enter the resolution matrix. + +### Per-file changes, `epiphany-pipeline/src/lib.rs` + +| Line | Change | +|---|---| +| `:262-267` | Add `RulingAuthority` and `FindingOrigin` to the `unit_enums!` block. | +| `:290-294` | Delete `SubtractionEstimate` and its comment. | +| `:296` | `pub struct MutationRecord { label: Label, rule: Line, location: CodeLocation, before: Line, after: Line, commit: Sha, failed_as_expected: bool }` | +| `:298-299` | Reword the comment so it no longer names `SubtractionEstimate`. | +| after `:307` | `pub struct Promise { label: Label, text: Line }` beside `LandedName`. | +| `:308` | `VerdictClaim` gains `promise: Option