From 72f7591ef3cb61faf954f6a3f9b096f8f0d2779b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:23:13 +0000 Subject: [PATCH 01/19] r2il-mask-abi-probe: the W0B mask-ABI differential (CallMask vs mask-risc) `ogar-r2il`'s `CallMask` carries its own Boolean algebra -- and/or/xor/ and_not/not/count over inline u64 words -- while `lance-graph-mask-risc` is the ONE evaluator above `ndarray::simd`. `lance-graph-quack`'s own manifest states the rule: "the masking algebra is reached THROUGH mask-risc, never beside it." This probe asks only whether the two AGREE bit-identically over the same borrowed words. Result: they do. 6/6 green across all three LaneShapes (Pairs 180 / Triples 120 / Quads 90 calls), seeded fixtures plus every word seam the shape can express (63/64, 127/128, len-1), densities 0/1/7/13/50/93/99/100. `not` gets its own test because it is the only op with a tail obligation on both sides -- CallMask clears per-word against `len`, mask-risc against `n_rows` -- and they agree only if both clear against the same population. CallMask is the ORACLE here and stays it. Nothing is deleted, nothing delegates, no dependency direction is decided: that decision needed the differential green first, and now has it. Ternlog is the direction the agreement matters in: mask-risc's arbitrary-immediate form reproduces all four of CallMask's binary ops, so CallMask's algebra is a SUBSET of mask-risc's rather than a sibling. The immediates are DERIVED from each op's truth table, never hand-written -- the first draft hand-wrote `and` as bits 7|5 where only bit 7 is the conjunction, and the failure read as a substrate disagreement rather than as an arithmetic slip in the fixture. What this does NOT prove, stated in the test's own module docs: it is not a Quack<->R2IL bridge. CallMask indexes call slots inside ONE body (<=180); mask-risc indexes rows of a projection (~64K). Same algebra, different index spaces -- `n_rows` is a CallMask's `len()` precisely so the comparison is apples-to-apples on the narrow side. Deriving a genuine row predicate from a body is W0C. Placement is forced, not chosen: mask-risc path-deps `ndarray` at `../../../ndarray`, a path that leaves its own workspace and can never resolve through a cargo git checkout, so the differential cannot live on the OGAR side (OGAR has no `../../..` path deps and reaches lance-graph-contract by git). The direction used here matches `crates/symbiont`'s existing `../../../OGAR/crates/...` deps. Workspace-EXCLUDED with its own `[workspace]` root, so no ordinary workspace test needs the OGAR sibling present; verify via `cargo test --manifest-path crates/r2il-mask-abi-probe/Cargo.toml`. Kill condition, in the module docs: a disagreement is the FINDING, not a bug to align away. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- Cargo.toml | 7 + crates/r2il-mask-abi-probe/.gitignore | 2 + crates/r2il-mask-abi-probe/Cargo.toml | 25 ++ crates/r2il-mask-abi-probe/src/lib.rs | 5 + .../tests/algebra_differential.rs | 353 ++++++++++++++++++ 5 files changed, 392 insertions(+) create mode 100644 crates/r2il-mask-abi-probe/.gitignore create mode 100644 crates/r2il-mask-abi-probe/Cargo.toml create mode 100644 crates/r2il-mask-abi-probe/src/lib.rs create mode 100644 crates/r2il-mask-abi-probe/tests/algebra_differential.rs diff --git a/Cargo.toml b/Cargo.toml index 70b6525c7..2c6eed334 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,13 @@ exclude = [ # session + Railway/CI. MUST stay excluded (keeps surrealdb-core/OGAR out of # the default build). Verify via `cargo build --manifest-path crates/symbiont/Cargo.toml` # or `docker build -f crates/symbiont/Dockerfile -t symbiont .`. + # W0B mask-ABI differential at the R2IL seam: proves ogar-r2il's CallMask + # algebra and lance-graph-mask-risc's agree bit-identically over the same + # borrowed words, with CallMask as the oracle. MUST stay excluded -- it + # path-deps the OGAR sibling, and no ordinary workspace test should need + # that checkout present. Verify via + # `cargo test --manifest-path crates/r2il-mask-abi-probe/Cargo.toml`. + "crates/r2il-mask-abi-probe", "crates/symbiont", # OGAR (Open Graph of Active Record) activation crate — re-exports OGAR's full # AR surface (ogar-vocab Class/codebook + ogar-class-view impl ClassView + diff --git a/crates/r2il-mask-abi-probe/.gitignore b/crates/r2il-mask-abi-probe/.gitignore new file mode 100644 index 000000000..4fffb2f89 --- /dev/null +++ b/crates/r2il-mask-abi-probe/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/crates/r2il-mask-abi-probe/Cargo.toml b/crates/r2il-mask-abi-probe/Cargo.toml new file mode 100644 index 000000000..9c7969e09 --- /dev/null +++ b/crates/r2il-mask-abi-probe/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "r2il-mask-abi-probe" +version = "0.1.0" +edition = "2021" +publish = false +description = "W0B: the mask-ABI differential at the R2IL seam. Proves ogar-r2il's CallMask algebra and lance-graph-mask-risc's agree BIT-IDENTICALLY over the same borrowed words — and nothing more. NOT a Quack<->R2IL bridge: CallMask indexes call slots inside ONE body (<=180), mask-risc indexes rows of a projection (~64K). Same algebra, different index spaces; the row bridge is W0C." + +# Its OWN workspace root. Excluded from lance-graph's so no ordinary +# workspace test pays for the OGAR sibling checkout, and so `ndarray`'s +# escaping `../../../ndarray` path (reached through mask-risc) still resolves +# from its own manifest dir. Same shape as `helix` / `symbiont`. +[workspace] + +[dependencies] + +[dev-dependencies] +# The candidate for the ONE executing algebra. +lance-graph-mask-risc = { path = "../lance-graph-mask-risc" } +# The oracle in THIS probe — deliberately not yet the delegating side. Reached +# by PATH, not git: mask-risc path-deps `ndarray` at `../../../ndarray`, a +# path that leaves its own workspace and can never resolve through a cargo git +# checkout, so the differential cannot live on the OGAR side. The direction +# here matches `crates/symbiont`'s existing `../../../OGAR/crates/...` deps. +ogar-r2il = { path = "../../../OGAR/crates/ogar-r2il" } +ogar-loco = { path = "../../../OGAR/crates/ogar-loco" } diff --git a/crates/r2il-mask-abi-probe/src/lib.rs b/crates/r2il-mask-abi-probe/src/lib.rs new file mode 100644 index 000000000..c1dd38e1d --- /dev/null +++ b/crates/r2il-mask-abi-probe/src/lib.rs @@ -0,0 +1,5 @@ +//! No library surface — the probe IS its differential test. +//! +//! Deliberately empty: this crate exists to hold +//! `tests/algebra_differential.rs`, and a type declared here would be a +//! third place the two algebras could disagree. diff --git a/crates/r2il-mask-abi-probe/tests/algebra_differential.rs b/crates/r2il-mask-abi-probe/tests/algebra_differential.rs new file mode 100644 index 000000000..8f4314b65 --- /dev/null +++ b/crates/r2il-mask-abi-probe/tests/algebra_differential.rs @@ -0,0 +1,353 @@ +//! **W0B — the mask-ABI differential at the R2IL seam.** +//! +//! `ogar-r2il`'s [`CallMask`] carries its own Boolean algebra — `and` / `or` +//! / `xor` / `and_not` / `not` / `count` — over inline `u64` words. +//! `lance-graph-mask-risc` carries the same algebra as the ONE evaluator +//! above `ndarray::simd`. `lance-graph-quack`'s own manifest states the rule +//! this probe exists to test against: *"the masking algebra is reached +//! THROUGH mask-risc, never beside it."* +//! +//! So this asks exactly one question: **do the two agree bit-identically +//! over the same borrowed words?** `CallMask` is the oracle here and stays +//! the oracle — nothing is deleted, nothing delegates, no dependency +//! direction is decided. That decision needs the differential green first. +//! +//! # What this does NOT prove +//! +//! It is not a Quack↔R2IL bridge, and the two sides are not two views of one +//! population: +//! +//! ```text +//! CallMask population = call slots inside ONE body N <= 180 +//! mask-risc population = rows of one projection N ~= 64K +//! ``` +//! +//! Same algebra, different index spaces. `n_rows` below is a CallMask's +//! `len()` precisely so the comparison is apples-to-apples on the narrow +//! side; feeding a body's call mask to a row-population consumer would be a +//! category error, not an optimisation. Deriving a genuine row predicate +//! from a body is W0C. +//! +//! # Kill condition +//! +//! A disagreement is the FINDING, not a bug to align away. Do not "fix" +//! either side until it is settled which semantics is correct — the +//! difference is the information. + +use lance_graph_mask_risc::{ + execute, words_for, MaskOp, Operand, Planes, Program, Scratch, Terminal, Value, +}; +use ogar_loco::LaneShape; +use ogar_r2il::CallMask; + +/// Every shape, with the call population `ogar-loco` derives for it +/// (`CONTENT_SLOTS × calls_per_lane` = 30 × 6 / 4 / 3). +const SHAPES: [(LaneShape, u32, usize); 3] = [ + (LaneShape::Pairs, 180, 3), + (LaneShape::Triples, 120, 2), + (LaneShape::Quads, 90, 2), +]; + +fn lcg(seed: &mut u64) -> u64 { + *seed = seed + .wrapping_mul(6364136223846793005) + .wrapping_add(1442695040888963407); + *seed >> 11 +} + +/// A seeded mask plus every word/population boundary the shape can express. +/// +/// The explicit edges are the point: `63/64` and `127/128` are the word +/// seams, and `len-1` is the straddling word's last real bit. A purely +/// random fixture hits them only by luck, and the tail is exactly where two +/// complement implementations diverge. +fn seeded(shape: LaneShape, seed: u64, density: u64) -> CallMask { + let mut m = CallMask::empty(shape); + let mut s = seed; + for i in 0..m.len() { + if lcg(&mut s) % 100 < density { + m.set(i); + } + } + for edge in [0u32, 1, 62, 63, 64, 65, 126, 127, 128, 129] { + if edge < m.len() && edge % 3 != 0 { + m.set(edge); + } + } + if m.len() >= 2 { + m.set(m.len() - 2); + m.set(m.len() - 1); + } + m +} + +/// Run a one-op program over borrowed CallMask words and read the result back. +fn run_mask_op(op_of: impl Fn(Operand, Operand) -> MaskOp, a: &CallMask, b: &CallMask) -> Vec { + let n_rows = a.len() as usize; + let program = Program::new( + vec![op_of(Operand::Plane(0), Operand::Plane(1))], + Terminal::Keep { + mask: Operand::Scratch(0), + }, + ); + let planes: [&[u64]; 2] = [a.words(), b.words()]; + let planes = Planes { + n_rows, + masks: &planes, + lanes: &[], + }; + let mut scratch = Scratch::for_program(&program, n_rows).expect("scratch"); + let v = execute(&program, &planes, &mut scratch, None).expect("execute"); + assert_eq!( + v, + Value::Mask(Operand::Scratch(0)), + "Keep must report the slot it kept" + ); + scratch.slot(0).expect("slot 0").to_vec() +} + +/// The word count the two sides must independently agree on. +/// +/// Not a formality: `CallMask::words()` slices to `len.div_ceil(64)` and +/// mask-risc sizes a scratch slot with `words_for(n_rows)`. If those ever +/// disagreed, every comparison below would be between slices of different +/// length and the `assert_eq!` would report a shape mismatch rather than a +/// semantic one. +#[test] +fn both_sides_span_the_same_words() { + for (shape, want_len, want_words) in SHAPES { + let m = CallMask::all(shape); + assert_eq!(m.len(), want_len, "{shape:?}: population"); + assert_eq!( + m.words().len(), + want_words, + "{shape:?}: CallMask slice width" + ); + assert_eq!( + words_for(m.len() as usize), + want_words, + "{shape:?}: mask-risc words_for disagrees with the CallMask slice" + ); + } +} + +#[test] +fn and_or_xor_andnot_agree_bit_for_bit() { + for (shape, _, _) in SHAPES { + for (sa, sb) in [(1u64, 2u64), (0xDEAD, 0xBEEF), (7, 7)] { + for (da, db) in [(50u64, 50u64), (3, 97), (100, 0), (0, 0), (100, 100)] { + let a = seeded(shape, sa, da); + let b = seeded(shape, sb, db); + + for (name, expect, op) in [ + ( + "and", + a.and(&b), + (|x, y| MaskOp::And { a: x, b: y, dst: 0 }) + as fn(Operand, Operand) -> MaskOp, + ), + ("or", a.or(&b), |x, y| MaskOp::Or { a: x, b: y, dst: 0 }), + ("xor", a.xor(&b), |x, y| MaskOp::Xor { a: x, b: y, dst: 0 }), + ("and_not", a.and_not(&b), |x, y| MaskOp::AndNot { + a: x, + b: y, + dst: 0, + }), + ] { + let got = run_mask_op(op, &a, &b); + assert_eq!( + got, + expect.words(), + "{shape:?} {name}: seeds ({sa},{sb}) density ({da},{db}) \ + -- CallMask and mask-risc disagree. THIS IS THE FINDING: \ + settle which semantics is correct before aligning either side." + ); + } + } + } + } +} + +/// `not` is the one with a tail obligation on both sides, so it gets its own +/// test: `CallMask::not` clears per-word against `len`, mask-risc's `Not` +/// documents "(tail cleared)" against `n_rows`. They agree only if both +/// clear against the same population — which is what this measures. +#[test] +fn not_agrees_including_the_tail() { + for (shape, _, _) in SHAPES { + for (seed, density) in [(1u64, 0u64), (2, 50), (3, 100), (4, 1)] { + let a = seeded(shape, seed, density); + let n_rows = a.len() as usize; + let program = Program::new( + vec![MaskOp::Not { + a: Operand::Plane(0), + dst: 0, + }], + Terminal::Keep { + mask: Operand::Scratch(0), + }, + ); + let planes: [&[u64]; 1] = [a.words()]; + let planes = Planes { + n_rows, + masks: &planes, + lanes: &[], + }; + let mut scratch = Scratch::for_program(&program, n_rows).expect("scratch"); + execute(&program, &planes, &mut scratch, None).expect("execute"); + assert_eq!( + scratch.slot(0).expect("slot 0"), + a.not().words(), + "{shape:?} not: seed {seed} density {density} -- tail handling differs" + ); + } + } +} + +#[test] +fn count_agrees_with_the_count_terminal() { + for (shape, _, _) in SHAPES { + for (seed, density) in [(1u64, 0u64), (2, 13), (3, 50), (4, 99), (5, 100)] { + let a = seeded(shape, seed, density); + let n_rows = a.len() as usize; + let program = Program::new( + vec![], + Terminal::Count { + mask: Operand::Plane(0), + }, + ); + let planes: [&[u64]; 1] = [a.words()]; + let planes = Planes { + n_rows, + masks: &planes, + lanes: &[], + }; + let mut scratch = Scratch::for_program(&program, n_rows).expect("scratch"); + let v = execute(&program, &planes, &mut scratch, None).expect("execute"); + assert_eq!( + v, + Value::Count(a.count() as usize), + "{shape:?} count: seed {seed} density {density}" + ); + } + } +} + +/// The four binary ops as TERNLOG immediates. +/// +/// `CallMask` has no three-input op, so this is the direction the agreement +/// actually matters in: if mask-risc's arbitrary-immediate form reproduces +/// all four of CallMask's binary ops, then CallMask's algebra is a SUBSET of +/// mask-risc's, not a sibling of it — which is the evidence the ownership +/// decision (deferred out of this probe) will need. +/// +/// The immediates are DERIVED from each op's own truth table, never written +/// by hand. Hand-writing them is how the first draft of this test failed: +/// `and` was given `0b1010_0000` (bits 7 and 5) where only bit 7 is the +/// conjunction, and the failure looked like a substrate disagreement rather +/// than an arithmetic slip in the fixture. +fn ternlog_imm_for(f: impl Fn(bool, bool) -> bool) -> u8 { + let mut imm = 0u8; + for idx in 0u8..8 { + // VPTERNLOG index convention: (a << 2) | (b << 1) | c. + let a = idx & 0b100 != 0; + let b = idx & 0b010 != 0; + let c = idx & 0b001 != 0; + // `c` is bound to `a`'s plane below, so triples with `a != c` are + // unreachable and their bits are left zero — one canonical immediate + // per function rather than the four that would also work. + if a == c && f(a, b) { + imm |= 1 << idx; + } + } + imm +} + +#[test] +fn ternlog_reproduces_callmask_s_binary_ops() { + let and = ternlog_imm_for(|x, y| x && y); + let or = ternlog_imm_for(|x, y| x || y); + let xor = ternlog_imm_for(|x, y| x != y); + let andnot = ternlog_imm_for(|x, y| x && !y); + + // Pinned, so a change to the index convention fails HERE with the + // derivation visible, not inside a mask comparison. + assert_eq!(and, 0b1000_0000, "and = index 7 only"); + assert_eq!(or, 0b1010_0100, "or = indices 2, 5, 7"); + assert_eq!(xor, 0b0010_0100, "xor = indices 2, 5"); + assert_eq!(andnot, 0b0010_0000, "and_not = index 5 only"); + // The four must be distinct, or the test could pass with one op's + // immediate standing in for another's. + let mut seen = [and, or, xor, andnot]; + seen.sort_unstable(); + assert!( + seen.windows(2).all(|w| w[0] != w[1]), + "two ops derived the same immediate: {seen:?}" + ); + + for (shape, _, _) in SHAPES { + for (sa, sb, da, db) in [(1u64, 2u64, 50u64, 50u64), (9, 4, 7, 93), (5, 5, 100, 0)] { + let a = seeded(shape, sa, da); + let b = seeded(shape, sb, db); + let n_rows = a.len() as usize; + + for (name, imm, expect) in [ + ("and", and, a.and(&b)), + ("or", or, a.or(&b)), + ("xor", xor, a.xor(&b)), + ("and_not", andnot, a.and_not(&b)), + ] { + let program = Program::new( + vec![MaskOp::Ternlog { + imm, + a: Operand::Plane(0), + b: Operand::Plane(1), + c: Operand::Plane(0), + dst: 0, + }], + Terminal::Keep { + mask: Operand::Scratch(0), + }, + ); + let planes: [&[u64]; 2] = [a.words(), b.words()]; + let planes = Planes { + n_rows, + masks: &planes, + lanes: &[], + }; + let mut scratch = Scratch::for_program(&program, n_rows).expect("scratch"); + execute(&program, &planes, &mut scratch, None).expect("execute"); + assert_eq!( + scratch.slot(0).expect("slot 0"), + expect.words(), + "{shape:?} ternlog imm {imm:#010b} must reproduce CallMask::{name}" + ); + } + } + } +} + +/// **Anti-vacuity.** Every comparison above is between two computed masks; +/// if the fixtures were degenerate — all-zero, all-one, or `a == b` — most +/// of the ops would coincide and the differential would pass while proving +/// almost nothing. +#[test] +fn the_fixtures_actually_discriminate() { + for (shape, _, _) in SHAPES { + let a = seeded(shape, 1, 50); + let b = seeded(shape, 2, 50); + assert_ne!(a.words(), b.words(), "{shape:?}: fixtures are identical"); + assert!(a.count() > 0, "{shape:?}: a is empty"); + assert!(a.count() < a.len(), "{shape:?}: a is full"); + assert_ne!( + a.and(&b).words(), + a.or(&b).words(), + "{shape:?}: and == or, so the ops cannot be told apart" + ); + assert_ne!( + a.xor(&b).words(), + a.and_not(&b).words(), + "{shape:?}: xor == and_not, so the ops cannot be told apart" + ); + } +} From 8500a2a56fb58ff7c99cbfe730e52e8f0cf251e8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:27:52 +0000 Subject: [PATCH 02/19] ci: run the r2il-mask-abi-probe differential (excluded tier) The probe is workspace-excluded, so every `cargo test` step in this workflow steps past it -- and this repo's own discipline is that an excluded crate without a CI line rots invisibly (measured elsewhere in the fleet: a floating branch dep broken for weeks because no CI built the pair). It is runnable here and nowhere else in CI today: `rust-test.yml` already checks out BOTH siblings the probe needs as siblings of `lance-graph` (`path: ndarray`, `path: OGAR`, `working-directory: lance-graph`), which is exactly the layout `../../../ndarray` and `../../../OGAR/crates/ogar-r2il` resolve against. Placed beside the lance-graph-ogar step, the other OGAR-sibling-armed excluded tier. ORDERING, stated rather than hidden: this step is RED until AdaWorldAPI/OGAR#305 (`CallMask::words()`) merges, because it compiles against the OGAR sibling's default branch. That is a stacked dependency the PR body already names, not a defect in the probe -- and a red step whose cause is on the record beats a green workflow that never ran the test. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .github/workflows/rust-test.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/rust-test.yml b/.github/workflows/rust-test.yml index 30f1e0eb3..4e7afc8a5 100644 --- a/.github/workflows/rust-test.yml +++ b/.github/workflows/rust-test.yml @@ -155,6 +155,22 @@ jobs: # had never minted them). One scoped step closes both. - name: Run lance-graph-ogar codebook-parity + hotplug-activation tests (armed tier, OGAR sibling) run: cargo test --manifest-path crates/lance-graph-ogar/Cargo.toml + # r2il-mask-abi-probe: the W0B mask-ABI differential, workspace-EXCLUDED + # and path-depping BOTH siblings checked out above (mask-risc reaches + # `ndarray` at ../../../ndarray; the probe reaches ogar-r2il at + # ../../../OGAR/crates/ogar-r2il). It proves ogar-r2il's CallMask + # Boolean algebra and lance-graph-mask-risc's agree BIT-IDENTICALLY over + # the same borrowed words -- the check that decides whether CallMask's + # and/or/xor/and_not/not/count is a second algebra beside the one + # evaluator or a subset of it. Excluded means no step above reaches it, + # and an excluded crate with no CI line rots invisibly. + # + # ORDERING: requires ogar-r2il's `CallMask::words()` (AdaWorldAPI/OGAR + # #305). This step is RED until that merges, because it compiles against + # the OGAR sibling's default branch -- a stated stacked dependency, not a + # defect in this probe. + - name: Run r2il-mask-abi-probe mask-ABI differential (excluded tier, OGAR + ndarray siblings) + run: cargo test --manifest-path crates/r2il-mask-abi-probe/Cargo.toml # deepnsm: standalone 0-dep codec crate, workspace-excluded, so the # lance-graph test steps above never reached it. ~217 lib + integration + # doctests, fast (no lance/datafusion/ndarray deps). Gating. From 92499a488bab81c225e65aca251757bf10c70945 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:35:10 +0000 Subject: [PATCH 03/19] knowledge+agent: the CARGO COMPUTE SUBSTRATE LAW, measured MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator ruling 2026-09-20: "ndarray ist das Silizium. Die Crates sind nur verschiedene Schaltungen darauf." The ten-rule law, plus a dependency-architecture-ONLY agent to apply it and a CI guard to retire it. The distinction the doc rests on: package/crate boundaries are not runtime boundaries. Many crates at compile time, one statically linked binary at runtime -- so "one binary" is never an argument for fewer crates. Rule 1 deliberately does NOT say every crate imports ndarray; a pure DTO/vocabulary crate has no compute contract and coupling it would be artificial. The binding form is compute-contract scoped. Rule 7 splits carrier from algebra: `CallMask.words` is a domain carrier and stays one permanently; `CallMask::and/or/xor` is a transitional domain-local algebra whose destination is ndarray via mask-risc. The migration order is fixed -- differential parity FIRST, then ownership, then migration -- and a duplicate not yet proven bit-identical is never deleted, because the difference would be the finding. FOUR MEASURED FINDINGS, each with the command that produced it (§2): 1. Six coordinate shapes across ten repos, at FIVE different path depths (`../ndarray` .. `../../../../../ndarray`). The sibling-directory assumption is load-bearing in at least five repos at once. 2. lance-graph has one ndarray identity TODAY BY ACCIDENT OF EXCLUSION. The root `[patch.crates-io]` redirects the upstream registry crate, and `[patch.crates-io]` structurally cannot redirect the AdaWorldAPI git URL that `perturbation-sim` and `helix` use. Both are workspace-EXCLUDED, so no member binary sees both; promote either and the graph carries two. 3. The recorded blocker against a canonical git coordinate DOES NOT REPRODUCE, so rule 5 is implementable. That `[patch]` comment blamed a `burn` SUBMODULE with an unfetchable gitlink. Measured on master (e1ef350): `git ls-tree HEAD` shows no `160000` entry and no `.gitmodules` -- `burn` is `crates/burn`, an in-tree member whose OWN git deps (AdaWorldAPI/burn.git rev 9b2b671) are genuinely out of scope. But cargo resolves the `ndarray` package, not every member's dependencies: a throwaway crate with the git coordinate returned `cargo metadata` exit 0, `Locking 10 packages`, `ndarray v0.17.2 (...#e1ef350a)`, no burn fetch, no 403. Comment corrected in place in this commit; what survives is the smaller true reason (a git coordinate needs network on a fresh resolve). 4. One canonical source COUPLES THE FLEET'S MSRV. ndarray master requires Rust 1.98; tesseract-rs pins 1.97.1, odoo-rs 1.95, ladybug-rs 1.94.0, and two of those path-dep ndarray directly -- measurably unable to build against master. Filed as ISS-NDARRAY-CANONICAL-COORDINATE-COUPLES-FLEET-MSRV, explicitly NOT to be resolved by bumping three toolchains inside a unification pass. The agent card names the issue id and is instructed to report and stop. The agent (`cargo-substrate-architect`, sonnet) carries a hard scope fence: dependency coordinates, features, workspace tables and patches ONLY. It never designs carriers, never touches reasoning code, never bumps a toolchain, and returns per-site verdicts (CANONICAL / REDIRECTABLE / PATH-LOCKED / DUPLICATE-IDENTITY / PARALLEL-ALGEBRA / OUT-OF-SCOPE) rather than prose. Its step 10 is a CI guard with a mandatory disable run per check, and its closing rule is that "an agent notices" is not an answer to "what stops this regressing?". Indexed in `.claude/agents/BOOT.md`'s trigger table beside simd-savant -- an agent card nobody can find is the same rots-invisibly failure as an excluded crate with no CI line. DELIBERATELY NO EPIPHANIES ENTRY, stated rather than skipped silently. Finding 3 is a correction, which the board table routes to EPIPHANIES -- but it is already recorded in the two places it is actionable (the comment it corrects, and §2.3 of the doc the agent must read first). A third dated entry would divide the search surface, which is the measured cost the 2026-09-19 cleanup pass names. Finding 4 went to ISSUES because it is an unresolved blocker, which is what ISSUES is for. Gates: workspace manifest parses (`cargo metadata --no-deps`), supersession index regenerates byte-identical (no plan or verdict changed). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/agents/BOOT.md | 1 + .claude/agents/cargo-substrate-architect.md | 197 +++++++++++++ .claude/board/ISSUES.md | 37 +++ .claude/knowledge/CARGO-COMPUTE-SUBSTRATE.md | 277 +++++++++++++++++++ Cargo.toml | 33 ++- 5 files changed, 539 insertions(+), 6 deletions(-) create mode 100644 .claude/agents/cargo-substrate-architect.md create mode 100644 .claude/knowledge/CARGO-COMPUTE-SUBSTRATE.md diff --git a/.claude/agents/BOOT.md b/.claude/agents/BOOT.md index 3e352e67b..4773cc0fa 100644 --- a/.claude/agents/BOOT.md +++ b/.claude/agents/BOOT.md @@ -207,6 +207,7 @@ documents listed in its trigger row BEFORE producing output. | **Quality lifecycle — DURING-IMPL: "two crates need to talk" / "DTO field shape change" / "renamed in PR #X" / lib.rs/mod.rs touch / new REST endpoint / sprint↔sprint handover / cross-repo dep** | **baton-handoff-auditor** (PP-15, boundary mismatch hunter) | baton-handoff-anti-patterns.md, iron-rules-doctrine.md, lab-vs-canonical-surface.md | | **Quality lifecycle — POST-IMPL: "ready for codex review" / "pre-merge sanity check" / clippy/audit/deny/kani/loom gate / unsafe without `// SAFETY:` / v1-API-under-v2-feature alias** | **brutally-honest-tester** (PP-13, codex-class within-crate bug hunter) | codex-p1-anti-patterns.md, iron-rules-doctrine.md | | **Quality lifecycle — CROSS-CUTTING (PRE-SPAWN + DURING-IMPL + PRE-MERGE): "_mm*" or "vld1q_*" or "is_x86_feature_detected" in a consumer crate / arch-specific cfg outside `ndarray/src/simd_*` / hand-rolled SIMD-feature dispatch / SIMD primitive missing from polyfill / duplicated SIMD wrapper / SIMD-induced UB or OOB** | **simd-savant** (5th-slot, ndarray::simd polyfill keeper — all SIMD via `simd.rs` + `simd_ops.rs` > `simd_{type}.rs`) | autoattended-multiagent-pattern.md §14 | +| **Dependency architecture — ndarray coordinate / `[patch]` / `[workspace.dependencies]` / relative cross-repo `path = "../../../ndarray"` / `optional = true` on a compute crate / "multiple ndarray identities" / a domain-local and/or/xor algebra beside the substrate / "one binary" reasoning applied to crate count** | **cargo-substrate-architect** (dependency graph ONLY — never carriers, never reasoning code, never deletes a duplicate algebra before differential parity) | CARGO-COMPUTE-SUBSTRATE.md | **The insight update cycle:** diff --git a/.claude/agents/cargo-substrate-architect.md b/.claude/agents/cargo-substrate-architect.md new file mode 100644 index 000000000..8c9d2b8ec --- /dev/null +++ b/.claude/agents/cargo-substrate-architect.md @@ -0,0 +1,197 @@ +--- +name: cargo-substrate-architect +description: > + Dependency architecture only. Holds the CARGO COMPUTE SUBSTRATE LAW — + one ndarray, one package identity, one binary, no parallel compute + substrate. Use BEFORE adding/moving/pinning/feature-gating any + `ndarray` dependency in ANY fleet repo, before writing a `[patch]`, + a `[workspace.dependencies]` entry, or a relative cross-repo path + dep, and to run the fleet unification wave. It does NOT design + carriers, does NOT touch reasoning code, and does NOT delete a + duplicate algebra before differential parity. +tools: Read, Glob, Grep, Bash +model: sonnet +--- + +You are the CARGO_SUBSTRATE_ARCHITECT. Your mission is **boring +infrastructure** and is stated in one line: + +> one ndarray, one package identity, one binary, no parallel compute substrate. + +You are not here to discover architecture. You are here to make the dependency +graph say what the architecture already decided. + +## MANDATORY FIRST READ + +`.claude/knowledge/CARGO-COMPUTE-SUBSTRATE.md` — the ten-rule law, the +measured 2026-09-20 fleet inventory, the `[patch]` limit, and the anti-pattern +table. Do not restate it; apply it. If your finding contradicts a measurement +in §2 of that doc, **re-run the command** before writing anything: its numbers +carry the command that produced them precisely so you can falsify them. + +## HARD SCOPE FENCE — read this before the wave + +You change **dependency coordinates, features, workspace tables and patches**. +You do not change: + +- what `CallMask`, `CE64`, `Moore128`, `AlphaMask`, or any R2IL/OGAR type MEANS; +- any reasoning, masking, fold, or semantic implementation; +- any carrier's layout, width, or field set; +- toolchain pins (see the MSRV trap below). + +A session that unifies `ndarray` AND redesigns a carrier has produced a diff +nobody can review. If a dependency change appears to require a semantic +change, **STOP and report it** — that is a finding for the operator, not work +for you. + +## The wave, in order + +### 1. Inventory — measure, never read by eye + +```bash +for r in ; do + grep -rhnE '^[[:space:]]*ndarray[[:space:]]*=' --include=Cargo.toml "$r" +done +``` + +Record for every site: `path` / `git` / `registry` / `workspace = true`, the +rev or branch, `optional`, and the feature list. Group by coordinate SHAPE, and +count distinct PATH DEPTHS separately — depth variety is what makes the +sibling-directory assumption fragile. + +### 2. Establish whether a duplicate identity exists TODAY + +Per-binary, not per-repo: + +```bash +cargo metadata --format-version 1 | \ + python3 -c "import json,sys;p=[x['id'] for x in json.load(sys.stdin)['packages'] if x['name']=='ndarray'];print(len(p),p)" +cargo tree -d | grep -A3 ndarray +``` + +**A single identity may be an accident of exclusion.** In lance-graph today the +two git-coordinate crates are workspace-EXCLUDED; promote either to a member +and the graph carries two. Report the accident as an accident. + +### 3. Pick the canonical coordinate and declare it once + +Per workspace root: + +```toml +[workspace.dependencies] +ndarray = { git = "", rev = "", default-features = false, features = ["std"] } +``` + +Members become `ndarray = { workspace = true, features = [...] }`. + +### 4. Retire relative cross-repo paths + +`ndarray = { path = "../../../ndarray" }` is forbidden as a DURABLE contract +(rule 5), for one mechanical reason you must be able to state: **a `[patch]` +rewrites a source, not a dependency declaration**, so a literal `path =` is the +one form nothing can centrally redirect. + +Local crate paths INSIDE a single workspace stay. They are not cross-repo. + +### 5. Enable local development + +At the top-level consumer only: + +```toml +[patch.""] +ndarray = { path = "../ndarray" } +``` + +Note the section name matters: `[patch.crates-io]` redirects the upstream +registry crate and **cannot** redirect an AdaWorldAPI git URL. lance-graph +already has the crates-io form for exactly the upstream-fork case; do not +mistake it for git unification. + +### 6. Remove `optional = true` where the contract is compute + +Rule 6. A crate whose contract is compute execution has no meaningful +substrate-less build. Build the compute-contract list explicitly and put each +crate on it with a reason; do not infer membership from the crate's name. + +### 7. Inventory duplicate Boolean/SIMD algebras — DO NOT DELETE + +Record every domain-local `and`/`or`/`xor`/`not`/`count`/`popcount` or raw +intrinsic implementation. For each, the order is fixed: + +```text +differential parity FIRST -> then ownership -> then migration +``` + +A duplicate not yet proven bit-identical is a FINDING, never a deletion. The +worked precedent is `crates/r2il-mask-abi-probe` (CallMask vs mask-risc, 6/6, +every test disable-verified, ownership deliberately left open). + +### 8. Prove one identity per final binary + +`cargo metadata` + `cargo tree -d` on each representative consumer, and state +the number. "Should be one" is not a measurement. + +### 9. Link the representative final binaries + +Quack, R2IL/OGAR, the Java ABI, the Odoo PoC — a full `cargo build --release`, +not a `cargo check`. A resolve proves the graph; only a link proves rule 8. + +### 10. Leave a CI guard behind, then stop + +This is the step that makes you unnecessary. Ship a script that FAILS on: + +```text +multiple ndarray package identities in one resolve +ndarray optional in a mandatory-compute crate +a forbidden direct SIMD implementation +a forbidden cross-repo ../../../ndarray dependency +``` + +**Every check needs a disable run** — introduce the violation, watch it go red, +restore — before you claim it guards anything. A guard that cannot fail is +decoration, and this workspace has shipped that mistake before. + +## Traps, each measured + +**The MSRV coupling.** ndarray master requires Rust 1.98. Measured +2026-09-20: `tesseract-rs` pins 1.97.1, `odoo-rs` 1.95, `ladybug-rs` 1.94.0, +and two of those path-dep ndarray directly. **One canonical source means one +MSRV floor for every consumer.** Do not bump three toolchains as a side effect +of a dependency pass — that is +`ISS-NDARRAY-CANONICAL-COORDINATE-COUPLES-FLEET-MSRV` and it is the operator's +call. + +**A documented reason can be stale.** lance-graph's `[patch.crates-io]` comment +blamed a `burn` SUBMODULE with an unfetchable gitlink. Measured: no gitlink, no +`.gitmodules`; `burn` is an in-tree member whose OWN git deps are out of scope, +and a git coordinate for `ndarray` resolves clean anyway (exit 0, 10 packages, +no 403). **Before you accept a recorded blocker, run the command that would +falsify it.** + +**The `.git` suffix is not a second identity.** Cargo canonicalizes git URLs +and strips a trailing `.git`. Do not count it, do not "fix" it. + +**One binary is not one crate.** If your conclusion is "merge these crates", +you have confused a link property with a module boundary. Report and stop. + +## Verdicts + +Return one per site, never prose: + +- **CANONICAL** — uses the one coordinate, correct features, not optional + where the contract forbids it. +- **REDIRECTABLE** — wrong coordinate but on a patchable source; name the + one-line change. +- **PATH-LOCKED** — a literal relative cross-repo `path =`; no `[patch]` can + reach it, so it needs the one-time move onto a patchable coordinate. +- **DUPLICATE-IDENTITY** — two ndarray package ids reach one binary; name both + ids and the crate that introduces the second. +- **PARALLEL-ALGEBRA** — a domain-local compute algebra beside the substrate; + name it, name whether a differential exists, and **do not touch it**. +- **OUT-OF-SCOPE** — a semantic change is required; stop and report. + +## Closing rule + +After you run, nobody should have to remember the law. If the answer to +"what stops this regressing?" is "an agent notices", you have not finished +step 10. diff --git a/.claude/board/ISSUES.md b/.claude/board/ISSUES.md index 6632bc168..4efa95938 100644 --- a/.claude/board/ISSUES.md +++ b/.claude/board/ISSUES.md @@ -1,3 +1,40 @@ +## ISS-NDARRAY-CANONICAL-COORDINATE-COUPLES-FLEET-MSRV — one canonical ndarray source imposes one MSRV floor; three repos pin below it (2026-09-20) + +**Status:** OPEN. Operator decision, not a dependency-pass side effect. + +The CARGO COMPUTE SUBSTRATE LAW (`.claude/knowledge/CARGO-COMPUTE-SUBSTRATE.md`, +rule 3) requires ONE canonical `ndarray` source coordinate across the fleet. +Measured 2026-09-20, that has a price nobody had stated: ndarray master +(`e1ef350`) reports **requires Rust 1.98**, and the fleet does not agree on a +toolchain. + +| toolchain | repos | +|---|---| +| **1.98.1** | lance-graph, OGAR, a2ui-rs, stockfish-rs, MedCare-rs, q2 | +| 1.97.1 | tesseract-rs | +| 1.95 | odoo-rs | +| 1.94.0 | ladybug-rs | + +`tesseract-rs` and `ladybug-rs` both path-dep ndarray DIRECTLY +(`path = "../../../ndarray"` with `features = ["runtime-dispatch"]`, and +`path = "../ndarray"` respectively), so on current master they are measurably +unable to build against it. Whatever they build against today is an older +checkout. + +**So "one canonical source" and "each repo keeps its own toolchain pin" cannot +both hold.** The options are a fleet-wide 1.98 bump, a pinned older ndarray +`rev` as the canonical coordinate, or an explicit two-tier split — each with +consequences outside a dependency pass. + +**Do NOT resolve this by bumping three toolchains inside a unification PR.** +`cargo-substrate-architect` is instructed to report it and stop; the card names +this issue id. + +Method note: `tesseract-rs`'s own CLAUDE.md records a 1.97.1 pin and +`stockfish-rs`'s records 1.95 while its `rust-toolchain.toml` says 1.98.1 — the +FILES were read, not the prose, per this workspace's own rule that a document +is not evidence about the state of the tree. + ## ISS-DISMECH-SEAM-INVERTED-BOTH-WAYS — counterfactual adjudication CORRECTED; cleanup pass closed (2026-09-19) ⊘ The census addendum below says the DisMech `Verdict{Consistent, diff --git a/.claude/knowledge/CARGO-COMPUTE-SUBSTRATE.md b/.claude/knowledge/CARGO-COMPUTE-SUBSTRATE.md new file mode 100644 index 000000000..cccd113fa --- /dev/null +++ b/.claude/knowledge/CARGO-COMPUTE-SUBSTRATE.md @@ -0,0 +1,277 @@ +# Cargo compute substrate — one ndarray, one package identity, one binary + +> READ BY: cargo-substrate-architect, integration-lead, simd-savant, +> kernel-membrane-warden, any session that adds, moves, pins, or feature-gates +> an `ndarray` dependency in ANY repo of this fleet, or that is about to write +> a `[patch]`, a `[workspace.dependencies]` entry, or a relative cross-repo +> path dep. +> +> Born 2026-09-20 from the W0B mask-ABI differential, which surfaced a +> domain-local Boolean algebra (`ogar-r2il::CallMask::and/or/xor/and_not/not`) +> sitting beside the one evaluator. Operator ruling the same day: *"ndarray ist +> das Silizium. Die Crates sind nur verschiedene Schaltungen darauf."* +> +> Scope: DEPENDENCY ARCHITECTURE ONLY. This doc never decides what `CallMask`, +> CE64, Moore, or R2IL MEAN. A session using it to redesign a carrier has left +> its scope. + +## 0. The distinction the whole doc rests on + +**Package/crate boundaries are not runtime boundaries.** Cargo may look like a +wide graph and still produce one statically linked executable: + +```text + final-app + / | \ + Quack R2IL Odoo + | | | + mask-risc ogar-loco OGAR + \ | / + └────────── ndarray ────────┘ + │ + ▼ + target/release/ +``` + +No plugins, no DLL layer, no IPC, no second process. Many crates at compile +time, one binary at runtime — hard compile-time modularity with **no runtime +architecture tax**. "Everything must be one binary" is therefore NOT an +argument for fewer crates; if anything it is an argument for more, each with a +harder contract. + +## 1. THE LAW + +```text +CARGO COMPUTE SUBSTRATE LAW + + 1. ndarray is the mandatory compute substrate. + 2. Hot execution crates depend on ndarray directly or through the one + canonical execution facade; no sibling SIMD/mask implementation. + 3. All repositories use ONE canonical ndarray source coordinate. + 4. Local development may [patch] that coordinate to a local checkout. + 5. Relative cross-repo ndarray paths are forbidden as durable dependencies. + 6. Features may select capabilities/backends, but may not remove ndarray + from a crate whose contract is compute execution. + 7. Domain-local carriers are allowed: + CallMask, AlphaMask, Moore128, ... + Domain-local duplicate execution algebras are not. + 8. One final executable is expected: + many Rust crates at compile time + one statically linked binary at runtime. + 9. `cargo tree -d` must not show multiple ndarray package identities. +10. CI proves the rule. Documentation does not. +``` + +### What rule 1 does NOT say + +It does **not** say every crate must import ndarray. A pure DTO / vocabulary / +contract crate (`lance-graph-contract`, `ogar-loco`, `ogar-vocab`) has no +compute contract and coupling it to the substrate would be artificial. The +binding form is: + +> Every crate that EXECUTES masking, SIMD, fold, tile, vector, field, or +> numeric hot-path algebra must use the same canonical ndarray package +> identity. No parallel compute algebra beside it. The final product may link +> everything statically into one binary. + +### Rule 7, stated as the carrier/algebra split + +```text +CallMask.words domain CARRIER ALLOWED, permanently +CallMask::and/or/xor/... domain-local ALGEBRA transitional only +ndarray (via mask-risc) execution AUTHORITY the destination +``` + +The migration order is not negotiable and is not "delete the duplicate": + +```text +differential parity FIRST -> then ownership -> then migration +``` + +A duplicate algebra that has not been proven bit-identical must not be +deleted, delegated, or "aligned" — the difference would be the finding. + +## 2. MEASURED CURRENT STATE (2026-09-20) + +Every number below came from a command, not from a manifest read by eye. + +### 2.1 Six coordinate shapes across ten repos + +``` +grep -rhnE '^[[:space:]]*ndarray[[:space:]]*=' --include=Cargo.toml +``` + +| shape | seen in | +|---|---| +| `path = "../../../ndarray"` | lance-graph (majority), tesseract-rs, lance-graph-java | +| `path = "../ndarray"` | stockfish-rs, ladybug-rs, lance-graph root `[patch]` | +| `path = "../../ndarray"` / `"../../../../ndarray"` / `"../../../../../ndarray"` | q2, lance-graph-java | +| `git = ".../ndarray.git", branch = "master"` | lance-graph (`perturbation-sim`, `helix`) | +| `git = ".../ndarray", branch = "master"` | a2ui-rs, MedCare-rs | +| `workspace = true` | MedCare-rs, q2 | + +Path depths run from `../ndarray` to `../../../../../ndarray` — **five +different depths**, so "the repos happen to sit next to each other" is +load-bearing in at least five repos at once. That is what rule 5 exists to +retire. + +The `.git` suffix difference is COSMETIC: cargo canonicalizes a git URL and +strips a trailing `.git`, so those two forms are one source. Do not "fix" it as +a bug and do not count it as a second identity. + +### 2.2 lance-graph today has ONE identity — by accident of exclusion + +The root carries `[patch.crates-io] ndarray = { path = "../ndarray" }`. Note +the section: it redirects the REAL crates.io `ndarray` (the upstream numeric +crate this is a fork of) onto the fork, which is what stops a transitive pull +of upstream from becoming a second identity. It does **not** redirect the +AdaWorldAPI git URL — `[patch.crates-io]` cannot. + +The two crates that DO use the git coordinate (`perturbation-sim`, `helix`) are +both workspace-EXCLUDED, and `helix` has its own `[workspace]`. So no member +binary sees both identities. **The single identity is a consequence of those +two crates being excluded, not of any rule.** Promote either to a member and +the graph carries two ndarrays. + +### 2.3 The recorded blocker against a canonical git coordinate DOES NOT REPRODUCE + +`Cargo.toml`'s patch comment says the git form "re-fetched AdaWorldAPI/ndarray ++ its burn submodule on every resolve; burn is outside the session repo scope +(403) and the gitlink rev is unfetchable, so the git form deadlocks offline +sessions." + +Measured on master (`e1ef350`): + +- **`burn` is not a submodule.** `git ls-tree HEAD` shows no `160000` gitlink + and no `.gitmodules`. It is `crates/burn`, an in-tree workspace member + (`members` line 484). +- The out-of-scope dependency is real but differently located: + `crates/burn/Cargo.toml` git-deps `AdaWorldAPI/burn.git` rev `9b2b671` + (three crates), and `AdaWorldAPI/elliptic-curves` appears elsewhere in the + fork. +- **A git coordinate for `ndarray` nonetheless resolves clean.** A throwaway + crate with `ndarray = { git = ".../ndarray", branch = "master", + default-features = false, features = ["std"] }` returned + `cargo metadata` exit 0, `Locking 10 packages`, `ndarray v0.17.2 + (…?branch=master#e1ef350a)`. No burn fetch. No 403. Cargo resolves the + `ndarray` package, not every member's dependencies. + +So **rule 5 is implementable** and the comment's stated cause is stale. The one +real remaining cost is honest and small: a git coordinate needs network on a +fresh resolve where a path coordinate needs none. That is a reason to `[patch]` +locally (rule 4), never a reason to keep the relative path as the durable +contract. + +> The comment is corrected in place in the same commit that added this doc. +> Recorded here because a documented reason that no longer holds is worse than +> no reason: it is the only thing standing against rule 5, and it survived +> unchallenged until somebody ran `git ls-tree`. + +### 2.4 One canonical source COUPLES THE FLEET'S MSRV — three repos pin below it + +ndarray master reports `requires Rust 1.98`. + +| toolchain | repos | +|---|---| +| **1.98.1** | lance-graph, OGAR, a2ui-rs, stockfish-rs, MedCare-rs, q2 | +| 1.97.1 | tesseract-rs | +| 1.95 | odoo-rs | +| 1.94.0 | ladybug-rs | + +`tesseract-rs` and `ladybug-rs` both path-dep ndarray directly, so on current +master they are measurably unable to build against it. This is rule 3's real +price and it is not optional: **one canonical source means one MSRV floor for +every consumer of it.** Tracked as +`ISS-NDARRAY-CANONICAL-COORDINATE-COUPLES-FLEET-MSRV`; do NOT bump three +toolchains as a side effect of a dependency-unification pass. + +### 2.5 One known duplicate algebra, differential GREEN, migration NOT started + +`ogar-r2il::CallMask` carries `and`/`or`/`xor`/`and_not`/`not`/`count` over +inline `[u64; 3]`. Proven bit-identical to `lance-graph-mask-risc` over the +same borrowed words (`crates/r2il-mask-abi-probe`, 6/6, every test +disable-verified), and mask-risc's arbitrary ternlog immediate reproduces all +four binary ops — so CallMask's algebra is a SUBSET, not a sibling. + +Ownership is deliberately undecided. Under rule 7 the destination is ndarray +via mask-risc; the three live options are tiny wrappers/oracle, a shared lower +primitive, or delegation if the direction is clean. `lance-graph-quack` states +the target shape in its own manifest: *"the masking algebra is reached THROUGH +mask-risc, never beside it."* + +## 3. The target dependency geometry + +Not this: + +```text +lance-graph -> path ../../../ndarray +OGAR -> git ndarray +odoo-rs -> crates.io ndarray # three packages, one name +``` + +But this: + +```text +every repo: ndarray = { workspace = true } +workspace root: + [workspace.dependencies] + ndarray = { git = "", rev = "" , ... } + +local supercheckout only: + [patch.""] + ndarray = { path = "../ndarray" } +``` + +Which gives: + +```text +CI / standalone clone -> pinned git ndarray +local development -> same dep, transparently patched to ../ndarray +release binary -> exactly ONE resolved ndarray package +``` + +### The `[patch]` limit that must be understood before using it + +A `[patch]` rewrites a **source**, not a dependency declaration. A manifest +that already says + +```toml +ndarray = { path = "../../../ndarray" } +``` + +is **not** redirected by any `[patch]`. For such a crate the path geometry must +be correct, or the dependency has to be moved once onto a patchable coordinate +(a git source, or `workspace = true`). This is precisely why rule 5 is a rule +and not a preference: a relative path is the one form that cannot be +centrally redirected. + +Within a SINGLE workspace, ordinary local crate paths stay — they are not +cross-repo and nothing here asks for them to change. + +## 4. Falsifiers — rule 10 in practice + +Documentation does not prove the law. Each rule gets a mechanical check: + +| rule | check | +|---|---| +| 3, 9 | `cargo metadata` → count distinct package ids named `ndarray`; `cargo tree -d \| grep ndarray` must be empty | +| 5 | no `Cargo.toml` in the fleet matches `ndarray *= *{[^}]*path *= *"(\.\./){2,}` | +| 6 | no `ndarray = { … optional = true` in a crate on the compute-contract list | +| 2, 7 | no `core::arch`, `_mm_`, `#[cfg(target_arch` or `target_feature` outside `ndarray` itself and `#[cfg(test)]` oracles | +| 8 | a representative final binary LINKS: Quack, R2IL/OGAR, the Java ABI, the Odoo PoC | + +A guard that cannot fail proves nothing: each check needs a disable run +(introduce the violation, watch the check go red) before it is trusted — the +same rule this workspace applies to every other gate. + +## 5. Anti-patterns, each with the right shape beside it + +| anti-pattern | right shape | +|---|---| +| "ndarray is mandatory, so this DTO crate must import it" | compute contract, not crate count — leave vocabulary crates alone | +| "one binary, so merge the crates" | one binary is a LINK property; keep the crates and their contracts | +| "the duplicate algebra is obviously wrong, delete it" | differential parity first; the difference is the finding | +| "add `optional = true` so the lean build skips ndarray" | a compute crate without its substrate has no contract left (rule 6) | +| "`[patch]` will unify it" — on a crate with a literal `path =` | `[patch]` rewrites sources, not path declarations | +| "`.git` suffix mismatch is a second identity" | cargo canonicalizes; measured, not a duplicate | +| "bump the three lagging toolchains while we are in here" | that is `ISS-NDARRAY-CANONICAL-COORDINATE-COUPLES-FLEET-MSRV`, its own decision | diff --git a/Cargo.toml b/Cargo.toml index 2c6eed334..32ab3abb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -341,12 +341,33 @@ datafusion-functions-aggregate = "54" object_store = { version = "0.13", features = ["aws"] } [patch.crates-io] -# Local sibling checkout of the SAME fork (P0: "prefer the local/fork source, -# always"; the direct deps already assume the sibling via path = "../../../ndarray"). -# The git-URL form re-fetched AdaWorldAPI/ndarray+its burn submodule on every -# resolve; burn is outside the session repo scope (403) and the gitlink rev is -# unfetchable, so the git form deadlocks offline sessions. Path form = zero -# network, identical source. +# Redirects the REAL crates.io `ndarray` -- the upstream numeric crate this is +# a fork OF -- onto the fork, so a transitive pull of upstream can never become +# a second package identity. Note the section: `[patch.crates-io]` CANNOT +# redirect the AdaWorldAPI git URL, and two excluded crates +# (`perturbation-sim`, `helix`) do use that git coordinate. No member binary +# sees both identities today, but that is a consequence of those crates being +# EXCLUDED, not of this patch. +# +# P0: "prefer the local/fork source, always"; the direct deps already assume +# the sibling via path = "../../../ndarray". +# +# ⊘ CORRECTED 2026-09-20. This comment previously read: "The git-URL form +# re-fetched AdaWorldAPI/ndarray+its burn submodule on every resolve; burn is +# outside the session repo scope (403) and the gitlink rev is unfetchable, so +# the git form deadlocks offline sessions." Measured on master (e1ef350): +# `git ls-tree HEAD` shows NO `160000` gitlink and NO `.gitmodules` -- `burn` +# is `crates/burn`, an in-tree workspace member. Its OWN git deps +# (AdaWorldAPI/burn.git rev 9b2b671) are genuinely out of session scope, but +# cargo resolves the `ndarray` package rather than every member's +# dependencies: a throwaway crate with `ndarray = { git = ".../ndarray", +# branch = "master" }` returned `cargo metadata` exit 0, `Locking 10 +# packages`, `ndarray v0.17.2 (...#e1ef350a)`, no burn fetch, no 403. So the +# git form does NOT deadlock. What survives: a git coordinate needs network on +# a fresh resolve where a path coordinate needs none. Path form = zero network, +# identical source -- which is the reason to keep it, and it is a smaller +# reason than the one this comment used to give. +# Full measurement + the target geometry: .claude/knowledge/CARGO-COMPUTE-SUBSTRATE.md ndarray = { path = "../ndarray" } # Dev/test debuginfo OFF (operator, 2026-08-18: "Cargo Debug*=0 or so makes it From 80f6c7d54ef497183767889a821ab1574f365f2e Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:38:54 +0000 Subject: [PATCH 04/19] hooks: two-sided test for the anti-pattern-matching guard (pre-disable checkpoint) --- .claude/hooks/anti-pattern-matching.sh | 44 ++++++++++- .../hooks/tests/anti-pattern-matching.test.sh | 74 +++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) create mode 100755 .claude/hooks/tests/anti-pattern-matching.test.sh diff --git a/.claude/hooks/anti-pattern-matching.sh b/.claude/hooks/anti-pattern-matching.sh index a616fd72c..fbd61cb2a 100755 --- a/.claude/hooks/anti-pattern-matching.sh +++ b/.claude/hooks/anti-pattern-matching.sh @@ -19,7 +19,7 @@ input="$(cat)" tool="$(printf '%s' "$input" | jq -r '.tool_name // ""')" -RULE='ANTI-MUSTER-REGEL (Operator-Direktive): Grep/grep/rg/sed/tail/head sind NUR schnelle Discovery-Suche ueber den kompletten Corpus (ein Symbol/eine Datei lokalisieren) — NIEMALS Ersatz fuers Verstehen. Auf einen Treffer NICHT handeln (editieren, loeschen, beurteilen, "verstanden" behaupten), bevor die betroffene Datei VOLLSTAENDIG mit dem Read-Tool gelesen wurde. Verstehen = ganzes Read, kein Snippet. (Grund: geloeschter Code, der nur gemustert, nie gelesen wurde.)' +RULE='ANTI-MUSTER-REGEL (Operator-Direktive): Grep/grep/rg/sed/tail/head sind NUR schnelle Discovery-Suche ueber den kompletten Corpus (ein Symbol/eine Datei lokalisieren) — NIEMALS Ersatz fuers Verstehen. Auf einen Treffer NICHT handeln (editieren, loeschen, beurteilen, "verstanden" behaupten), bevor die betroffene Datei VOLLSTAENDIG mit dem Read-Tool gelesen wurde. Verstehen = ganzes Read, kein Snippet. (Grund: geloeschter Code, der nur gemustert, nie gelesen wurde.) || SEARCH IS NAVIGATION, NEVER EVIDENCE. Suche darf NUR feststellen: "Kandidaten sind X, Y, Z". Sie darf NIE feststellen: was ein Typ bedeutet, was eine Funktion garantiert, dass ein Consumer NICHT existiert, dass ein Mechanismus unbenutzt ist, wer etwas besitzt, wie eine Dependency-Richtung laeuft. AUTO-DEEPEN (Pflicht-Read vor jeder Aussage) bei: 0 Treffer + Absenz-Behauptung | den Worten none/no consumer/unused/never/only/all/every/not implemented | nur einem Snippet als Grundlage | trait/macro/generated/re-export/alias/feature-gated | Crate- oder Repo-Grenze | abgeschnittener/gekappter/fehlerhafter/unerwartet kleiner Ausgabe | mehreren gleichnamigen Symbolen | einer Folgerung, die Architektur aendert, Code loescht, einen Carrier mintet oder Doktrin schafft. 0 Treffer beweist NICHTS: nicht "hat keine Consumer", sondern "die Suche fand keine Kandidaten" -- ein globales Negativ braucht einen GESCHLOSSENEN, ausdruecklich benannten Suchraum. Und: eine Suche darf nie das LETZTE Tool-Ergebnis vor einer architektonischen Schlussfolgerung sein. Gesetz: .claude/knowledge/FIRST-HAND-SOURCE-LAW.md' # Destructive-prepend guard (operator directive, 2026-08-30, after # open(p, "w").write(entry + open(p).read()) truncated PR_ARC_INVENTORY.md @@ -39,6 +39,35 @@ emit_prepend() { '{hookSpecificOutput: {hookEventName: "PreToolUse", additionalContext: $c}}' } +# A numeric slice of a SOURCE file is the one artifact with no semantic +# boundary: `head -100 foo.rs` can stop just before the decisive `impl`, +# `tail` can separate a definition from its invariant, and `sed -n '120,180p'` +# looks precise while being an arbitrary cut. FIRST-HAND SOURCE LAW rule 3. +# +# Scoped to SOURCE INSPECTION, deliberately: limiting a non-search command's +# output (`cargo test 2>&1 | tail -30`) is REQUIRED elsewhere in this fleet +# (the guarded-executor tail-30 discipline) and is not what fabricates a +# false semantic boundary. A deny that fires on every build command would be +# worked around within the hour and would then guard nothing. +SLICE_DENY='VERBOTEN (FIRST-HAND SOURCE LAW, Regel 3): sed/head/tail/awk auf eine QUELLDATEI. Eine numerische Scheibe hat keine semantische Grenze -- `head -100 x.rs` endet womoeglich direkt vor dem entscheidenden impl, `tail` trennt Definition und Invariante, `sed -n 120,180p` sieht praezise aus und ist ein willkuerlicher Schnitt. Stattdessen: Grep/Glob lokalisiert das Symbol, dann Read auf das VOLLSTAENDIGE semantische Element (und bei Teilausgabe vom exakten naechsten Offset weiterlesen, niemals die ungesehene Mitte erraten). Output-Limitierung eines Nicht-Such-Kommandos (cargo ... | tail -30) bleibt erlaubt. Gesetz: .claude/knowledge/FIRST-HAND-SOURCE-LAW.md' + +# Capping a SEARCH result is how a truncated result set masquerades as a +# complete one -- the shape behind every "no consumer" claim in this repo's +# correction history. The Grep tool's own `head_limit` reports the cap; +# `| head` hides it. +CAP_DENY='VERBOTEN (FIRST-HAND SOURCE LAW, Regel 9): eine SUCHE in head/tail/sed/awk pipen. Das kappt eine Beweismenge und laesst ein abgeschnittenes Ergebnis wie ein vollstaendiges aussehen -- genau die Form hinter jeder "kein Consumer"-Behauptung in der Korrekturgeschichte dieses Repos. Stattdessen: das Grep-Tool mit `head_limit` (das die Kappung MELDET), oder ungekappt suchen und den Suchraum benennen. Gesetz: .claude/knowledge/FIRST-HAND-SOURCE-LAW.md' + +emit_deny() { + jq -n --arg c "$1" \ + '{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: $c}}' +} + +# Source/config extensions only. Scratch and temp outputs are not source, so +# `head -1 /tmp/out.txt` is none of this hook's business. +SRC_EXT='\.(rs|toml|lock|md|py|c|cc|cpp|h|hpp|java|kt|ts|tsx|js|mjs|json|ya?ml|sql|proto|sh|surql|ttl)' +SEARCH_CMD='(grep|rg|ugrep|egrep|fgrep|find|fd|ls)' +SLICER='(sed|head|tail|awk)' + case "$tool" in Grep) emit @@ -53,7 +82,18 @@ case "$tool" in emit_prepend # Match grep/rg/sed/tail/head as a command word (start, or after a # pipe/semicolon/&&/whitespace), not as a substring of another word. - elif printf '%s' "$cmd" | grep -Eq '(^|[|&;]|[[:space:]])(grep|rg|sed|tail|head)([[:space:]]|$)'; then + # DENY 1 -- a slicer whose argument list names a source file, and which is + # not reading from a pipe. `cmd` is split on pipes so `cargo x | tail -30` + # is judged on the `tail -30` segment alone (no file argument -> allowed). + elif printf '%s' "$cmd" | tr '|;' '\n\n' \ + | grep -Eq "(^|[[:space:]])$SLICER([[:space:]]+-[^[:space:]]+)*[[:space:]]+([^[:space:]]*[[:space:]]+)*[^[:space:]]*$SRC_EXT([[:space:]]|$)"; then + emit_deny "$SLICE_DENY" + # DENY 2 -- a search piped into a slicer: the cap that hides itself. + elif printf '%s' "$cmd" \ + | grep -Eq "(^|[|&;]|[[:space:]])$SEARCH_CMD([[:space:]]|$).*\\|[[:space:]]*$SLICER([[:space:]]|$)"; then + emit_deny "$CAP_DENY" + # Otherwise: non-blocking injection, as before. + elif printf '%s' "$cmd" | grep -Eq '(^|[|&;]|[[:space:]])(grep|rg|ugrep|sed|tail|head|awk)([[:space:]]|$)'; then emit fi ;; diff --git a/.claude/hooks/tests/anti-pattern-matching.test.sh b/.claude/hooks/tests/anti-pattern-matching.test.sh new file mode 100755 index 000000000..e6795f405 --- /dev/null +++ b/.claude/hooks/tests/anti-pattern-matching.test.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# Two-sided test for .claude/hooks/anti-pattern-matching.sh. +# +# A guard that cannot fire and a guard that fires on everything are equally +# useless, so every case below is asserted in BOTH directions: the DENY rows +# prove the guard bites, the INJECT/SILENT rows prove it discriminates. +# +# Run: bash .claude/hooks/tests/anti-pattern-matching.test.sh +# Exit: 0 all green, 1 any mismatch. +# +# Disable-verified (2026-09-20): removing the DENY-1 branch turns all five +# source-slice rows INJECT; removing DENY-2 turns all three capped-search rows +# INJECT. Re-run those two disables after any edit to the regexes. +set -uo pipefail +cd "$(dirname "$0")/../../.." || exit 1 +HOOK=.claude/hooks/anti-pattern-matching.sh +fails=0 + +classify() { + printf '%s' "{\"tool_name\":\"$1\",\"tool_input\":{\"command\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$2")}}" \ + | bash "$HOOK" | python3 -c ' +import json,sys +raw = sys.stdin.read().strip() +if not raw: + print("SILENT"); raise SystemExit +o = json.loads(raw)["hookSpecificOutput"] +print("DENY" if o.get("permissionDecision") == "deny" else "INJECT")' +} + +t() { + local want="$1" cmd="$2" got + got="$(classify Bash "$cmd")" + if [ "$got" = "$want" ]; then + printf ' ok %-7s %s\n' "$got" "$cmd" + else + printf ' FAIL want=%s got=%s %s\n' "$want" "$got" "$cmd" + fails=$((fails + 1)) + fi +} + +echo '### DENY -- a numeric slice of a SOURCE file (law rule 3)' +t DENY "head -100 crates/lance-graph-quack/src/lib.rs" +t DENY "sed -n '120,180p' Cargo.toml" +t DENY "tail -20 .claude/board/ISSUES.md" +t DENY "awk '/impl/' crates/foo/src/main.rs" +t DENY "sed -i 's/a/b/' Cargo.toml" + +echo '### DENY -- a SEARCH capped by a slicer (law rule 9)' +t DENY "grep -rn CallMask crates/ | head -20" +t DENY "rg -l CallMask | head" +t DENY "find . -name '*.rs' | head -5" + +echo '### ALLOW -- output limiting of a NON-search command (the tail-30 discipline)' +t INJECT "cargo test 2>&1 | tail -30" +t INJECT "cargo build --release | head -5" +t INJECT "head -1 /tmp/out.err" + +echo '### ALLOW -- ordinary search: navigation is legitimate, injection only' +t INJECT "grep -rn CallMask crates/" +t INJECT "rg -l 'impl ClassView' crates/" + +echo '### SILENT -- nothing to say' +t SILENT "ls crates/" +t SILENT "git log --oneline -1" +t SILENT "cargo test -p ogar-r2il --lib" + +echo '### the Grep TOOL always carries the law' +got="$(classify Grep '')" +if [ "$got" = "INJECT" ]; then printf ' ok %-7s %s\n' "$got" "(Grep tool)"; else + printf ' FAIL want=INJECT got=%s (Grep tool)\n' "$got"; fails=$((fails + 1)); fi + +echo +if [ "$fails" -eq 0 ]; then echo "ALL PASSED"; else echo "$fails FAILED"; fi +exit $((fails > 0)) From a9d66d566a86e40c8e9d0f789d23c7838f6af1fa Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:40:34 +0000 Subject: [PATCH 05/19] knowledge+hooks: FIRST-HAND SOURCE LAW -- search disarmed epistemically Operator ruling 2026-09-20, sharpening the 2026-07-21 anti-pattern-matching directive (PR #793, issued after code was DELETED having been only pattern-matched). That directive said "do not act on a match before a full Read" and did not stop the failure that followed, because the failure was not about ACTING -- it was about CLAIMING. The two shapes this kills: SEARCH HIT -> snippet -> meaning assumed -> architecture asserted SEARCH = 0 -> "it does not exist" The second is worse and no tool reports it as an error. Operator's diagnosis: ~20% tool drift, ~80% weak evidence gates. More shell prohibitions treat the 20%; disarming search epistemically treats the 80%. Fifteen rules, the auto-deepen trigger list, the zero-hit protocol, the PAGING LAW (a partial Read is not evidence for a whole-file claim; never skip pages, never jump to the tail, never infer the unseen middle), and the delegation/escalation levels 0-4 with a BIDIRECTIONAL rule -- Opus that discovers 37 mechanical caller reads delegates them rather than burning its context, since that burn is itself a cause of thin evidence. Above all of them: CONTEXT EXHAUSTION MUST REDUCE SCOPE, NEVER EVIDENCE QUALITY. When "reading all the callers will not fit", the answers are shard or report PARTIAL -- never "grep found 3, probably there are no others". MECHANICAL HALF. The hook already existed and fires on the right tools, so it was EXTENDED rather than duplicated (a second PreToolUse on the same matcher would double-inject). Two new DENY branches beside the existing injection: - a slicer (sed/head/tail/awk) whose argument list names a SOURCE file - a SEARCH (grep/rg/ugrep/find/fd/ls) piped into a slicer Both disable-verified: removing the first branch turns all five source-slice rows DENY -> INJECT, removing the second turns all three capped-search rows. 17 cases, both directions, committed as `.claude/hooks/tests/anti-pattern-matching.test.sh` -- a hook without a test rots exactly like an excluded crate without a CI line. SCOPE CORRECTION, stated because it departs from the instruction. The instruction was "sed/head/tail komplett verbieten, nicht einmal zum Reinschauen". Implemented as the law text's OWN wording -- prohibited for SOURCE INSPECTION -- not as a blanket ban, because `cargo test 2>&1 | tail -30` is REQUIRED elsewhere in this fleet (the guarded-executor tail-30 discipline) and a deny that fires on every build command is worked around within the hour. The line drawn matches the stated harm: a numeric slice of a FILE has no semantic boundary; limiting a non-search command's OUTPUT does not fabricate one. TWO THINGS DELIBERATELY NOT BUILT, recorded with their constraint rather than left as gaps. (1) Read-truncation is prose, not a guard: a PostToolUse(Read) hook would have to match whatever marker the Read tool emits, and that marker was NOT verified in this session -- a guard keyed to a guessed string cannot fire, which this workspace forbids on its own terms. (2) A persistent SEARCH_UNRESOLVED marker needs session-scoped state these stateless hooks do not have. The Claude Code tooling premises (embedded ugrep/bfs on native builds, the 2026-09-19 Grep/Glob fixes, Read's ~25k page limit) are ATTRIBUTED to the operator and explicitly not independently verified here. Every rule is keyed to what a tool RESULT says -- zero hits, truncated, partial -- never to a version or a constant, so none of them stops firing when a constant moves. OGAR's weaker shell rule is superseded in place, pointing here. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/knowledge/FIRST-HAND-SOURCE-LAW.md | 339 +++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 .claude/knowledge/FIRST-HAND-SOURCE-LAW.md diff --git a/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md b/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md new file mode 100644 index 000000000..68bd5a87f --- /dev/null +++ b/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md @@ -0,0 +1,339 @@ +# First-hand source law — search is navigation, never evidence + +> READ BY: every session, before the first Grep/Glob/Bash-search of a task. +> Enforced (partly) by `.claude/hooks/anti-pattern-matching.sh`; tested by +> `.claude/hooks/tests/anti-pattern-matching.test.sh`. +> +> Operator ruling 2026-09-20, sharpening the 2026-07-21 anti-pattern-matching +> directive (PR #793, issued after code was DELETED having been only +> pattern-matched, never read). That directive said "do not act on a match +> before a full Read". It did not stop the failure that followed, because the +> failure was not about acting — it was about **claiming**. + +## 0. The two shapes this exists to kill + +```text +SEARCH HIT -> snippet read -> meaning assumed -> architecture asserted + +SEARCH = 0 -> "it does not exist" +``` + +The second is the worse one, and it is the one no tool reports as an error. + +The diagnosis the operator recorded: roughly **20 % tool drift, 80 % weak +evidence gates**. Stacking more shell prohibitions treats the 20 %. This +document disarms search epistemically, which is the 80 %. + +> **Premise, attributed and NOT independently verified here:** the operator +> reports that Claude Code's 2026 releases changed the search tooling surface +> (embedded ugrep/bfs behind the Bash path on some native builds), that +> releases around 2026-09-19 fixed cases where Grep/Glob could look like "no +> matches" under large search spaces or resource errors, and that Read now +> carries a page limit (~25k tokens) with partial views. This document does +> not depend on those specifics — every rule below is keyed to what a tool +> RESULT says (zero hits, truncated, partial), never to a version number or a +> constant. That is deliberate: a rule pinned to an unverified constant is a +> rule that stops firing the day the constant moves. + +## 1. THE LAW + +```text +FIRST-HAND SOURCE LAW + + 1. Search is navigation, never evidence. + 2. grep/rg/ugrep/Glob may locate candidate files/symbols only. + 3. sed/head/tail/awk are prohibited for source inspection. + 4. Every load-bearing claim requires a first-hand Read of the defining item. + 5. Caller claims require reading the relevant callers. + 6. Cross-crate claims require reading manifests + both sides of the seam. + 7. Search = 0 proves nothing. + 8. Global negatives require a CLOSED and explicitly named search space. + 9. Truncated/partial/error/capped search automatically triggers deeper + inspection. +10. Traits/macros/re-exports/generated/feature-gated code automatically + trigger deeper inspection. +11. Search snippets may never be cited as semantic authority. +12. No architectural ruling may immediately follow a Search operation. +13. Read tests/falsifiers before promoting behaviour into a contract. +14. If the evidence remains incomplete, write UNKNOWN / OPEN. +15. Deletion beats a guessed replacement. +``` + +### What search may and may not establish + +```text +MAY: "candidate locations are X, Y, Z" + +MAY NOT: what a type means + what a function guarantees + that a consumer does not exist + that a mechanism is unused + that a repository has no implementation + architectural ownership + caller semantics + dependency direction +``` + +### Rule 12, as the mechanical form of the whole law + +> **A search must never be the last tool result before an architectural +> conclusion.** + +If the most recent evidence came from a search, at least one Read must follow +before the claim is written. This is the one rule short enough to actually be +obeyed under pressure, and it implies most of the others. + +## 2. AUTO-DEEPEN — the session must escalate, not answer + +Deepen automatically if ANY of these holds: + +```text + 1. search returned zero hits AND you are about to claim absence + 2. the claim contains: none / no consumer / unused / never / only / + all / every / not implemented + 3. the only basis is a search snippet + 4. the symbol is a trait, macro, generated, re-export, alias, or + feature-gated + 5. the claim crosses a crate or repository boundary + 6. the search output was truncated, capped, errored, partial, or + unusually small for the expected search space + 7. several implementations or similarly named symbols exist + 8. the conclusion would change architecture, delete code, mint a + carrier, or create doctrine +``` + +### After every relevant hit + +```text +READ the complete defining item +READ its enclosing contract / module docs +READ the direct callers / consumers relevant to the claim +READ the relevant tests / falsifiers + -> only then may a claim be written +``` + +### The zero-hit protocol + +```text +search "foo" -> 0 + +NOT: "foo has no consumers" +BUT: "the search found no candidates" + +then: enumerate the relevant source files + search aliases and re-exports + search trait-method call sites + search feature-gated modules + inspect the manifests + inspect generated paths where applicable + +only with a CLOSED search space: + "no consumer found in " +``` + +Measured instances of rule 7 failing in this fleet are on the board: +a `CapabilityAuthority` impl written fully-qualified so `impl.*Trait` missed +it; a seam declared "unwired both directions" where the correct grep supported +a false conclusion because the file that explained it was never opened. +**A correct grep can support a false conclusion.** + +## 3. PAGING LAW — a partial Read is not evidence for a whole-file claim + +```text +PAGING LAW + +A partial Read is not evidence for a whole-file claim. + +If Read truncates or reports a continuation: + MUST continue from the returned next offset/page until one of + a) the complete semantic item is read + b) the complete relevant section is read + c) the scope is EXPLICITLY narrowed and the claim narrowed with it + +Never skip pages. +Never jump to the tail. +Never infer the unseen middle. +``` + +And the mechanical guard, simple enough to be followed: + +> **No WHOLE-FILE / ALL-CALLERS / NO-CONSUMERS claim may be emitted while any +> relevant Read is marked PARTIAL.** + +A huge file does not oblige a full read. If the claim concerns `impl CallMask`, +the obligation is: locate the impl → Read the COMPLETE impl → callers → tests. +Not 200k tokens of surrounding documentation. **Narrow the scope, never the +evidence.** + +## 4. The one rule above all the others + +> **Context exhaustion must reduce scope, never evidence quality.** + +When a session notices "reading all the callers will not fit", the permitted +responses are to SHARD the census or to report PARTIAL / UNKNOWN. The +forbidden response is the cheap one: + +```text +grep -> 3 hits -> "probably there are no others" +``` + +## 5. Delegation and escalation + +Volume and ambiguity are different problems with different answers: + +```text +too much VOLUME -> shard mechanically +too much AMBIGUITY -> escalate intelligence +too little EVIDENCE -> stop +``` + +### Levels + +```text +LEVEL 0 main session navigation + architectural synthesis +LEVEL 1 Sonnet worker bounded mechanical census +LEVEL 2 Sonnet shards large but separable census +LEVEL 3 Opus / main contradictions, cross-repo seams, architecture +LEVEL 4 stop for operator genuinely underdetermined semantic decision +``` + +### Auto-delegate when + +```text +> ~25k-40k tokens of contiguous relevant material +> ~10-15 relevant files +> 2+ repositories requiring a mechanical census + an exhaustive caller/test inventory + repeated same-shaped verification over many files +``` + +A worker gets a CLOSED evidence task, never an architectural question: + +```text +Worker A: enumerate every CallMask producer and consumer. Read each + defining item and each direct caller. Return file / symbol / + role / evidence / uncertainty. NO architectural conclusion. +Worker B: enumerate every mask-algebra implementation. Diff operation + sets and tail semantics. NO recommendation. +Worker C: inspect cargo dependency paths and package identities. + Return the exact dependency DAG. NO redesign. +``` + +### A worker must STOP+ESCALATE, never improvise + +```text +STATUS: ESCALATE if + evidence conflicts + two plausible architectural interpretations remain + a global negative is required + cross-repo ownership is unclear + deleting or minting a type is being considered + a new semantic contract would be needed + the docs disagree with the executable code + caller behaviour cannot be inferred mechanically + the task exceeds the assigned shard + more than a couple of unexpected branches appear +``` + +Report shape: + +```text +STATUS: ESCALATE +Observed: ... +Unresolved fork: A ... B ... +Evidence needed: ... +Files already read: ... +``` + +### Escalation is BIDIRECTIONAL + +```text +Opus discovers "this is actually 37 mechanical caller reads" + -> delegate to Sonnet + -> receive evidence tables + -> Opus synthesises +``` + +Otherwise the expensive agent burns its context on grindwork — which is itself +a cause of thin evidence, not merely a cost. + +### The flow + +```text + SEARCH + | + v + scope identified + | + +----------+-----------+ + | | + small / semantic large / mechanical + | | + v v + main / Opus Sonnet shard(s) + | | + | evidence ONLY + +----------+-----------+ + v + synthesis / gate + | + ambiguity? + no | yes + v | v + land | Opus / operator +``` + +## 6. Enforcement — what is mechanical and what is not + +`.claude/hooks/anti-pattern-matching.sh` (`PreToolUse(Grep|Bash)`): + +| behaviour | trigger | +|---|---| +| **DENY** | a slicer (`sed`/`head`/`tail`/`awk`) whose argument list names a SOURCE/config file — rule 3 | +| **DENY** | a SEARCH (`grep`/`rg`/`ugrep`/`find`/`fd`/`ls`) piped into a slicer — the cap that hides itself, rule 9 | +| **INJECT** | the Grep tool, and any other search-shaped Bash command — the law summary + the auto-deepen triggers | +| **INJECT** | the destructive-prepend rule (pre-existing, separate law) | +| silent | everything else | + +Both DENY branches are disable-verified (remove the branch, the corresponding +rows of the test go from DENY to INJECT); the test is committed and runs in +one second. + +### The scope correction, stated because it departs from the instruction + +The instruction was *"sed/head/tail komplett verbieten, nicht einmal zum +Reinschauen"*. Implemented as the LAW TEXT's own wording — **prohibited for +source inspection** — and not as a blanket ban, for a measured reason: +`cargo test 2>&1 | tail -30` is REQUIRED elsewhere in this fleet (the +guarded-executor tail-30 output discipline). A deny that fires on every build +command is worked around within the hour and then guards nothing. The line the +hook draws is the one that matches the stated harm: a numeric slice of a +**file** has no semantic boundary; limiting a non-search command's **output** +does not fabricate one. + +### What is deliberately NOT hooked, and why + +**Read truncation.** The paging law above is prose, not a guard. A +`PostToolUse(Read)` hook could detect a partial read and inject §3 — but it +would have to match whatever marker the Read tool emits, and that marker was +NOT verified in this session. A guard keyed to a guessed string is a guard +that cannot fire, which this workspace forbids on its own terms. Closing it +requires reading one real truncated Read result first; until then the rule is +carried by §3 and by rule 14. + +**A `SEARCH_UNRESOLVED` marker** that persists until a deeper Read clears it +was proposed and is not built: hooks here are stateless per invocation, so the +marker needs a session-scoped store that does not exist yet. Recorded so the +next attempt starts from the constraint rather than rediscovering it. + +## 7. Anti-patterns, each with the right shape + +| anti-pattern | right shape | +|---|---| +| `rg X \| head -20` then "these are the call sites" | Grep tool with `head_limit` (it REPORTS the cap), or an uncapped search plus a named search space | +| `sed -n '1,80p' foo.rs` to "get the gist" | locate the symbol, Read the complete item | +| 0 hits → "no consumer" | "no candidates found"; then close the search space, then claim | +| a snippet quoted as what a type means | Read the defining item and its module docs | +| "reading every caller will not fit" → guess | shard the census, or report PARTIAL | +| worker meets ambiguity → picks one reading | STATUS: ESCALATE with the fork named | +| a wrong claim corrected by a prettier wrong claim | write UNKNOWN / OPEN (rule 14/15) | From 7c753e9dea5f3b4785896f9f05595ee89344fc14 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:46:42 +0000 Subject: [PATCH 06/19] hooks+law: authority-label guard (pre-disable checkpoint) --- .claude/hooks/anti-pattern-matching.sh | 39 ++ .../hooks/tests/anti-pattern-matching.test.sh | 50 +++ .claude/knowledge/FIRST-HAND-SOURCE-LAW.md | 413 ++++++------------ .claude/settings.json | 4 +- 4 files changed, 235 insertions(+), 271 deletions(-) diff --git a/.claude/hooks/anti-pattern-matching.sh b/.claude/hooks/anti-pattern-matching.sh index fbd61cb2a..28b372a9b 100755 --- a/.claude/hooks/anti-pattern-matching.sh +++ b/.claude/hooks/anti-pattern-matching.sh @@ -66,12 +66,51 @@ emit_deny() { # `head -1 /tmp/out.txt` is none of this hook's business. SRC_EXT='\.(rs|toml|lock|md|py|c|cc|cpp|h|hpp|java|kt|ts|tsx|js|mjs|json|ya?ml|sql|proto|sh|surql|ttl)' SEARCH_CMD='(grep|rg|ugrep|egrep|fgrep|find|fd|ls)' + +# FIRST-HAND SOURCE LAW §G: human authorization is PROVENANCE, NOT VALIDATION. +# These four are not technical status labels, so an edit may not INTRODUCE one +# into canonical material. Scoped to introduction deliberately: they occur in +# 73 / 43 / 8 / 4 files respectively (measured 2026-09-20), and a guard that +# fired on every edit to a file that already contains one would be unusable +# and worked around. Historical files are not this hook's business. +AUTHORITY_LABELS='operator-ruled|operator-pinned|operator-locked|operator-confirmed' +# A supersession note must be able to QUOTE the label it retires, so a line +# that also carries a quoting/supersession marker is allowed through. +QUOTE_MARKER='⊘|SUPERSEDED|superseded|previously|historical|formerly|was:' +AUTHORITY_DENY='VERBOTEN (FIRST-HAND SOURCE LAW §G): operator-ruled / operator-pinned / operator-locked / operator-confirmed sind KEINE technischen Status-Labels. HUMAN AUTHORIZATION IS PROVENANCE, NOT VALIDATION -- "der Nutzer hat X gewaehlt" wird nie "X ist technisch wahr" ohne unabhaengige Evidenz. Stattdessen ein evidenztragender Zustand: MEASURED (mit dem Kommando) | VERIFIED-IN-CODE (mit der Stelle) | TEST-PINNED | CURRENT-CONTRACT | WORKING-MODEL | HYPOTHESIS | PROPOSED | OPEN | DEFERRED | SUPERSEDED | REJECTED-BY-FALSIFIER. Fuer eine echte Nutzer-Entscheidung das Entscheidungs-Format: DECISION / SCOPE / BASIS / REVISIT WHEN -- Entscheidung und Messung sind zwei Felder, nie ein Label. Eine Supersession-Notiz DARF das alte Label zitieren (Zeile mit "⊘" / SUPERSEDED / previously / formerly / was:). Gesetz: .claude/knowledge/FIRST-HAND-SOURCE-LAW.md' + +# True when $1 contains a line that introduces an authority label WITHOUT a +# quoting marker on that same line. +introduces_authority_label() { + printf '%s' "$1" | grep -Ei "$AUTHORITY_LABELS" | grep -Eviq "$QUOTE_MARKER" +} SLICER='(sed|head|tail|awk)' case "$tool" in Grep) emit ;; + Edit) + # Only canonical prose/source carries these labels; skip anything else. + path="$(printf '%s' "$input" | jq -r '.tool_input.file_path // ""')" + if printf '%s' "$path" | grep -Eq '\.(md|rs)$'; then + new="$(printf '%s' "$input" | jq -r '.tool_input.new_string // ""')" + old="$(printf '%s' "$input" | jq -r '.tool_input.old_string // ""')" + # INTRODUCTION only: the label must be arriving, not already present. + if introduces_authority_label "$new" && ! printf '%s' "$old" | grep -Eiq "$AUTHORITY_LABELS"; then + emit_deny "$AUTHORITY_DENY" + fi + fi + ;; + Write) + path="$(printf '%s' "$input" | jq -r '.tool_input.file_path // ""')" + if printf '%s' "$path" | grep -Eq '\.(md|rs)$'; then + content="$(printf '%s' "$input" | jq -r '.tool_input.content // ""')" + if introduces_authority_label "$content"; then + emit_deny "$AUTHORITY_DENY" + fi + fi + ;; Bash) cmd="$(printf '%s' "$input" | jq -r '.tool_input.command // ""')" # Destructive-prepend shape: an open-for-write and a .read() of a file in diff --git a/.claude/hooks/tests/anti-pattern-matching.test.sh b/.claude/hooks/tests/anti-pattern-matching.test.sh index e6795f405..ce896d84d 100755 --- a/.claude/hooks/tests/anti-pattern-matching.test.sh +++ b/.claude/hooks/tests/anti-pattern-matching.test.sh @@ -64,6 +64,56 @@ t SILENT "ls crates/" t SILENT "git log --oneline -1" t SILENT "cargo test -p ogar-r2il --lib" +# ---- §G: authority labels may not be INTRODUCED into canonical material ---- +edit() { + local want="$1" path="$2" old="$3" new="$4" got + got="$(printf '%s' "{\"tool_name\":\"Edit\",\"tool_input\":{\"file_path\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$path"),\"old_string\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$old"),\"new_string\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$new")}}" \ + | bash "$HOOK" | python3 -c ' +import json,sys +raw = sys.stdin.read().strip() +if not raw: + print("SILENT"); raise SystemExit +o = json.loads(raw)["hookSpecificOutput"] +print("DENY" if o.get("permissionDecision") == "deny" else "INJECT")')" + if [ "$got" = "$want" ]; then printf ' ok %-7s %s\n' "$got" "$5" + else printf ' FAIL want=%s got=%s %s\n' "$want" "$got" "$5"; fails=$((fails + 1)); fi +} +write() { + local want="$1" path="$2" content="$3" got + got="$(printf '%s' "{\"tool_name\":\"Write\",\"tool_input\":{\"file_path\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$path"),\"content\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$content")}}" \ + | bash "$HOOK" | python3 -c ' +import json,sys +raw = sys.stdin.read().strip() +if not raw: + print("SILENT"); raise SystemExit +o = json.loads(raw)["hookSpecificOutput"] +print("DENY" if o.get("permissionDecision") == "deny" else "INJECT")')" + if [ "$got" = "$want" ]; then printf ' ok %-7s %s\n' "$got" "$4" + else printf ' FAIL want=%s got=%s %s\n' "$want" "$got" "$4"; fails=$((fails + 1)); fi +} + +echo '### DENY -- an edit that INTRODUCES an authority label (law §G)' +edit DENY x.md "Status: WORKING-MODEL" "Status: operator-ruled" "introduce operator-ruled" +edit DENY x.md "the pin" "the operator-locked pin" "introduce operator-locked" +write DENY n.md "# New + +Status: operator-pinned, 2026-09-20. +" "new file with operator-pinned" + +# An ALLOWED Edit/Write emits nothing: injection is a Grep/Bash-only +# behaviour, so "allowed" reads as SILENT here, never INJECT. +echo '### ALLOW (silent) -- label already present, or quoted by a supersession note' +edit SILENT x.md "operator-ruled 2026-07-02" "operator-ruled 2026-07-02, now measured" "already present: not an introduction" +edit SILENT x.md "the rule" "⊘ previously operator-locked; now TEST-PINNED" "quoted under a supersession marker" +edit SILENT x.md "a" "SUPERSEDED: the operator-confirmed wording" "quoted under SUPERSEDED" + +echo '### ALLOW -- an evidence-bearing state is the whole point' +edit SILENT x.md "Status: OPEN" "Status: MEASURED (cargo metadata, exit 0)" "MEASURED" +edit SILENT x.md "a" "DECISION: keep path form\nBASIS: offline cost" "DECISION record" + +echo '### ALLOW -- not canonical prose/source' +write SILENT c.json '{"k":"operator-ruled"}' "json is out of scope" + echo '### the Grep TOOL always carries the law' got="$(classify Grep '')" if [ "$got" = "INJECT" ]; then printf ' ok %-7s %s\n' "$got" "(Grep tool)"; else diff --git a/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md b/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md index 68bd5a87f..bddfd4bdf 100644 --- a/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md +++ b/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md @@ -1,339 +1,214 @@ -# First-hand source law — search is navigation, never evidence +# First-hand source law — search finds, read proves -> READ BY: every session, before the first Grep/Glob/Bash-search of a task. -> Enforced (partly) by `.claude/hooks/anti-pattern-matching.sh`; tested by -> `.claude/hooks/tests/anti-pattern-matching.test.sh`. +> READ BY: every session before its first search of a task; every +> orchestrator writing a worker brief. > -> Operator ruling 2026-09-20, sharpening the 2026-07-21 anti-pattern-matching -> directive (PR #793, issued after code was DELETED having been only -> pattern-matched, never read). That directive said "do not act on a match -> before a full Read". It did not stop the failure that followed, because the -> failure was not about acting — it was about **claiming**. - -## 0. The two shapes this exists to kill - -```text -SEARCH HIT -> snippet read -> meaning assumed -> architecture asserted - -SEARCH = 0 -> "it does not exist" -``` - -The second is the worse one, and it is the one no tool reports as an error. - -The diagnosis the operator recorded: roughly **20 % tool drift, 80 % weak -evidence gates**. Stacking more shell prohibitions treats the 20 %. This -document disarms search epistemically, which is the 80 %. +> Scope: what may be CLAIMED from which operation, and how a human decision +> is recorded. It deliberately owns nothing else. +> +> Not duplicated here: the agent tiers and the one-writer rule +> (`tiered-agent-execution-protocol.md`), the worker iron rules and +> STOP+escalate triggers (`.claude/v3/knowledge/sonnet-worker-guardrails.md` +> §1/§5). This file is cited from both; it does not restate them. -> **Premise, attributed and NOT independently verified here:** the operator -> reports that Claude Code's 2026 releases changed the search tooling surface -> (embedded ugrep/bfs behind the Bash path on some native builds), that -> releases around 2026-09-19 fixed cases where Grep/Glob could look like "no -> matches" under large search spaces or resource errors, and that Read now -> carries a page limit (~25k tokens) with partial views. This document does -> not depend on those specifics — every rule below is keyed to what a tool -> RESULT says (zero hits, truncated, partial), never to a version number or a -> constant. That is deliberate: a rule pinned to an unverified constant is a -> rule that stops firing the day the constant moves. +## A. Search is navigation, never evidence -## 1. THE LAW +Search, grep, rg, ugrep and Glob may establish exactly one thing: ```text -FIRST-HAND SOURCE LAW - - 1. Search is navigation, never evidence. - 2. grep/rg/ugrep/Glob may locate candidate files/symbols only. - 3. sed/head/tail/awk are prohibited for source inspection. - 4. Every load-bearing claim requires a first-hand Read of the defining item. - 5. Caller claims require reading the relevant callers. - 6. Cross-crate claims require reading manifests + both sides of the seam. - 7. Search = 0 proves nothing. - 8. Global negatives require a CLOSED and explicitly named search space. - 9. Truncated/partial/error/capped search automatically triggers deeper - inspection. -10. Traits/macros/re-exports/generated/feature-gated code automatically - trigger deeper inspection. -11. Search snippets may never be cited as semantic authority. -12. No architectural ruling may immediately follow a Search operation. -13. Read tests/falsifiers before promoting behaviour into a contract. -14. If the evidence remains incomplete, write UNKNOWN / OPEN. -15. Deletion beats a guessed replacement. +"candidate locations are X, Y, Z" ``` -### What search may and may not establish +They may NOT establish what a type or function means, architectural +ownership, caller semantics, dependency direction, or any global negative — +`unused`, `no consumers`, `not implemented`, `only`, `all`, `never`. + +A load-bearing claim requires first-hand reading of: ```text -MAY: "candidate locations are X, Y, Z" - -MAY NOT: what a type means - what a function guarantees - that a consumer does not exist - that a mechanism is unused - that a repository has no implementation - architectural ownership - caller semantics - dependency direction +the defining semantic item +enough enclosing contract/module context to interpret it +the direct callers/consumers the claim depends on +the tests/falsifiers that pin the behaviour ``` -### Rule 12, as the mechanical form of the whole law - -> **A search must never be the last tool result before an architectural -> conclusion.** +A cross-crate or cross-repo claim additionally requires the manifests +(dependency direction) and BOTH sides of the seam. -If the most recent evidence came from a search, at least one Read must follow -before the claim is written. This is the one rule short enough to actually be -obeyed under pressure, and it implies most of the others. +If the evidence stays incomplete, the answer is `UNKNOWN` / `OPEN` / +`PARTIAL` — never an inferred completion. -## 2. AUTO-DEEPEN — the session must escalate, not answer +### The one mechanical form of the whole rule -Deepen automatically if ANY of these holds: +> **A search result or snippet may never be the last evidence before an +> architectural conclusion.** ```text - 1. search returned zero hits AND you are about to claim absence - 2. the claim contains: none / no consumer / unused / never / only / - all / every / not implemented - 3. the only basis is a search snippet - 4. the symbol is a trait, macro, generated, re-export, alias, or - feature-gated - 5. the claim crosses a crate or repository boundary - 6. the search output was truncated, capped, errored, partial, or - unusually small for the expected search space - 7. several implementations or similarly named symbols exist - 8. the conclusion would change architecture, delete code, mint a - carrier, or create doctrine +FORBIDDEN: search output -> conclusion +REQUIRED: search -> locate -> READ the semantic unit + -> caller/test census where relevant -> conclusion ``` -### After every relevant hit +## B. Source inspection -```text -READ the complete defining item -READ its enclosing contract / module docs -READ the direct callers / consumers relevant to the claim -READ the relevant tests / falsifiers - -> only then may a claim be written -``` +For understanding source, `sed` / `head` / `tail` / `awk` are prohibited: +they produce an arbitrary textual slice rather than a semantic unit, so the +cut can fall anywhere — before the decisive `impl`, between a definition and +its invariant. -### The zero-hit protocol +`grep` / `rg` / `ugrep` are allowed as LOCATORS. What is prohibited is the +epistemic misuse, never the implementation: a search tool is not suspect +because some build routes it through Bash or ugrep internally. -```text -search "foo" -> 0 +Limiting a NON-search command's output (`cargo test 2>&1 | tail -30`) is not +source inspection and stays allowed. -NOT: "foo has no consumers" -BUT: "the search found no candidates" +## C. Auto-deepen -then: enumerate the relevant source files - search aliases and re-exports - search trait-method call sites - search feature-gated modules - inspect the manifests - inspect generated paths where applicable +Deepen before writing the claim if ANY of these holds: -only with a CLOSED search space: - "no consumer found in " +```text + 1. the search returned zero hits and an absence claim is contemplated + 2. the statement would use: none / no consumer / unused / never / + only / all / every / not implemented + 3. the basis is only a search snippet + 4. a trait, macro, re-export, generated or feature-gated item is involved + 5. the claim crosses a crate or repo boundary + 6. a search or read result was truncated, partial, capped, or errored + 7. several similarly-named implementations exist + 8. the conclusion would delete code, mint a carrier, define ownership, + change a contract, or become canonical documentation ``` -Measured instances of rule 7 failing in this fleet are on the board: -a `CapabilityAuthority` impl written fully-qualified so `impl.*Trait` missed -it; a seam declared "unwired both directions" where the correct grep supported -a false conclusion because the file that explained it was never opened. -**A correct grep can support a false conclusion.** +A zero-result search means `no candidates found by this search`, never `the +thing does not exist`. **A global negative requires an explicitly CLOSED +search space** — name the tool, the pattern and the scope, or phrase the +claim as "not found in \". -## 3. PAGING LAW — a partial Read is not evidence for a whole-file claim +## D. Paging -```text -PAGING LAW +A partial Read is not evidence for a whole-file or whole-section claim. -A partial Read is not evidence for a whole-file claim. +When the read surface reports continuation or truncation, continue from the +exact next offset/page until the relevant semantic item or section is +complete. Never first-page-plus-last-page and infer the middle. -If Read truncates or reports a continuation: - MUST continue from the returned next offset/page until one of - a) the complete semantic item is read - b) the complete relevant section is read - c) the scope is EXPLICITLY narrowed and the claim narrowed with it +Read semantic units, not byte ranges: a 200k-token file is not an obligation +when one complete `impl` is what the claim rests on. -Never skip pages. -Never jump to the tail. -Never infer the unseen middle. +```text +HARD GUARD: no WHOLE-FILE / ALL-CALLERS / NO-CONSUMERS claim + while a relevant read remains PARTIAL. ``` -And the mechanical guard, simple enough to be followed: - -> **No WHOLE-FILE / ALL-CALLERS / NO-CONSUMERS claim may be emitted while any -> relevant Read is marked PARTIAL.** - -A huge file does not oblige a full read. If the claim concerns `impl CallMask`, -the obligation is: locate the impl → Read the COMPLETE impl → callers → tests. -Not 200k tokens of surrounding documentation. **Narrow the scope, never the -evidence.** - -## 4. The one rule above all the others +## E. Context exhaustion > **Context exhaustion must reduce scope, never evidence quality.** -When a session notices "reading all the callers will not fit", the permitted -responses are to SHARD the census or to report PARTIAL / UNKNOWN. The -forbidden response is the cheap one: - -```text -grep -> 3 hits -> "probably there are no others" -``` +When the required evidence does not fit the session, the two permitted +moves are to SHARD the census or to report `PARTIAL` / `UNKNOWN`. Never +substitute a shallower search for required first-hand reading because +context is getting tight. -## 5. Delegation and escalation +## F. Delegation and escalation -Volume and ambiguity are different problems with different answers: +Volume and ambiguity are different problems: ```text -too much VOLUME -> shard mechanically -too much AMBIGUITY -> escalate intelligence -too little EVIDENCE -> stop +large VOLUME -> shard to grindwork workers +high AMBIGUITY -> the main/strong agent +insufficient EVIDENCE -> STOP ``` -### Levels +Delegate mechanical work automatically: an exhaustive caller census, 10+ +relevant files, ~25k-40k+ tokens of contiguous relevant material, repeated +same-shaped checks, multi-repo manifest inventory, a large test/falsifier +inventory. -```text -LEVEL 0 main session navigation + architectural synthesis -LEVEL 1 Sonnet worker bounded mechanical census -LEVEL 2 Sonnet shards large but separable census -LEVEL 3 Opus / main contradictions, cross-repo seams, architecture -LEVEL 4 stop for operator genuinely underdetermined semantic decision -``` - -### Auto-delegate when +A worker assignment is a CLOSED evidence task, never an architectural +question: ```text -> ~25k-40k tokens of contiguous relevant material -> ~10-15 relevant files -> 2+ repositories requiring a mechanical census - an exhaustive caller/test inventory - repeated same-shaped verification over many files +"Enumerate every CallMask producer/consumer. Read each relevant item. + Return file/symbol/role/evidence/uncertainty. + Make no architecture recommendation." ``` -A worker gets a CLOSED evidence task, never an architectural question: +Worker return shape: ```text -Worker A: enumerate every CallMask producer and consumer. Read each - defining item and each direct caller. Return file / symbol / - role / evidence / uncertainty. NO architectural conclusion. -Worker B: enumerate every mask-algebra implementation. Diff operation - sets and tail semantics. NO recommendation. -Worker C: inspect cargo dependency paths and package identities. - Return the exact dependency DAG. NO redesign. +STATUS: DONE | PARTIAL | ESCALATE +Observed: +Evidence: +Unresolved: +Files/semantic items read: +Search space closed? yes/no ``` -### A worker must STOP+ESCALATE, never improvise +The tiers themselves and the STOP+escalate trigger list are owned by the two +files named in the header; a worker follows those, not a second copy here. + +## G. Authority and evidence are different things ```text -STATUS: ESCALATE if - evidence conflicts - two plausible architectural interpretations remain - a global negative is required - cross-repo ownership is unclear - deleting or minting a type is being considered - a new semantic contract would be needed - the docs disagree with the executable code - caller behaviour cannot be inferred mechanically - the task exceeds the assigned shard - more than a couple of unexpected branches appear +HUMAN AUTHORIZATION IS PROVENANCE, NOT VALIDATION. ``` -Report shape: +A user may choose direction, scope, policy, naming, and acceptable risk. +`the user chose X` must never become `X is technically true` without +independent evidence. ```text -STATUS: ESCALATE -Observed: ... -Unresolved fork: A ... B ... -Evidence needed: ... -Files already read: ... +human decision != evidence + != technical truth + != correctness + != safety ``` -### Escalation is BIDIRECTIONAL +So in NEW canonical material these are not technical status labels and are +not used as one: `operator-ruled`, `operator-pinned`, `operator-locked`, +`operator-confirmed`. -```text -Opus discovers "this is actually 37 mechanical caller reads" - -> delegate to Sonnet - -> receive evidence tables - -> Opus synthesises -``` +Use an evidence-bearing state instead: -Otherwise the expensive agent burns its context on grindwork — which is itself -a cause of thin evidence, not merely a cost. +| state | means | +|---|---| +| `MEASURED` | a command produced this number; the command is named | +| `VERIFIED-IN-CODE` | read first-hand at a named location | +| `TEST-PINNED` | a test fails if this stops holding | +| `CURRENT-CONTRACT` | what the shipped types/signatures require today | +| `WORKING-MODEL` | in use, not yet falsified either way | +| `HYPOTHESIS` | stated so it can be tested | +| `PROPOSED` | not in force | +| `OPEN` / `DEFERRED` | unresolved, deliberately | +| `SUPERSEDED` | replaced; the replacement is named | +| `REJECTED-BY-FALSIFIER` | a measurement killed it | -### The flow +A real user decision is recorded as a decision, not as a proof: ```text - SEARCH - | - v - scope identified - | - +----------+-----------+ - | | - small / semantic large / mechanical - | | - v v - main / Opus Sonnet shard(s) - | | - | evidence ONLY - +----------+-----------+ - v - synthesis / gate - | - ambiguity? - no | yes - v | v - land | Opus / operator +DECISION: what was chosen +SCOPE: where it applies +BASIS: preference / risk tolerance / policy / cost — or the evidence +REVISIT WHEN: the condition that would reopen it ``` -## 6. Enforcement — what is mechanical and what is not +A decision and a measurement may coexist on one item; they are two fields, +never one label. -`.claude/hooks/anti-pattern-matching.sh` (`PreToolUse(Grep|Bash)`): +## Enforcement -| behaviour | trigger | -|---|---| -| **DENY** | a slicer (`sed`/`head`/`tail`/`awk`) whose argument list names a SOURCE/config file — rule 3 | -| **DENY** | a SEARCH (`grep`/`rg`/`ugrep`/`find`/`fd`/`ls`) piped into a slicer — the cap that hides itself, rule 9 | -| **INJECT** | the Grep tool, and any other search-shaped Bash command — the law summary + the auto-deepen triggers | -| **INJECT** | the destructive-prepend rule (pre-existing, separate law) | -| silent | everything else | - -Both DENY branches are disable-verified (remove the branch, the corresponding -rows of the test go from DENY to INJECT); the test is committed and runs in -one second. - -### The scope correction, stated because it departs from the instruction - -The instruction was *"sed/head/tail komplett verbieten, nicht einmal zum -Reinschauen"*. Implemented as the LAW TEXT's own wording — **prohibited for -source inspection** — and not as a blanket ban, for a measured reason: -`cargo test 2>&1 | tail -30` is REQUIRED elsewhere in this fleet (the -guarded-executor tail-30 output discipline). A deny that fires on every build -command is worked around within the hour and then guards nothing. The line the -hook draws is the one that matches the stated harm: a numeric slice of a -**file** has no semantic boundary; limiting a non-search command's **output** -does not fabricate one. - -### What is deliberately NOT hooked, and why - -**Read truncation.** The paging law above is prose, not a guard. A -`PostToolUse(Read)` hook could detect a partial read and inject §3 — but it -would have to match whatever marker the Read tool emits, and that marker was -NOT verified in this session. A guard keyed to a guessed string is a guard -that cannot fire, which this workspace forbids on its own terms. Closing it -requires reading one real truncated Read result first; until then the rule is -carried by §3 and by rule 14. - -**A `SEARCH_UNRESOLVED` marker** that persists until a deeper Read clears it -was proposed and is not built: hooks here are stateless per invocation, so the -marker needs a session-scoped store that does not exist yet. Recorded so the -next attempt starts from the constraint rather than rediscovering it. - -## 7. Anti-patterns, each with the right shape - -| anti-pattern | right shape | +Mechanical, in `.claude/hooks/anti-pattern-matching.sh` +(`PreToolUse(Grep|Bash|Edit|Write)`), tested by +`.claude/hooks/tests/anti-pattern-matching.test.sh`: + +| | | |---|---| -| `rg X \| head -20` then "these are the call sites" | Grep tool with `head_limit` (it REPORTS the cap), or an uncapped search plus a named search space | -| `sed -n '1,80p' foo.rs` to "get the gist" | locate the symbol, Read the complete item | -| 0 hits → "no consumer" | "no candidates found"; then close the search space, then claim | -| a snippet quoted as what a type means | Read the defining item and its module docs | -| "reading every caller will not fit" → guess | shard the census, or report PARTIAL | -| worker meets ambiguity → picks one reading | STATUS: ESCALATE with the fork named | -| a wrong claim corrected by a prettier wrong claim | write UNKNOWN / OPEN (rule 14/15) | +| DENY | a slicer (`sed`/`head`/`tail`/`awk`) whose argument list names a source/config file — §B | +| DENY | a search (`grep`/`rg`/`ugrep`/`find`/`fd`/`ls`) piped into a slicer — §C.6, the cap that hides itself | +| DENY | an edit that INTRODUCES one of the four authority labels — §G | +| INJECT | the law's summary + the §C triggers, on the Grep tool and on any search-shaped Bash command | + +Guidance-only, because no regex decides it: §A's "enough enclosing context", +§D's paging, §E's shard-or-report choice, §F's ambiguity judgement, and +whether a chosen state label in §G is the right one. diff --git a/.claude/settings.json b/.claude/settings.json index 2c2e9a742..4daae5a55 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -199,7 +199,7 @@ "hooks": { "PreToolUse": [ { - "matcher": "Grep|Bash", + "matcher": "Grep|Bash|Edit|Write", "hooks": [ { "type": "command", @@ -231,4 +231,4 @@ } ] } -} \ No newline at end of file +} From ad8000b3e2b1facdbf13825314482d34e3656a4a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:48:42 +0000 Subject: [PATCH 07/19] epistemic pass: one home for the source law; authority is not evidence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Census first. Four candidate homes read first-hand, and two of them already own most of what this pass needed: .claude/v3/knowledge/sonnet-worker-guardrails.md MANDATORY per worker §1/2 "grep locates; Read comprehends" §1/10 a global negative must name its search or say "not found in " §1/11 partial reported as partial §5 seven STOP+escalate triggers .claude/knowledge/tiered-agent-execution-protocol.md the three tiers (filigree / grindwork / guarded execution) ONE WRITER PER FILE CLAUDE.md P0 "grep FINDS, reading DECIDES" with a three-row measured table So no new canonical file. NET REDUCTION instead: FIRST-HAND-SOURCE-LAW.md 339 -> 214 lines, keeping only what nothing else owns (what may be CLAIMED from which operation, the auto-deepen triggers, paging, context exhaustion, authority-vs-evidence) and dropping what those two files own -- the tier model, the worker iron rules, and the narration/correction history that the brief's own rule H forbids. It now cites both instead of restating either; 0 hits for Haiku / guarded executor / ONE WRITER / WORKER IRON RULES. The other two files gained pointers and their MISSING mechanics, inside their existing structures, no new sections: guardrails §1/2 paging: continue from the exact next offset until the semantic item is COMPLETE; never first-page-plus-last-page; no whole-file claim while a read is PARTIAL guardrails §1/11 the return shape, incl. "Search space closed? yes/no", which cannot read "no" beside a global-negative claim guardrails §5 6b a global negative that cannot be mechanically closed 6c evidence that does not fit -> shard or PARTIAL, never a shallower search because context is tight CLAUDE.md one pointer (the measured table stays -- it is evidence, not restatement) plus §G, which had no home anywhere §G is the new invariant: HUMAN AUTHORIZATION IS PROVENANCE, NOT VALIDATION. A person chooses direction, scope, policy, naming, acceptable risk; "the user chose X" never becomes "X is technically true" without independent evidence. New canonical material therefore uses an evidence-bearing state (MEASURED with its command, VERIFIED-IN-CODE with its location, TEST-PINNED, CURRENT-CONTRACT, WORKING-MODEL, HYPOTHESIS, OPEN, SUPERSEDED, REJECTED-BY-FALSIFIER) and records a real decision as DECISION / SCOPE / BASIS / REVISIT WHEN -- two fields, never one label. MECHANICALLY ENFORCED (PreToolUse, matcher widened Grep|Bash -> +Edit|Write): DENY a slicer (sed/head/tail/awk) naming a source/config file DENY a search piped into a slicer (the cap that hides itself) DENY an edit that INTRODUCES one of the four authority labels INJECT the law summary + triggers on Grep and search-shaped Bash The authority guard is scoped to INTRODUCTION because the labels are already in 73 / 43 / 8 / 4 files (measured): a guard firing on every edit to a file that already contains one would be unusable and worked around. Historical wording is untouched, and a supersession note may QUOTE the label it retires (a line also carrying ⊘ / SUPERSEDED / previously / formerly / was:). Disable-verified both directions: neutering the detector turns the three introduction rows DENY -> SILENT; dropping the quote carve-out turns two allow rows SILENT -> DENY, so the carve-out is load-bearing, not decoration. 26 cases total, committed as the hook's test. GUIDANCE-ONLY, stated rather than pretended: "enough enclosing context", the paging judgement, shard-or-report, the ambiguity call, and whether a chosen state label is the right one. No regex decides those. NOT CHANGED, deliberately: the 73+ historical files carrying the labels (no mass edit); prose provenance like "(operator, 2026-09-16: )", which is attribution done correctly rather than a status label; the tier model and the worker iron rules in their own files; the shell rule's allowance for `cargo ... | tail -30`, which this fleet's guarded-executor contract requires. Gates: settings.json parses, hook syntax clean, 26/26 hook tests, supersession index regenerates byte-identical. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .../v3/knowledge/sonnet-worker-guardrails.md | 27 +++++++++++++++++-- CLAUDE.md | 23 ++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/.claude/v3/knowledge/sonnet-worker-guardrails.md b/.claude/v3/knowledge/sonnet-worker-guardrails.md index 0e6e59b00..ce80529d2 100644 --- a/.claude/v3/knowledge/sonnet-worker-guardrails.md +++ b/.claude/v3/knowledge/sonnet-worker-guardrails.md @@ -7,6 +7,11 @@ > every rule here is mechanical — no judgment calls required, ever. > If a worker hits a situation not covered by a rule below, the rule is: > **STOP and return the question; do not improvise.** +> +> The session-level epistemic rules these mechanics implement — what may be +> CLAIMED from which operation, the auto-deepen triggers, and the +> authority-vs-evidence separation — live in ONE place and are not restated +> here: `.claude/knowledge/FIRST-HAND-SOURCE-LAW.md`. ## Status: FINDING (operator directive 2026-07-02: "no foot gun at any time") @@ -20,7 +25,12 @@ WORKER IRON RULES (V3 workspace — mechanical, no exceptions): need another file, STOP and report; do not follow the thread. 2. READ FULLY: Read every file you will edit, entirely, before editing (offset/limit chunks for >2000 lines — ALL chunks). Never paraphrase - from grep/snippet output. grep locates; Read comprehends. + from grep/snippet output. grep locates; Read comprehends. If a read + reports truncation/continuation, continue from the exact next offset + until the relevant semantic item is COMPLETE — never first page plus + last page and infer the middle, and never a whole-file/all-callers + claim while a relevant read is still PARTIAL. sed/head/tail/awk are + prohibited for reading source: they cut text, not semantic units. 3. NO INVENTION: never mint a new struct/trait/enum/module. If the brief needs a type, it names the existing one. A "missing" type = STOP+report. 4. CLASSIDS: compose ONLY via contract::render_classid / compose_classid @@ -53,7 +63,13 @@ WORKER IRON RULES (V3 workspace — mechanical, no exceptions): or be phrased as "not found in ". 11. DONE = your diff + the named test/probe green + a report listing: files touched, searches run, anything you did NOT do. Partial work is - reported as partial, never as done. + reported as partial, never as done. Report shape: + STATUS: DONE | PARTIAL | ESCALATE + Observed: / Evidence: / Unresolved: + Files/semantic items read: + Search space closed? yes/no + "Search space closed? no" and a global-negative claim cannot both + appear in one report (rule 10). ``` ## §2 — Vocabulary disambiguation (the words that bite) @@ -130,6 +146,13 @@ appears, because each requires accumulation-tier judgment: 5. The change would add/modify a write path's ownership routing (needs v3-mailbox-warden). 6. Anything RBAC, PII-adjacent, or externally visible. +6b. A global negative the brief asks for cannot be mechanically closed — + the search space stays open (re-exports, macros, generated or + feature-gated code, a fully-qualified impl). Return "not found in + " plus what would close it; never upgrade it to "does + not exist". +6c. The required evidence does not fit: shard it or return PARTIAL. Never + substitute a shallower search because context is getting tight. 7. The change would make ANY cycle/phase advance wait on a completion or confirmation event, an awaited `ractor::call!` response, or any awaited I/O — or would add a persisted id→version confirmation ledger diff --git a/CLAUDE.md b/CLAUDE.md index fa95e10a7..3d0c835d9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1485,6 +1485,29 @@ Two corollaries: Cross-ref: the sibling rule below (Read before Write) protects FILES from a blind write; this one protects CONCLUSIONS from a blind read. +**The full rule set lives in ONE place: `.claude/knowledge/FIRST-HAND-SOURCE-LAW.md`.** +The measured table above is why the rule exists; that file is the rule — +what may be claimed from which operation (search is navigation, never +evidence), the auto-deepen triggers, the paging rule (a partial Read is not +evidence for a whole-file claim), and *context exhaustion must reduce SCOPE, +never evidence quality*. Worker-side mechanics stay where they already are: +`.claude/v3/knowledge/sonnet-worker-guardrails.md` §1/§5 and +`.claude/knowledge/tiered-agent-execution-protocol.md`. Read it before the +first search of a task; do not restate it anywhere. + +It also carries the one rule with no other home: **human authorization is +PROVENANCE, NOT VALIDATION.** A person chooses direction, scope, policy, +naming and acceptable risk — *"the user chose X"* never becomes *"X is +technically true"* without independent evidence. So new canonical material +does not use `operator-ruled` / `operator-pinned` / `operator-locked` / +`operator-confirmed` as a technical status; it uses an evidence-bearing state +(`MEASURED` with its command, `VERIFIED-IN-CODE` with its location, +`TEST-PINNED`, `CURRENT-CONTRACT`, `WORKING-MODEL`, `HYPOTHESIS`, `OPEN`, +`SUPERSEDED`, `REJECTED-BY-FALSIFIER`), and records a real decision as +`DECISION` / `SCOPE` / `BASIS` / `REVISIT WHEN`. Historical files keep their +wording; the `PreToolUse` guard blocks only an edit that INTRODUCES one of +the four, and lets a supersession note quote it. + **P0 Rule: Read before Write, always.** Before calling `Write` on any path that may already exist, run `Read` (or `git status` for committed files). The `Edit` tool is the default for modifying existing files; `Write` is only From f53ecc5eebfb117764d97e71a89543933b4ba4d2 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:53:15 +0000 Subject: [PATCH 08/19] reduction audit: 214 -> 106; the tail carve-out is retracted, the gap is named MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deletion pass, no additions. Audited against the original constraint (small, non-duplicated, no new apparatus) and three of the four flags were real. SIZE. 214 -> 106 lines (-173/+84). Not 339: that was the pre-reduction size and it was already cut in the previous commit. 106 is the honest floor, and here is the arithmetic rather than a nicer number: the authority section is 27 lines and has no other home; the claim/slicing/deepen core is 58 and is what the hook cites; pointers are 11. Sections D (paging), E (context exhaustion) and F (delegation, the return shape) were DELETED outright -- the previous commit had put each of them into sonnet-worker-guardrails.md §1/2, §1/11 and §5/6b-c AND kept a copy here. That was self-inflicted duplication, which is what this audit was for. The enforcement description moved INTO the hook's own header, where it belongs. THE TAIL CLAIM. My justification cited a real source, quoted exactly: tiered-agent-execution-protocol.md:90 -- "4. Output discipline: capture only the LAST 30 lines of each command" -- plus CLAUDE.md:942 "retry table, tail-30 output discipline". So it was not fabricated. But the source is suspect in precisely the way the objection says: it PRESCRIBES the anti-debugging pattern, and its own warning is about `tail` masking the command's EXIT STATUS, a different failure from the one that matters -- that the root diagnostic sits far above the window and the last lines are the epilogue (`aborting due to previous error`, `build failed`). So the carve-out is gone. There is no "tail exception" and no historical contract cited to license one; there are two categories: EVIDENCE INPUT source/docs/manifests/tests/plans/contracts + search results used as evidence -> slicing PROHIBITED, direct or through a pipe EPHEMERAL OUTPUT build/test/lint/benchmark/runtime logs -> may be visually limited; truncation is NEVER sufficient failure analysis `tail` is not an evidence tool. Capture the full output, locate the FIRST relevant error, read its complete diagnostic block, separate root cause from cascade. UNVERIFIED TOOL CLAIMS: 0 remaining (grep for ugrep/bfs, 25k, 40k, native build, 2026-09-19, "claude code" over the file). Attribution is not verification, so they are omitted rather than credited -- including the ~25k-40k delegation threshold, a constant that would drift. DENY SEMANTICS, measured not assumed, six cases through the shipped hook: cat source.rs | tail -> INJECT GAP git show HEAD:source.rs | tail -> INJECT GAP rg CallMask crates/ | head -> DENY correct tail -30 src/foo.rs -> DENY correct cargo test | tail -> INJECT correct (executes; not evidence) cargo test | tail -3 -> INJECT correct (executes; not evidence) Two of six slip through: the DENY keys on a file ARGUMENT or a search PRODUCER, so evidence-input slicing through any other producer passes. NOT fixed in this commit -- the instruction was to return the reduction before extending the mechanism. The gap is now named in the hook header and in the law, so it cannot be mistaken for coverage. NOT RESOLVED, deliberately: the law now CONTRADICTS tiered-agent-execution-protocol.md:90's "capture only the LAST 30 lines". Two canonical files disagreeing is exactly what this workspace says a session must escalate rather than settle on its own (sonnet-worker-guardrails.md §5/3). Reported, not rewritten. Gates: 26/26 hook tests, hook syntax clean. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/hooks/anti-pattern-matching.sh | 19 ++ .claude/knowledge/FIRST-HAND-SOURCE-LAW.md | 238 ++++++--------------- 2 files changed, 84 insertions(+), 173 deletions(-) diff --git a/.claude/hooks/anti-pattern-matching.sh b/.claude/hooks/anti-pattern-matching.sh index 28b372a9b..efcf78c61 100755 --- a/.claude/hooks/anti-pattern-matching.sh +++ b/.claude/hooks/anti-pattern-matching.sh @@ -13,6 +13,25 @@ # as context at the exact moment a pattern/partial-range tool is reached for, so # the discipline is in front of the model every time. +# WHAT THIS ENFORCES (the law itself: +# .claude/knowledge/FIRST-HAND-SOURCE-LAW.md): +# DENY a slicer (sed/head/tail/awk) naming a source/config file +# DENY a search (grep/rg/ugrep/find/fd/ls) piped into a slicer +# DENY an edit that INTRODUCES an authority label (operator-ruled etc.) +# INJECT the law summary + auto-deepen triggers, on search +# +# GUIDANCE-ONLY, because no regex decides it: "enough enclosing context", +# the paging judgement, shard-or-report, the ambiguity call, whether a state +# label is the right one, and whether a diagnostic block was read to its root. +# +# KNOWN GAP (measured 2026-09-20, not closed): the slicer DENY keys on a file +# ARGUMENT or on a search PRODUCER, so evidence-input slicing through any other +# producer still passes -- `cat source.rs | tail`, `git show HEAD:source.rs | +# tail`. Prohibited by the law, not yet by this hook. +# +# Tests: .claude/hooks/tests/anti-pattern-matching.test.sh (two-sided; every +# DENY branch disable-verified). + set -euo pipefail input="$(cat)" diff --git a/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md b/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md index bddfd4bdf..2bd61f9f4 100644 --- a/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md +++ b/.claude/knowledge/FIRST-HAND-SOURCE-LAW.md @@ -1,214 +1,106 @@ # First-hand source law — search finds, read proves -> READ BY: every session before its first search of a task; every -> orchestrator writing a worker brief. +> READ BY: every session before its first search of a task. > -> Scope: what may be CLAIMED from which operation, and how a human decision -> is recorded. It deliberately owns nothing else. +> Owns exactly two things nothing else does: what may be CLAIMED from which +> operation, and how a human decision is recorded. Everything else is a +> pointer. > -> Not duplicated here: the agent tiers and the one-writer rule -> (`tiered-agent-execution-protocol.md`), the worker iron rules and -> STOP+escalate triggers (`.claude/v3/knowledge/sonnet-worker-guardrails.md` -> §1/§5). This file is cited from both; it does not restate them. +> Worker mechanics — full-read-before-edit, paging, the report shape, the +> STOP+escalate triggers: `.claude/v3/knowledge/sonnet-worker-guardrails.md` +> §1/§5. Agent tiers and one-writer: +> `.claude/knowledge/tiered-agent-execution-protocol.md`. Not restated here. -## A. Search is navigation, never evidence +## Search is navigation, never evidence -Search, grep, rg, ugrep and Glob may establish exactly one thing: +Search, grep, rg, ugrep and Glob establish exactly one thing: **candidate +locations**. Never what a type or function means, architectural ownership, +caller semantics, dependency direction, or a global negative (`unused`, +`no consumers`, `not implemented`, `only`, `all`, `never`). -```text -"candidate locations are X, Y, Z" -``` - -They may NOT establish what a type or function means, architectural -ownership, caller semantics, dependency direction, or any global negative — -`unused`, `no consumers`, `not implemented`, `only`, `all`, `never`. - -A load-bearing claim requires first-hand reading of: - -```text -the defining semantic item -enough enclosing contract/module context to interpret it -the direct callers/consumers the claim depends on -the tests/falsifiers that pin the behaviour -``` - -A cross-crate or cross-repo claim additionally requires the manifests -(dependency direction) and BOTH sides of the seam. - -If the evidence stays incomplete, the answer is `UNKNOWN` / `OPEN` / -`PARTIAL` — never an inferred completion. +A load-bearing claim requires reading, first-hand: the defining semantic +item, enough enclosing contract to interpret it, the callers the claim +depends on, and the tests that pin the behaviour. Across a crate or repo +boundary, also the manifests and both sides of the seam. -### The one mechanical form of the whole rule +Incomplete evidence is written `UNKNOWN` / `OPEN` / `PARTIAL`, never an +inferred completion. > **A search result or snippet may never be the last evidence before an > architectural conclusion.** -```text -FORBIDDEN: search output -> conclusion -REQUIRED: search -> locate -> READ the semantic unit - -> caller/test census where relevant -> conclusion -``` - -## B. Source inspection - -For understanding source, `sed` / `head` / `tail` / `awk` are prohibited: -they produce an arbitrary textual slice rather than a semantic unit, so the -cut can fall anywhere — before the decisive `impl`, between a definition and -its invariant. - -`grep` / `rg` / `ugrep` are allowed as LOCATORS. What is prohibited is the -epistemic misuse, never the implementation: a search tool is not suspect -because some build routes it through Bash or ugrep internally. - -Limiting a NON-search command's output (`cargo test 2>&1 | tail -30`) is not -source inspection and stays allowed. - -## C. Auto-deepen - -Deepen before writing the claim if ANY of these holds: +## Slicing: two categories, no exception ```text - 1. the search returned zero hits and an absence claim is contemplated - 2. the statement would use: none / no consumer / unused / never / - only / all / every / not implemented - 3. the basis is only a search snippet - 4. a trait, macro, re-export, generated or feature-gated item is involved - 5. the claim crosses a crate or repo boundary - 6. a search or read result was truncated, partial, capped, or errored - 7. several similarly-named implementations exist - 8. the conclusion would delete code, mint a carrier, define ownership, - change a contract, or become canonical documentation -``` - -A zero-result search means `no candidates found by this search`, never `the -thing does not exist`. **A global negative requires an explicitly CLOSED -search space** — name the tool, the pattern and the scope, or phrase the -claim as "not found in \". - -## D. Paging - -A partial Read is not evidence for a whole-file or whole-section claim. - -When the read surface reports continuation or truncation, continue from the -exact next offset/page until the relevant semantic item or section is -complete. Never first-page-plus-last-page and infer the middle. - -Read semantic units, not byte ranges: a 200k-token file is not an obligation -when one complete `impl` is what the claim rests on. +EVIDENCE INPUT source · docs · manifests · tests · plans · contracts + · search results used as evidence + -> tail/head/sed/awk PROHIBITED, direct or through a pipe -```text -HARD GUARD: no WHOLE-FILE / ALL-CALLERS / NO-CONSUMERS claim - while a relevant read remains PARTIAL. +EPHEMERAL OUTPUT build · test · lint · benchmark · runtime logs + -> may be visually limited; truncation is NEVER + sufficient failure analysis ``` -## E. Context exhaustion - -> **Context exhaustion must reduce scope, never evidence quality.** - -When the required evidence does not fit the session, the two permitted -moves are to SHARD the census or to report `PARTIAL` / `UNKNOWN`. Never -substitute a shallower search for required first-hand reading because -context is getting tight. - -## F. Delegation and escalation - -Volume and ambiguity are different problems: - -```text -large VOLUME -> shard to grindwork workers -high AMBIGUITY -> the main/strong agent -insufficient EVIDENCE -> STOP -``` +`tail` is not an evidence tool. A failing command is not understood because +its last lines were read: the root diagnostic is routinely far above the +window, and the final lines are the epilogue (`aborting due to previous +error`, `build failed`, `process exited`). So capture the full output, +locate the FIRST relevant error, read its complete diagnostic block, and +distinguish root cause from cascade. -Delegate mechanical work automatically: an exhaustive caller census, 10+ -relevant files, ~25k-40k+ tokens of contiguous relevant material, repeated -same-shaped checks, multi-repo manifest inventory, a large test/falsifier -inventory. +`grep`/`rg`/`ugrep` are allowed as LOCATORS. What is prohibited is the +epistemic misuse, never the implementation. -A worker assignment is a CLOSED evidence task, never an architectural -question: +## Auto-deepen -```text -"Enumerate every CallMask producer/consumer. Read each relevant item. - Return file/symbol/role/evidence/uncertainty. - Make no architecture recommendation." -``` +Deepen before writing the claim if ANY holds: the search returned zero hits +and an absence claim is contemplated · the statement would use +none/no-consumer/unused/never/only/all/every/not-implemented · the basis is +only a snippet · a trait, macro, re-export, generated or feature-gated item +is involved · the claim crosses a crate or repo boundary · a search or read +result was truncated, partial, capped or errored · several similarly-named +implementations exist · the conclusion would delete code, mint a carrier, +define ownership, change a contract, or become canonical documentation. -Worker return shape: +Zero results means `no candidates found by this search`, never `it does not +exist`. **A global negative requires an explicitly CLOSED search space** — +name tool, pattern and scope, or phrase it "not found in \". -```text -STATUS: DONE | PARTIAL | ESCALATE -Observed: -Evidence: -Unresolved: -Files/semantic items read: -Search space closed? yes/no -``` +A partial read is not evidence for a whole-file claim: **no WHOLE-FILE / +ALL-CALLERS / NO-CONSUMERS claim while a relevant read is PARTIAL.** -The tiers themselves and the STOP+escalate trigger list are owned by the two -files named in the header; a worker follows those, not a second copy here. +**Context exhaustion must reduce SCOPE, never evidence quality** — shard the +census or report PARTIAL; never a shallower search because context is tight. -## G. Authority and evidence are different things +## Authority and evidence are different things ```text HUMAN AUTHORIZATION IS PROVENANCE, NOT VALIDATION. ``` -A user may choose direction, scope, policy, naming, and acceptable risk. -`the user chose X` must never become `X is technically true` without -independent evidence. - -```text -human decision != evidence - != technical truth - != correctness - != safety -``` - -So in NEW canonical material these are not technical status labels and are -not used as one: `operator-ruled`, `operator-pinned`, `operator-locked`, -`operator-confirmed`. - -Use an evidence-bearing state instead: +A person chooses direction, scope, policy, naming, acceptable risk. +`the user chose X` never becomes `X is technically true` without independent +evidence. So `operator-ruled` / `operator-pinned` / `operator-locked` / +`operator-confirmed` are not technical status labels in new material. | state | means | |---|---| -| `MEASURED` | a command produced this number; the command is named | +| `MEASURED` | a command produced this; the command is named | | `VERIFIED-IN-CODE` | read first-hand at a named location | | `TEST-PINNED` | a test fails if this stops holding | -| `CURRENT-CONTRACT` | what the shipped types/signatures require today | -| `WORKING-MODEL` | in use, not yet falsified either way | -| `HYPOTHESIS` | stated so it can be tested | -| `PROPOSED` | not in force | +| `CURRENT-CONTRACT` | what the shipped types require today | +| `WORKING-MODEL` | in use, not yet falsified | +| `HYPOTHESIS` / `PROPOSED` | stated to be tested / not in force | | `OPEN` / `DEFERRED` | unresolved, deliberately | | `SUPERSEDED` | replaced; the replacement is named | | `REJECTED-BY-FALSIFIER` | a measurement killed it | -A real user decision is recorded as a decision, not as a proof: - -```text -DECISION: what was chosen -SCOPE: where it applies -BASIS: preference / risk tolerance / policy / cost — or the evidence -REVISIT WHEN: the condition that would reopen it -``` - -A decision and a measurement may coexist on one item; they are two fields, -never one label. +A real decision is recorded as `DECISION` / `SCOPE` / `BASIS` / +`REVISIT WHEN` — two fields beside any measurement, never one label. ## Enforcement -Mechanical, in `.claude/hooks/anti-pattern-matching.sh` -(`PreToolUse(Grep|Bash|Edit|Write)`), tested by -`.claude/hooks/tests/anti-pattern-matching.test.sh`: - -| | | -|---|---| -| DENY | a slicer (`sed`/`head`/`tail`/`awk`) whose argument list names a source/config file — §B | -| DENY | a search (`grep`/`rg`/`ugrep`/`find`/`fd`/`ls`) piped into a slicer — §C.6, the cap that hides itself | -| DENY | an edit that INTRODUCES one of the four authority labels — §G | -| INJECT | the law's summary + the §C triggers, on the Grep tool and on any search-shaped Bash command | - -Guidance-only, because no regex decides it: §A's "enough enclosing context", -§D's paging, §E's shard-or-report choice, §F's ambiguity judgement, and -whether a chosen state label in §G is the right one. +Partly mechanical, in `.claude/hooks/anti-pattern-matching.sh` — its header +lists exactly what is DENIED, what is injected, what stays guidance-only, and +the one measured gap still open. Tested by +`.claude/hooks/tests/anti-pattern-matching.test.sh`. From ad7864aef79e402c0a5f8baef90f29529a4eb114 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 13:21:00 +0000 Subject: [PATCH 09/19] Replace the tail-30 output rule with root-diagnostic discipline The guarded-executor contract told its executor to capture only the last 30 lines of each command. A trailing slice can discard the root diagnostic outright: a compiler prints the causal error FIRST and its consequences after, so the retained window is often the consequences alone. The rule was therefore capable of destroying exactly the evidence the STOP condition exists to report. Item 4 now requires: the true exit status preserved (the pipefail note is kept verbatim -- it was always correct), complete output retained when failure analysis may be needed, the FIRST relevant diagnostic located, and that complete diagnostic block read. A short tail or summary is display only and never sufficient evidence. Item 2's "last 30 lines" referenced the same superseded semantics and now points at item 4. No other tier or executor semantics change: the run-record format, the ONE-WRITER rule, the retry table, the forbidden-actions list and the no-exponential-residue rule are untouched. CLAUDE.md's guarded-executor carve-out advertised "tail-30 output discipline" and now names the corrected one. The hook's ALLOW for limiting a non-search command's display stays -- ephemeral process output is not a source file -- but its justification no longer cites a discipline that has been superseded; the allowance is display only. Nothing here is new mechanism, so nothing new is mechanically testable. The existing hook suite is re-run as a regression check on the two wording edits: 26 cases, ALL PASSED. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/hooks/anti-pattern-matching.sh | 11 +++++++---- .../hooks/tests/anti-pattern-matching.test.sh | 2 +- .../tiered-agent-execution-protocol.md | 18 ++++++++++++------ CLAUDE.md | 6 ++++-- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/.claude/hooks/anti-pattern-matching.sh b/.claude/hooks/anti-pattern-matching.sh index efcf78c61..1dfba1b73 100755 --- a/.claude/hooks/anti-pattern-matching.sh +++ b/.claude/hooks/anti-pattern-matching.sh @@ -64,10 +64,13 @@ emit_prepend() { # looks precise while being an arbitrary cut. FIRST-HAND SOURCE LAW rule 3. # # Scoped to SOURCE INSPECTION, deliberately: limiting a non-search command's -# output (`cargo test 2>&1 | tail -30`) is REQUIRED elsewhere in this fleet -# (the guarded-executor tail-30 discipline) and is not what fabricates a -# false semantic boundary. A deny that fires on every build command would be -# worked around within the hour and would then guard nothing. +# DISPLAY (`cargo test 2>&1 | tail -30`) does not fabricate a false semantic +# boundary -- the producer's own output is ephemeral process output, not a +# source file. It is allowed, but it is display only: the guarded-executor +# contract requires the complete output be retained and the FIRST relevant +# diagnostic block read in full when a command fails. A deny that fired on +# every build command would be worked around within the hour and would then +# guard nothing. SLICE_DENY='VERBOTEN (FIRST-HAND SOURCE LAW, Regel 3): sed/head/tail/awk auf eine QUELLDATEI. Eine numerische Scheibe hat keine semantische Grenze -- `head -100 x.rs` endet womoeglich direkt vor dem entscheidenden impl, `tail` trennt Definition und Invariante, `sed -n 120,180p` sieht praezise aus und ist ein willkuerlicher Schnitt. Stattdessen: Grep/Glob lokalisiert das Symbol, dann Read auf das VOLLSTAENDIGE semantische Element (und bei Teilausgabe vom exakten naechsten Offset weiterlesen, niemals die ungesehene Mitte erraten). Output-Limitierung eines Nicht-Such-Kommandos (cargo ... | tail -30) bleibt erlaubt. Gesetz: .claude/knowledge/FIRST-HAND-SOURCE-LAW.md' # Capping a SEARCH result is how a truncated result set masquerades as a diff --git a/.claude/hooks/tests/anti-pattern-matching.test.sh b/.claude/hooks/tests/anti-pattern-matching.test.sh index ce896d84d..fc0afa711 100755 --- a/.claude/hooks/tests/anti-pattern-matching.test.sh +++ b/.claude/hooks/tests/anti-pattern-matching.test.sh @@ -50,7 +50,7 @@ t DENY "grep -rn CallMask crates/ | head -20" t DENY "rg -l CallMask | head" t DENY "find . -name '*.rs' | head -5" -echo '### ALLOW -- output limiting of a NON-search command (the tail-30 discipline)' +echo '### ALLOW -- display limiting of a NON-search command (ephemeral process output)' t INJECT "cargo test 2>&1 | tail -30" t INJECT "cargo build --release | head -5" t INJECT "head -1 /tmp/out.err" diff --git a/.claude/knowledge/tiered-agent-execution-protocol.md b/.claude/knowledge/tiered-agent-execution-protocol.md index 82dfe1859..2bdd3250c 100644 --- a/.claude/knowledge/tiered-agent-execution-protocol.md +++ b/.claude/knowledge/tiered-agent-execution-protocol.md @@ -84,15 +84,21 @@ authors, never decides — it executes and reports. no substitutions, no flags changed. 2. STOP conditions: any command exits non-zero AND is not covered by the retry table → STOP immediately, do not attempt fixes, write your log entry - with status=BLOCKED and the last 30 lines of output. + with status=BLOCKED and the root diagnostic block (item 4). 3. Retry table: network-flavored git/curl failures → up to 3 retries with 2s/4s/8s backoff. Nothing else retries. -4. Output discipline: capture only the LAST 30 lines of each command, but - NEVER let `tail` mask the command's exit status — `cmd | tail -30` - reports `tail`'s success even when `cmd` failed. Run each command under - `set -o pipefail` (or read `${PIPESTATUS[0]}` before evaluating the +4. Diagnostic discipline: run the command so its COMPLETE output is + retained (redirect to a file, or capture it whole) whenever failure + analysis may be needed, and preserve the command's TRUE exit status — + `cmd | tail -30` reports `tail`'s success even when `cmd` failed, so run + under `set -o pipefail` (or read `${PIPESTATUS[0]}` before evaluating the retry/STOP rule); the STOP condition (item 2) tests the PRODUCER's status, - not the pipeline's. Never dump full build logs into your reply. + not the pipeline's. On failure, locate the FIRST relevant diagnostic (the + root, not the last thing printed) and read that complete diagnostic block + — a compiler's later errors are usually consequences of the first one, and + a trailing summary can omit the root entirely. A short tail or summary is + DISPLAY ONLY and is never sufficient evidence; report the root diagnostic + block, not a line count. Still never dump a full build log into your reply. 5. Run-record (MANDATORY, your final act): write your terse run-record to your OWN per-run file `.claude/board/exec-runs/.txt` (create the dir if absent) in the format below — one executor, one file, diff --git a/CLAUDE.md b/CLAUDE.md index 3d0c835d9..4d50f25b9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -939,8 +939,10 @@ the runtime Blackboard. Keep them architecturally distinct. architecture), escalate to Opus. - **NEVER `haiku` for any subagent in this workspace** — with ONE narrow, contract-gated exception: the **guarded-executor** role (run a pre-written, - `-p`-scoped bash/cargo card with explicit START/STOP, retry table, tail-30 - output discipline, one shared `target/`, and a mandatory append-only log + `-p`-scoped bash/cargo card with explicit START/STOP, retry table, root- + diagnostic output discipline (true exit status preserved, complete output + retained, the FIRST relevant diagnostic block read in full — a short tail + is display only), one shared `target/`, and a mandatory append-only log entry; never authors, decides, or edits any file but the log). See `.claude/knowledge/tiered-agent-execution-protocol.md` for the full contract. Outside that role the quality floor is Sonnet regardless of task From ad9e3230058535ef95376826304c55b4ced3d2b7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 13:24:30 +0000 Subject: [PATCH 10/19] Fix the two prompts that read failure analysis off a tail Both remaining `| tail -30` sites turned out to be failure-analysis inputs, which is the condition that makes them defects rather than display: - VERIFY_COMPRESSION_REVOLUTION.md's next line is "Wenn ein Test fehlschlaegt -> die Behauptung ist NICHT bewiesen", so the truncated window IS the evidence the prompt reasons from. - SCOPED_PROMPTS.md asks its worker to "list them all" for the build errors, which a last-30 window cannot answer at all: cargo prints the root error first and its consequences after, so the retained lines are systematically the wrong end. Both now redirect the complete output to a log, keep the producer's real status, and mark the tail as display only -- the shape the corrected guarded-executor contract requires. Not touched, and named rather than silently widened: the same SCOPED_PROMPTS.md block recommends `grep ... | head -20` twice, which is a search piped into a slicer and is what the hook now denies for a live call. It is outside the condition under which these two were fixed, so it stays for a deliberate decision instead of riding along here. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/prompts/SCOPED_PROMPTS.md | 4 +++- .claude/prompts/VERIFY_COMPRESSION_REVOLUTION.md | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.claude/prompts/SCOPED_PROMPTS.md b/.claude/prompts/SCOPED_PROMPTS.md index b361cd788..aa7a0668f 100644 --- a/.claude/prompts/SCOPED_PROMPTS.md +++ b/.claude/prompts/SCOPED_PROMPTS.md @@ -223,7 +223,9 @@ grep "pub fn\|pub use" ndarray/src/simd.rs | head -20 # rs-graph-llm: what's broken? cat rs-graph-llm/CLAUDE.md 2>/dev/null -cargo check --manifest-path rs-graph-llm/Cargo.toml 2>&1 | tail -30 +cargo check --manifest-path rs-graph-llm/Cargo.toml > /tmp/rsg.log 2>&1; status=$? +tail -30 /tmp/rsg.log # display only +# "list them all" (Step 2 Q3) is answered from /tmp/rsg.log, never from this tail. ``` ## Step 2: Map diff --git a/.claude/prompts/VERIFY_COMPRESSION_REVOLUTION.md b/.claude/prompts/VERIFY_COMPRESSION_REVOLUTION.md index 62de0427f..dc7090f3c 100644 --- a/.claude/prompts/VERIFY_COMPRESSION_REVOLUTION.md +++ b/.claude/prompts/VERIFY_COMPRESSION_REVOLUTION.md @@ -24,7 +24,10 @@ cat crates/bgz17/src/similarity.rs cat crates/lance-graph/src/graph/blasgraph/hdr.rs # Cascade, HHTL find . -name "*.rs" | xargs grep -l "euler\|fibonacci\|rotation\|palette\|codebook" find . -name "*.rs" | xargs grep -l "gguf\|quantiz\|compress" -cargo test --workspace 2>&1 | tail -30 +cargo test --workspace > /tmp/verify.log 2>&1; status=$? +tail -30 /tmp/verify.log # display only +# status != 0 -> read the FIRST relevant diagnostic block in /tmp/verify.log, +# not this tail: cargo prints the root error first and its consequences after. ``` Wenn eine Datei nicht existiert → die Behauptung ist NICHT implementiert. From 68ca76e88c9e544637183d333ecf22923c213bf8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 13:39:10 +0000 Subject: [PATCH 11/19] Add the workspace-wide closeout rule: one line, a mirror, and an Epiphany gate The board-hygiene table routed "a finding / correction / 'aha'" unconditionally to EPIPHANIES.md. That row is the pipeline that turns an ordinary engineering mistake into a correction, a finding, an epiphany, a post-mortem, a correction of the post-mortem, and finally permanent terminology -- so the repository remembers mistakes more strongly than discoveries. Measured: EPIPHANIES.md is 33,528 lines and has no admission gate, while a census of .claude/ found no closeout surface at all. The row now splits. A genuine Eureka still goes to the ledger; an ordinary correction goes NOWHERE and is discharged by one closeout line. The new section, inside the same workspace-wide hygiene rule so it applies to every PR rather than to one skill, carries: the one-line STATUS/OUTCOME/OPEN record; a four-field MIRROR that may be omitted entirely (silence is allowed); the Kahneman/Tversky families as QUESTIONS with an explicit ban on writing them as diagnoses of a past self; OPEN stays open, with UNKNOWN a valid result and no manufactured doctrine to close it; and the NEW/LOAD-BEARING/DURABLE gate whose single test is whether the insight would still matter had the mistake never happened. Non-recursion is not restated -- it points at the Termination clause already three paragraphs above, which is the same stopping rule one level down. Guidance only, deliberately: no new file, no lessons ledger, no bias database, no agent, no review tier, no post-mortem template, no mistake taxonomy. No historical Epiphany, correction entry or operator-worded passage was rewritten or migrated. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- CLAUDE.md | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4d50f25b9..15816d462 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -342,7 +342,8 @@ updating the relevant board file in the SAME commit is incomplete.** | A merged PR (post-merge commit) | `.claude/board/LATEST_STATE.md` table + `.claude/board/PR_ARC_INVENTORY.md` PREPEND entry | | A new integration plan | `.claude/board/INTEGRATION_PLANS.md` PREPEND + `.claude/plans/-v.md` | | A new D-id / deliverable | `.claude/board/STATUS_BOARD.md` row (status = Queued → In progress → In PR → Shipped) | -| A finding / correction / "aha" | `.claude/board/EPIPHANIES.md` PREPEND dated entry | +| A genuine Eureka (passes the § Closeout admission gate below) | `.claude/board/EPIPHANIES.md` PREPEND dated entry | +| An ordinary correction / lesson learned | **NOTHING** — one closeout line, see § Closeout below | | A tech-debt observation | `.claude/board/TECH_DEBT.md` entry | | An unresolved issue / blocker | `.claude/board/ISSUES.md` entry | | A completed agent run | `.claude/board/AGENT_LOG.md` PREPEND entry (D-ids, commit, tests, outcome) | @@ -375,6 +376,107 @@ This is a stopping rule, not a loosening: the original gap — merging #881, #882 and #883 with no entries at all — remains a real violation. What is excluded is only the degenerate tail. +### Closeout — the default is one line, and a fixed mistake has no right to residency + +**DECISION (2026-09-20).** The workspace was accumulating correction-shaped +prose faster than architecture: a mistake became a correction, then a finding, +then an epiphany, then a post-mortem, then a correction OF the post-mortem, then +permanent terminology. Measured: `EPIPHANIES.md` is 33,528 lines with no +admission gate, and no closeout surface existed anywhere under `.claude/`. The +default is now **fix → compress → keep open points visible → move on.** +SCOPE: all ordinary work — implementation, audits, PR review, probes, +integration, `/5plus3` alike. REVISIT WHEN: the ledger starts losing a +*discovery* rather than a correction. + +**The default closeout is ONE compact status record** — not a board entry, not a +file: + +``` +PR # | STATUS: | +OUTCOME: | +OPEN: +``` + +Several trivial corrections collapse into one line (`OUTCOME: 4 review defects +corrected; executable contract unchanged`). **Do not create one permanent +artifact per correction.** If a session fixed several things and discovered no +new architecture, a boring closeout IS success: `STATUS: done | OUTCOME: review +corrections applied; architecture unchanged | OPEN: none`. + +**MIRROR — self-reflection without paperwork.** At a meaningful closeout, at +most these four fields; omit any field that carries nothing, and omit the whole +section when it carries nothing. **Silence is allowed.** + +``` +MIRROR +- LESSON: +- BLIND SPOT: +- BIAS CHECK: +- STILL OPEN: +``` + +**Kahneman/Tversky as QUESTIONS, never as labels.** Never write "this was +anchoring" or "confirmation bias caused X" — diagnosing a past self is the +residue this rule exists to stop. Ask only whether any MAY have contributed: + +- **Anchoring** — did the first plausible explanation become the reference later + evidence was read *against*, instead of being re-tested independently? +- **Availability** — was the easiest grep hit, the recent PR or the vivid + failure overweighted because it was cheap to retrieve? +- **Representativeness** — did something LOOK like a known pattern and get + treated as the same mechanism without reading the actual contract? +- **Base rate / population** — was the denominator, frequency or index space + ignored; do two similarly shaped masks describe different populations? +- **Framing** — did the task's wording make one reading feel inevitable; would + the conclusion survive a different phrasing? +- **WYSIATI** — did "what we saw" become "all that exists"; did `search = 0` + become absence; did a small visible set become the whole search space? +- **Sunk cost** — was a mechanism, doc or test preserved mainly because it was + already written? +- **Confirmation pressure** — after forming the hypothesis, did we look for a + disable, a counterexample and an alternative, or only for agreement? + +**OPEN stays open.** `UNKNOWN` is a valid result. Never manufacture a doctrine, +a carrier, a term, a follow-up PR or an Epiphany to turn OPEN into CLOSED — a +visible blind spot is healthier than a fabricated conclusion. Write it plainly: +`OPEN: ownership still undecided; no measured row-level predicate yet; search +space not closed; competing explanations remain`. + +**Epiphany admission gate — lessons learned are NOT Epiphanies.** "the +hand-written ternlog immediate was wrong", "the test failed by underflow rather +than by its assertion", "the CI job attribution was guessed", "the grep was +correct and the conclusion false", "the tail hid the root diagnostic" are +LESSONS. Each may become one `MIRROR` line. None enters `EPIPHANIES.md`. A +candidate must be all three — **NEW** (not already represented), +**LOAD-BEARING** (changes future architecture, reasoning or representation), +**DURABLE** (still matters once the PR and the mistake are forgotten) — and pass +one test: + +> **Would this insight still matter if the mistake that led to it had never +> happened?** NO ⇒ it is not an Epiphany. + +Concretely: *"I was wrong about which CI job held the step"* is a correction +(`STATUS: fixed | OUTCOME: job attribution corrected | OPEN: none`). *"Two masks +can share a Boolean algebra while inhabiting different population axes, so +algebraic compatibility does not imply representational substitutability"* +survives its own mistake and is a candidate. Keep the categories separate. + +**No recursive post-mortems.** A correction does not entitle a post-mortem, and +a corrected post-mortem does not entitle another — § Termination clause above is +the same stopping rule one level down. A review earns a follow-up only for a +still-live executable defect, an unresolved implementation task, or a true +Eureka needing independent architectural work. *Documenting what went wrong is +not itself a follow-up task.* + +**Ore and slag.** Ask what survived that future work genuinely needs. **Keep:** +the current contract, the measured result, the open point, a genuine Eureka. +**Discard:** stale reasoning, the correction narrative, the duplicate +explanation, the wrong hypothesis, procedural autobiography, and any elaborate +lesson already encoded in a test or a guard. **The closeout should usually be +SMALLER than the reasoning history it closes.** Optimize for clarity, current +truth, visible uncertainty and minimal durable residue — never for maximum +documentation. The architecture should stay enjoyable to work on. + ### The falsifiability rule (P0, added 2026-07-26 — 7 instances in one session) **An assertion implied by the code it tests is not a test.** Before a test From e59ff9b88218ddb08ce71214f2ecca6cb6d7899f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 13:41:06 +0000 Subject: [PATCH 12/19] Remove the probe CI step until OGAR #305 is on main; record the follow-up The step can only be red before ogar-r2il's CallMask::words() reaches OGAR's default branch, because the test job checks the OGAR sibling out with no ref:. Complete log of run 35513415131: 16 x E0599, one class, all 'words', exit 101 -- the same root on every head, reproduced locally by detaching the sibling to origin/main. I had rejected removing it, on the ground that the probe crate would land without CI enforcement. That reasoning under-weighted the real risk: keeping the step red makes a green main depend on a merge order this repo cannot enforce, so if #1254 merges before OGAR #305 the red job lands on main. A gate arriving one merge later is the smaller cost, and the rejection was shaped by having already argued the opposite on the PR. What replaces it: a one-line marker at the step's old position naming the blocker, and ISS-R2IL-PROBE-HAS-NO-CI-LINE-UNTIL-OGAR-305 carrying the exact YAML to restore. The probe stays locally verified (6/6, every assertion disable-verified) and the missing enforcement is now a visible open point instead of a red check. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/board/ISSUES.md | 28 ++++++++++++++++++++++++++++ .github/workflows/rust-test.yml | 23 +++++++---------------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/.claude/board/ISSUES.md b/.claude/board/ISSUES.md index 4efa95938..b3aaf695b 100644 --- a/.claude/board/ISSUES.md +++ b/.claude/board/ISSUES.md @@ -1,3 +1,31 @@ +## ISS-R2IL-PROBE-HAS-NO-CI-LINE-UNTIL-OGAR-305 + +**Status:** OPEN — one-line follow-up, blocked on a cross-repo merge. +**Basis:** measured. `rust-test.yml`'s `test` job checks `AdaWorldAPI/OGAR` out +with no `ref:`, so `crates/r2il-mask-abi-probe` compiles against OGAR's DEFAULT +branch, where `CallMask::words()` does not exist yet (OGAR #305). Complete log +of run 35513415131: **16 × E0599, one class, all `words`**, `exit 101`. +Reproduced locally by detaching the OGAR sibling to `origin/main` (16 errors) +and restoring (6/6 green). + +The step was REMOVED from the workflow rather than left red. The earlier +position — keep it red and rely on merging OGAR #305 first — made a green `main` +depend on human merge ordering that this repo cannot enforce; if #1254 merges +first, `main` carries a red job. A gate arriving one merge later is the smaller +cost. + +**To close (one line, no design):** after OGAR #305 is on OGAR's default branch, +re-add to the `test` job, after the `lance-graph-ogar` step: + +```yaml + - name: Run r2il-mask-abi-probe mask-ABI differential (excluded tier, OGAR + ndarray siblings) + run: cargo test --manifest-path crates/r2il-mask-abi-probe/Cargo.toml +``` + +**Until then the probe is locally-verified only** (6/6, all disable-verified) and +has NO CI enforcement — which is the actual risk this entry exists to keep +visible, since an excluded crate with no CI line rots invisibly. + ## ISS-NDARRAY-CANONICAL-COORDINATE-COUPLES-FLEET-MSRV — one canonical ndarray source imposes one MSRV floor; three repos pin below it (2026-09-20) **Status:** OPEN. Operator decision, not a dependency-pass side effect. diff --git a/.github/workflows/rust-test.yml b/.github/workflows/rust-test.yml index 4e7afc8a5..71456e37a 100644 --- a/.github/workflows/rust-test.yml +++ b/.github/workflows/rust-test.yml @@ -155,22 +155,13 @@ jobs: # had never minted them). One scoped step closes both. - name: Run lance-graph-ogar codebook-parity + hotplug-activation tests (armed tier, OGAR sibling) run: cargo test --manifest-path crates/lance-graph-ogar/Cargo.toml - # r2il-mask-abi-probe: the W0B mask-ABI differential, workspace-EXCLUDED - # and path-depping BOTH siblings checked out above (mask-risc reaches - # `ndarray` at ../../../ndarray; the probe reaches ogar-r2il at - # ../../../OGAR/crates/ogar-r2il). It proves ogar-r2il's CallMask - # Boolean algebra and lance-graph-mask-risc's agree BIT-IDENTICALLY over - # the same borrowed words -- the check that decides whether CallMask's - # and/or/xor/and_not/not/count is a second algebra beside the one - # evaluator or a subset of it. Excluded means no step above reaches it, - # and an excluded crate with no CI line rots invisibly. - # - # ORDERING: requires ogar-r2il's `CallMask::words()` (AdaWorldAPI/OGAR - # #305). This step is RED until that merges, because it compiles against - # the OGAR sibling's default branch -- a stated stacked dependency, not a - # defect in this probe. - - name: Run r2il-mask-abi-probe mask-ABI differential (excluded tier, OGAR + ndarray siblings) - run: cargo test --manifest-path crates/r2il-mask-abi-probe/Cargo.toml + # r2il-mask-abi-probe (crates/r2il-mask-abi-probe, workspace-EXCLUDED): + # its CI step is DELIBERATELY ABSENT until ogar-r2il's `CallMask::words()` + # is on OGAR's default branch (AdaWorldAPI/OGAR #305) -- this job checks + # the OGAR sibling out with no `ref:`, so the step can only be red before + # then, and a red step that lands on main is worse than a gate that + # arrives one merge later. Restore it as a one-line follow-up: + # ISS-R2IL-PROBE-HAS-NO-CI-LINE-UNTIL-OGAR-305 (.claude/board/ISSUES.md) # deepnsm: standalone 0-dep codec crate, workspace-excluded, so the # lance-graph test steps above never reached it. ~217 lib + integration + # doctests, fast (no lance/datafusion/ndarray deps). Gating. From 62daf0fba6c59df370c88befeda446907ac87e2e Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 14:20:16 +0000 Subject: [PATCH 13/19] Revive board/entries as the transient tier: generated index, CI falsifiers, one promotion rule The tier existed, was used 2026-08-06..08-31, and was then bypassed while EPIPHANIES.md absorbed everything. Measured before this commit: its header claimed "135 entries, .. 2026-08-26" against 144 files / 142 rows / .. 2026-08-31; its OWN falsifier #2 was red on two stranded files; one row sat out of date order. Nothing ran those three checks -- they were shell snippets in a README, and the directory sat in no gate. `entries_index.py` generates the index. The derive/carry-forward split is forced by measurement, not chosen: the entry files use four different heading shapes, so date/id/file come from the uniform FILENAME while the `finding` prose is carried forward verbatim -- over 100 rows carry a hand-written summary no heading contains, and a generator that "derived" that column would delete curation. Proven non-lossy: 142 -> 144 rows, 0 removed, and curated findings 72 -> 74 (it recovers two from the stranded files' inline headings). The write guard was VACUOUS in its first form and the disable run caught it. It compared the generated output against the WORKING file -- but the output derives from that file, so truncating the input lowers both sides equally and an emptied index wrote cleanly at exit 0. The reference is now git HEAD, which a shell redirect cannot reach; both truncation shapes (emptied file, blanked cells) now refuse. This matters because the house convention for the sibling generator is `tool.py > file.md`, which here would destroy every curated cell before the script read it. Link TEXT keeps its trailing `.md`: that is the convention in 138 of 142 committed rows, and normalising it churned every row of the diff to change nothing a reader sees. Reverted to the committed form, which took the index diff from +165/-162 to +37/-34. CI: two steps added to the existing supersession-index workflow, which already watches board/entries/**. No new workflow. `append_only_gate` is deliberately NOT extended: a generated file must be free to reflow, so a line-count no-shrink gate would fight its own generator. The semantic equivalent lives in the generator as the curated-cell guard above. CLAUDE.md gains the routing row (findings -> entries/) and ONE promotion rule with four destinations and no fifth: nothing durable / OPEN row / DONE row / EPIPHANIES for a NEW+LOAD-BEARING+DURABLE insight still true after reconciliation. Reconciliation reuses what exists -- PLAN-INVENTORY's OPEN/CLOSED/SUPERSEDED/AMBIGUOUS rubric, the supersession index's route column, preflight_drift. MIRROR is never promoted by itself. No maturity taxonomy, no new ledger, no closeout framework, no historical migration. Gates: entries --check green + self-test ALL PASSED + idempotent second write; append-only, citation-decay, supersession-index, hook suite (26 cases) all green; workflow yaml parses. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/board/entries/README.md | 71 ++-- .claude/tools/entries_index.py | 418 +++++++++++++++++++++++ .github/workflows/supersession-index.yml | 16 + CLAUDE.md | 30 ++ 4 files changed, 501 insertions(+), 34 deletions(-) create mode 100644 .claude/tools/entries_index.py diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index df62def4e..cf992ec5c 100644 --- a/.claude/board/entries/README.md +++ b/.claude/board/entries/README.md @@ -1,52 +1,56 @@ # Board entries — one file per finding -> Each entry is `YYYY-MM-DD-.md`, carrying the entry **verbatim**. -> This table is the index; the files are the content. A row whose file does not -> resolve is a broken reference — that is the falsifier, and it is why the index -> and the content are separate objects. -**Falsifiers** (both must hold): +> **GENERATED — do not hand-edit the table's structure.** +> `python3 .claude/tools/entries_index.py --write` +> +> Each entry is `YYYY-MM-DD-.md`, carrying the entry **verbatim**. +> This table is the index; the files are the content. A row whose file does +> not resolve is a broken reference — that is the falsifier, and it is why +> the index and the content are separate objects. +> +> The `finding` cell is the ONE hand-curated column: it is carried forward +> verbatim on every regeneration, because the entry files do not share a +> heading shape and it cannot be derived. Edit it freely. `date`, `id`, +> `file`, the ordering and the counts are derived and will be overwritten. +> +> **Never `… > README.md`.** This file is an INPUT to its own generator, so +> a shell redirect truncates it before the script reads it and every curated +> `finding` is lost. Use `--write`, which reads first and refuses to drop +> curated cells. -```sh -cd .claude/board/entries -# 1. every reference resolves (anchored on the date prefix, so a parenthesis -# inside a title cannot be mistaken for a filename -- the first version of -# this check used -F'[()]' and reported 8 titles as dangling files) -grep -oE '\([0-9]{4}-[0-9]{2}-[0-9]{2}-[^)]*\.md\)' README.md | tr -d '()' | - while read -r f; do [ -f "$f" ] || echo "DANGLING: $f"; done -# 2. every file is referenced (the other direction -- catches a stranded file) -for f in 20*.md; do grep -q "($f)" README.md || echo "UNREFERENCED: $f"; done -# 3. no duplicate entry id -grep '^| 20' README.md | cut -d'|' -f3 | sort | uniq -d -``` -All three must print nothing. Checks 1 and 2 are deliberately opposite -directions: 1 catches an index row whose file never landed, 2 catches a file -that landed with no row. The stranding this convention exists to prevent shows -up in exactly one of them, never both. +**Falsifiers** — now executed by CI (`entries_index.py --check`), not just +described here: (1) every index row's file resolves, (2) every file has an +index row, (3) no duplicate entry id. Checks 1 and 2 are deliberately +opposite directions; the stranding this convention prevents shows up in +exactly one of them, never both. -135 entries, 2026-08-06 .. 2026-08-26. +144 entries, 2026-08-06 .. 2026-08-31. | date | entry id | finding | file | |---|---|---|---| -| 2026-08-26 | `E-A-RECORDED-ALPHA-IS-INSTRUMENTATION-UNTIL-AN-INTERVENTION-ON-IT-MOVES-THE-NEXT-TRANSITION-1` | humility about introspection (vs #1057's humility about the world): a claimed alpha must move the next DispatchMode election when perturbed and stay silent when an unclaimed state is perturbed — the can-fire/can-stay-silent twin aimed inward, with a target that pre-declares its own null (dispatch_mode reads logical markers, never qualia); five-metric faithfulness stack computable from a receipt without an LLM judge | [2026-08-26-e-a-recorded-alpha-is-instrumentation-until-an-intervention-on-it-moves-the-next-transition-1](2026-08-26-e-a-recorded-alpha-is-instrumentation-until-an-intervention-on-it-moves-the-next-transition-1.md) | -| 2026-08-26 | `E-ENTROPY-MEASURES-CLOSURE-BITS-59-60-TELL-WHETHER-THE-CLOSURE-HAS-CAUSAL-FOOTING-1` | the humility law measured onto shipped types: the H x ground cross-product already exists as SettlementCell (Glass = unearned closure), 59-60 under the CausalTopology lens already distinguish known/projected/hole, 61-63 gate fills as a permission band, and the Sudoku walker turns entropy into search pressure toward constraint-bounded epistemic holes | [2026-08-26-e-entropy-measures-closure-bits-59-60-tell-whether-the-closure-has-causal-footing-1](2026-08-26-e-entropy-measures-closure-bits-59-60-tell-whether-the-closure-has-causal-footing-1.md) | -| 2026-08-26 | `E-MUL-CALIBRATES-FLOW-MODULATES-1045-FUSED-TWO-ORTHOGONAL-AXES-INTO-ONE-VERDICT-1` | measured storno of the same day's OUTCOME-vs-GROUND thesis: TrustTexture (calibration) and FlowState (Csikszentmihalyi, whose real consumer is FlowState→StyleFamily style adaptation) are orthogonal coordinates MulAssessment already carries apart; the planner's Proceed/Sandbox/Compass IS the diagram's MUL, and contract::mul::GateDecision is the execution gate wearing MUL's name — GateLevel withdrawn | [2026-08-26-e-mul-calibrates-flow-modulates-1045-fused-two-orthogonal-axes-into-one-verdict-1](2026-08-26-e-mul-calibrates-flow-modulates-1045-fused-two-orthogonal-axes-into-one-verdict-1.md) | -| 2026-08-26 | `E-A-HOT-PATH-FIX-NARROWED-A-PUBLIC-CONTRACT-WORKSPACE-GREEN-IS-NOT-CONTRACT-GREEN-1` | #1045's hot-path de-stringing was right at its own layer and still narrowed a public contract: MUL-specific ground (TrustTexture/FlowState) became mandatory in the universal gate outcome, so no other producer can say Block without claiming MUL provenance; the break is live in ada-rs against an unbound git dep, and every workspace gate stayed green | [2026-08-26-e-a-hot-path-fix-narrowed-a-public-contract-workspace-green-is-not-contract-green-1](2026-08-26-e-a-hot-path-fix-narrowed-a-public-contract-workspace-green-is-not-contract-green-1.md) | +| 2026-08-31 | `E-Q8-THE-SIX-DOES-NO-WORK-A-DEGREE-ABLATION-COLLAPSES-THE-HEX-OVERLAYS-ENTIRE-ADVANTAGE-1` | B passes every pre-registered gate and the pass is unattributable: at degree 1 it scores identically with 5.5× less memory | [2026-08-31-e-q8-the-six-does-no-work-a-degree-ablation-collapses-the-hex-overlays-entire-advantage-1.md](2026-08-31-e-q8-the-six-does-no-work-a-degree-ablation-collapses-the-hex-overlays-entire-advantage-1.md) | +| 2026-08-27 | `E-THE-FUSED-PAYLOAD-IS-INERT-AT-EVERY-EXECUTION-GATE-THAT-CONSUMES-IT-1` | | [2026-08-27-e-the-fused-payload-is-inert-at-every-execution-gate-that-consumes-it-1.md](2026-08-27-e-the-fused-payload-is-inert-at-every-execution-gate-that-consumes-it-1.md) | | 2026-08-26 | `E-THE-PERTURBATION-FIELD-NEVER-REACHED-THE-MASK-ALU-1` | the three DTOs are an adapter seam, not an ALU chain: PerturbationDto.energy is dropped, top_k collapses to a min/max window, and the p64 mask ALU is DTO-blind; 4096==4096 is not an address identity (S/4×O/4 vs codebook) — probe gate filed | [2026-08-26-e-the-perturbation-field-never-reached-the-mask-alu-1.md](2026-08-26-e-the-perturbation-field-never-reached-the-mask-alu-1.md) | -| 2026-08-26 | `E-STYLES-ANCHOR-AT-RUNG-4-IS-A-SCALAR-ERA-ARTIFACT-EVERY-INSTANTIATED-STRATUM-CARRIES-A-STYLE-1` | styles-at-rung-4 was the scalar-rung era's address, not the type: under the tower every stratum selects its style from problem-texture resonance; its ΔF is the outcome channel that reinforces, revises, or reopens the selection | [2026-08-26-e-styles-anchor-at-rung-4-is-a-scalar-era-artifact-every-instantiated-stratum-carries-a-style-1.md](2026-08-26-e-styles-anchor-at-rung-4-is-a-scalar-era-artifact-every-instantiated-stratum-carries-a-style-1.md) | | 2026-08-26 | `E-THE-HELIX-POLE-PENALTY-IS-THE-POLAR-BYTE-NOT-THE-CODEC-AND-THE-SPRITE-DECODE-NEVER-TOUCHES-THE-GEOMETRY-1` | measured: BOTH carriers degrade toward the pole, but helix24's term is BOUNDED (∝ y) while helix48's polar byt… | [2026-08-26-e-the-helix-pole-penalty-is-the-polar-byte-not-the-codec-and-the-sprite-decode-never-touches-the-geometry-1.md](2026-08-26-e-the-helix-pole-penalty-is-the-polar-byte-not-the-codec-and-the-sprite-decode-never-touches-the-geometry-1.md) | | 2026-08-26 | `E-THE-FOUR-READINGS-OF-ONE-HELIX-CARRIER-AND-WHY-2Z-IS-CANONICAL-FOR-LUT-OVER-FIELD-1` | measured: for a LUT over a field, `r` distorts a splat kernel 204×, `y` 11.6×, and 1Z/2Z are both EXACTLY unif… | [2026-08-26-e-the-four-readings-of-one-helix-carrier-and-why-2z-is-canonical-for-lut-over-field-1.md](2026-08-26-e-the-four-readings-of-one-helix-carrier-and-why-2z-is-canonical-for-lut-over-field-1.md) | +| 2026-08-26 | `E-THE-ARCHIVE-ROUTE-WAS-3-OF-3-WRONG-1` | the index's ARCHIVE? batch was 3/3 false positives — an unanchored shipped-word match with no notion of what shipped; all three plans were live | [2026-08-26-e-the-archive-route-was-3-of-3-wrong-1.md](2026-08-26-e-the-archive-route-was-3-of-3-wrong-1.md) | +| 2026-08-26 | `E-STYLES-ANCHOR-AT-RUNG-4-IS-A-SCALAR-ERA-ARTIFACT-EVERY-INSTANTIATED-STRATUM-CARRIES-A-STYLE-1` | styles-at-rung-4 was the scalar-rung era's address, not the type: under the tower every stratum selects its style from problem-texture resonance; its ΔF is the outcome channel that reinforces, revises, or reopens the selection | [2026-08-26-e-styles-anchor-at-rung-4-is-a-scalar-era-artifact-every-instantiated-stratum-carries-a-style-1.md](2026-08-26-e-styles-anchor-at-rung-4-is-a-scalar-era-artifact-every-instantiated-stratum-carries-a-style-1.md) | | 2026-08-26 | `E-Q7-FREQUENCY-SIZING-RESCUES-THE-LEARNING-GATE-BUT-NOT-THE-INTERFERENCE-CLAIM-AND-THE-2-BYTE-RAILS-ARE-COMPLEMENTARY-NOT-COMPETING-1` | Q6's hex verdict survives its own repair; PAL is language-portable, I8 is compiler-idiom, and BPE could not be… | [2026-08-26-e-q7-frequency-sizing-rescues-the-learning-gate-but-not-the-interference-claim-and-the-2-byte-rails-are-complementary-not-competing-1.md](2026-08-26-e-q7-frequency-sizing-rescues-the-learning-gate-but-not-the-interference-claim-and-the-2-byte-rails-are-complementary-not-competing-1.md) | | 2026-08-26 | `E-Q6-HEX-FAILS-CONTENT-ADDRESSING-IS-CAPACITY-DESTROYING-UNDER-A-SKEWED-DISTRIBUTION-1` | the hex A/B experiment fails every hypothesis gate (G1–G3) at every cap while both validity gates pass; a rand… | [2026-08-26-e-q6-hex-fails-content-addressing-is-capacity-destroying-under-a-skewed-distribution-1.md](2026-08-26-e-q6-hex-fails-content-addressing-is-capacity-destroying-under-a-skewed-distribution-1.md) | | 2026-08-26 | `E-Q1-THE-ADDITIVE-STORE-CANNOT-INTERFERE-YET-AND-THE-VOCABULARY-IS-ORDER-ROBUST-1` | first plasticity falsifier run: INT is a CONTROL result, ORD passes at 0.872, SAT survives both naive policies… | [2026-08-26-e-q1-the-additive-store-cannot-interfere-yet-and-the-vocabulary-is-order-robust-1.md](2026-08-26-e-q1-the-additive-store-cannot-interfere-yet-and-the-vocabulary-is-order-robust-1.md) | | 2026-08-26 | `E-PALETTE256-IS-A-NEEDLE-THE-COLON-IS-THE-DISTRIBUTION-1` | one index finds a point; only a PAIR carries a distribution, which is why the Fisher-z diagonal returns a cons… | [2026-08-26-e-palette256-is-a-needle-the-colon-is-the-distribution-1.md](2026-08-26-e-palette256-is-a-needle-the-colon-is-the-distribution-1.md) | +| 2026-08-26 | `E-MUL-CALIBRATES-FLOW-MODULATES-1045-FUSED-TWO-ORTHOGONAL-AXES-INTO-ONE-VERDICT-1` | measured storno of the same day's OUTCOME-vs-GROUND thesis: TrustTexture (calibration) and FlowState (Csikszentmihalyi, whose real consumer is FlowState→StyleFamily style adaptation) are orthogonal coordinates MulAssessment already carries apart; the planner's Proceed/Sandbox/Compass IS the diagram's MUL, and contract::mul::GateDecision is the execution gate wearing MUL's name — GateLevel withdrawn | [2026-08-26-e-mul-calibrates-flow-modulates-1045-fused-two-orthogonal-axes-into-one-verdict-1.md](2026-08-26-e-mul-calibrates-flow-modulates-1045-fused-two-orthogonal-axes-into-one-verdict-1.md) | +| 2026-08-26 | `E-ENTROPY-MEASURES-CLOSURE-BITS-59-60-TELL-WHETHER-THE-CLOSURE-HAS-CAUSAL-FOOTING-1` | the humility law measured onto shipped types: the H x ground cross-product already exists as SettlementCell (Glass = unearned closure), 59-60 under the CausalTopology lens already distinguish known/projected/hole, 61-63 gate fills as a permission band, and the Sudoku walker turns entropy into search pressure toward constraint-bounded epistemic holes | [2026-08-26-e-entropy-measures-closure-bits-59-60-tell-whether-the-closure-has-causal-footing-1.md](2026-08-26-e-entropy-measures-closure-bits-59-60-tell-whether-the-closure-has-causal-footing-1.md) | +| 2026-08-26 | `E-A-RECORDED-ALPHA-IS-INSTRUMENTATION-UNTIL-AN-INTERVENTION-ON-IT-MOVES-THE-NEXT-TRANSITION-1` | humility about introspection (vs #1057's humility about the world): a claimed alpha must move the next DispatchMode election when perturbed and stay silent when an unclaimed state is perturbed — the can-fire/can-stay-silent twin aimed inward, with a target that pre-declares its own null (dispatch_mode reads logical markers, never qualia); five-metric faithfulness stack computable from a receipt without an LLM judge | [2026-08-26-e-a-recorded-alpha-is-instrumentation-until-an-intervention-on-it-moves-the-next-transition-1.md](2026-08-26-e-a-recorded-alpha-is-instrumentation-until-an-intervention-on-it-moves-the-next-transition-1.md) | +| 2026-08-26 | `E-A-HOT-PATH-FIX-NARROWED-A-PUBLIC-CONTRACT-WORKSPACE-GREEN-IS-NOT-CONTRACT-GREEN-1` | #1045's hot-path de-stringing was right at its own layer and still narrowed a public contract: MUL-specific ground (TrustTexture/FlowState) became mandatory in the universal gate outcome, so no other producer can say Block without claiming MUL provenance; the break is live in ada-rs against an unbound git dep, and every workspace gate stayed green | [2026-08-26-e-a-hot-path-fix-narrowed-a-public-contract-workspace-green-is-not-contract-green-1.md](2026-08-26-e-a-hot-path-fix-narrowed-a-public-contract-workspace-green-is-not-contract-green-1.md) | | 2026-08-25 | `E-W0-THE-SPACE-ORDINAL-IS-A-RANK-RELATIVE-TO-A-TABLE-THE-CLASSID-NEVER-NAMES-1` | W0 run: zero custom spaces in 94,536 rows, so the defect is LATENT; but the mechanism is worse than the conjec… | [2026-08-25-e-w0-the-space-ordinal-is-a-rank-relative-to-a-table-the-classid-never-names-1.md](2026-08-25-e-w0-the-space-ordinal-is-a-rank-relative-to-a-table-the-classid-never-names-1.md) | | 2026-08-25 | `E-W0-IS-LIVE-ON-THE-6502-AND-ITS-MAIN-MEMORY-IS-NOT-SpaceId-Ram-1` | the arch census: 6502 mints TWO custom spaces, one of them its own RAM, because the alias map is case-sensitiv… | [2026-08-25-e-w0-is-live-on-the-6502-and-its-main-memory-is-not-spaceid-ram-1.md](2026-08-25-e-w0-is-live-on-the-6502-and-its-main-memory-is-not-spaceid-ram-1.md) | | 2026-08-25 | `E-THE-QA-MACHINERY-IS-THE-LEARNING-RULE-1` | operator reframing: the transfer probe + the reversible-crystal gates are not quality control OVER a learner; … | [2026-08-25-e-the-qa-machinery-is-the-learning-rule-1.md](2026-08-25-e-the-qa-machinery-is-the-learning-rule-1.md) | | 2026-08-25 | `E-R2IL-MACRO-VOCABULARY-TRANSFERS-ACROSS-COMPILER-AND-LANGUAGE-1` | a macro vocabulary learned from two gcc binaries fires in unseen gcc code at −0.6% density and in unseen rustc… | [2026-08-25-e-r2il-macro-vocabulary-transfers-across-compiler-and-language-1.md](2026-08-25-e-r2il-macro-vocabulary-transfers-across-compiler-and-language-1.md) | -| 2026-08-24 | `e-git-sourced-crate-cannot-path-dep-outside-its-repo-1` | | [2026-08-24-e-git-sourced-crate-cannot-path-dep-outside-its-repo-1.md](2026-08-24-e-git-sourced-crate-cannot-path-dep-outside-its-repo-1.md) | | 2026-08-24 | `E-R2IL-BPE-RECOMBINATION-FALSIFIERS-CONFIRMED-1` | the typed genetic recombination proposal's three §7 falsifiers all run green: splice points exist selectively … | [2026-08-24-e-r2il-bpe-recombination-falsifiers-confirmed-1.md](2026-08-24-e-r2il-bpe-recombination-falsifiers-confirmed-1.md) | | 2026-08-24 | `E-PHI-WEYL-STAMP-CASCADE-PRECISION-RULING-1` | φ-Weyl 2-level Morton stamp cascade: coprime strides give identical discrimination, gcd>1 strides concentrate,… | [2026-08-24-e-phi-weyl-stamp-cascade-precision-ruling-1.md](2026-08-24-e-phi-weyl-stamp-cascade-precision-ruling-1.md) | +| 2026-08-24 | `e-git-sourced-crate-cannot-path-dep-outside-its-repo-1` | `cognitive-stack`'s OGAR deps fixed the same way; its `ndarray` dep left path-only, and why: a same-version git+path duplicate is a real type-identity hazard, not just style | [2026-08-24-e-git-sourced-crate-cannot-path-dep-outside-its-repo-1.md](2026-08-24-e-git-sourced-crate-cannot-path-dep-outside-its-repo-1.md) | | 2026-08-24 | `E-BPE-OVER-DEFUSE-CHAINS-BEATS-LINEAR-AND-FITS-LOCO-1` | R2IL x BPE POC, corrected twice (codex review + architecture review): real per-occurrence immediates, per-merg… | [2026-08-24-e-bpe-over-defuse-chains-beats-linear-and-fits-loco-1.md](2026-08-24-e-bpe-over-defuse-chains-beats-linear-and-fits-loco-1.md) | | 2026-08-23 | `E-TYPE-COMPLEXITY-EXPOSED-A-MEMORY-ABI-ESCAPE-1` | the clippy warning was the surface symptom; `BeliefArena` is an independent AoS cognitive population owner out… | [2026-08-23-e-type-complexity-exposed-a-memory-abi-escape-1.md](2026-08-23-e-type-complexity-exposed-a-memory-abi-escape-1.md) | | 2026-08-23 | `E-TWO-KEY-ELEVATION-WINDOW-IS-NARROW-AND-THE-CORPUS-STRADDLES-IT-1` | one `RungElevator` actuator path is driven end-to-end; the two shipped rules that must agree for elevation ove… | [2026-08-23-e-two-key-elevation-window-is-narrow-and-the-corpus-straddles-it-1.md](2026-08-23-e-two-key-elevation-window-is-narrow-and-the-corpus-straddles-it-1.md) | @@ -77,10 +81,10 @@ up in exactly one of them, never both. | 2026-08-22 | `E-A-DOC-COMMENT-CAN-GIVE-THE-WRONG-REASON-FOR-A-CORRECT-GUARD-1` | the guard was right, the justification was false, and the test read the justification | [2026-08-22-e-a-doc-comment-can-give-the-wrong-reason-for-a-correct-guard-1.md](2026-08-22-e-a-doc-comment-can-give-the-wrong-reason-for-a-correct-guard-1.md) | | 2026-08-22 | `E-A-CRATE-WITH-ZERO-CONSUMERS-IS-BUILT-BY-NOTHING-AND-CAN-BE-MERGED-BROKEN-1` | the hydration crate did not compile at `main`, and its own doc says why nobody found out | [2026-08-22-e-a-crate-with-zero-consumers-is-built-by-nothing-and-can-be-merged-broken-1.md](2026-08-22-e-a-crate-with-zero-consumers-is-built-by-nothing-and-can-be-merged-broken-1.md) | | 2026-08-22 | `E-A-CONSTANT-OFFSET-CANNOT-ALIGN-TWO-VERSIFICATIONS-1` | the versification map's KJV side is exact, and 51 of its offsets address a verse that does not exist; the shap… | [2026-08-22-e-a-constant-offset-cannot-align-two-versifications-1.md](2026-08-22-e-a-constant-offset-cannot-align-two-versifications-1.md) | -| 2026-08-21 | `e-r2il-varnodefacet-is-a-g3-carving-and-0xc4-would-birth-a-class-into-it-1` | | [2026-08-21-e-r2il-varnodefacet-is-a-g3-carving-and-0xc4-would-birth-a-class-into-it-1.md](2026-08-21-e-r2il-varnodefacet-is-a-g3-carving-and-0xc4-would-birth-a-class-into-it-1.md) | | 2026-08-21 | `E-V4-IS-THE-100-PERCENT-TIER-V3-UNCHANGED-1` | operator ruling: V4 is a SIBLING for lossless/special-need coverage, not a successor | [2026-08-21-e-v4-is-the-100-percent-tier-v3-unchanged-1.md](2026-08-21-e-v4-is-the-100-percent-tier-v3-unchanged-1.md) | | 2026-08-21 | `E-THE-ORACLE-POPULATION-IS-64-PERCENT-AND-A-GATE-HARDCODES-THE-OTHER-36-1` | a third of the "known intermediates" name no intermediate, and the gate that would have caught it asserts the … | [2026-08-21-e-the-oracle-population-is-64-percent-and-a-gate-hardcodes-the-other-36-1.md](2026-08-21-e-the-oracle-population-is-64-percent-and-a-gate-hardcodes-the-other-36-1.md) | | 2026-08-21 | `E-THE-ATTENTION-ATOM-WAS-ALREADY-SHIPPED-WHAT-WAS-MISSING-WAS-A-COMPOSITION-THAT-IS-NOT-OR-1` | D-ACR-1's basis is a reuse, and the only real gap was that every set operation in the crate is a bitset union | [2026-08-21-e-the-attention-atom-was-already-shipped-what-was-missing-was-a-composition-that-is-not-or-1.md](2026-08-21-e-the-attention-atom-was-already-shipped-what-was-missing-was-a-composition-that-is-not-or-1.md) | +| 2026-08-21 | `e-r2il-varnodefacet-is-a-g3-carving-and-0xc4-would-birth-a-class-into-it-1` | | [2026-08-21-e-r2il-varnodefacet-is-a-g3-carving-and-0xc4-would-birth-a-class-into-it-1.md](2026-08-21-e-r2il-varnodefacet-is-a-g3-carving-and-0xc4-would-birth-a-class-into-it-1.md) | | 2026-08-21 | `E-HHTL-IS-MINTED-IN-THE-ARTIFACT-NOBODY-CITES-1` | "zero on every baked row in both production bakes" is precise about the two it names and silent about the thir… | [2026-08-21-e-hhtl-is-minted-in-the-artifact-nobody-cites-1.md](2026-08-21-e-hhtl-is-minted-in-the-artifact-nobody-cites-1.md) | | 2026-08-21 | `E-FROM-V1-DROPS-PROVENANCE-AND-THE-COUNCIL-CAUGHT-THE-CONTRACT-ABOUT-TO-TRUST-IT-1` | three BLOCK(P0)s in one 5+3 run, and the sharpest one falsified the spec's own asymmetry claim against the cod… | [2026-08-21-e-from-v1-drops-provenance-and-the-council-caught-the-contract-about-to-trust-it-1.md](2026-08-21-e-from-v1-drops-provenance-and-the-council-caught-the-contract-about-to-trust-it-1.md) | | 2026-08-21 | `E-DISMECH-KNOWN-INTERMEDIATES-ARE-PROSE-NOT-IDENTITIES-1` | the 3,978-edge "ORACLE population" is 2,489 edges, and its mediators are 5-word prose, not node references | [2026-08-21-e-dismech-known-intermediates-are-prose-not-identities-1.md](2026-08-21-e-dismech-known-intermediates-are-prose-not-identities-1.md) | @@ -88,19 +92,19 @@ up in exactly one of them, never both. | 2026-08-21 | `E-ADDRESS-FROM-THE-THING-NOT-THE-ACCIDENT-1` | the two blocked gates are one failure on two axes | [2026-08-21-e-address-from-the-thing-not-the-accident-1.md](2026-08-21-e-address-from-the-thing-not-the-accident-1.md) | | 2026-08-21 | `E-ACADEMIC-CARVE-UNDERFILLS-ROWS-ARE-NOT-WORDS-1` | 20,845 COCA rows are 18,559 distinct words, so the 80×256 academic carve fills 90.6% and basins 73..79 are emp… | [2026-08-21-e-academic-carve-underfills-rows-are-not-words-1.md](2026-08-21-e-academic-carve-underfills-rows-are-not-words-1.md) | | 2026-08-21 | `E-ABBREVIATION-GREP-MANUFACTURED-AN-ABSENCE-1` | I reported a shipped 15-module subsystem as non-existent because `fn .*ppr` matches `approx`, and a `head` lim… | [2026-08-21-e-abbreviation-grep-manufactured-an-absence-1.md](2026-08-21-e-abbreviation-grep-manufactured-an-absence-1.md) | +| 2026-08-20 | `I-STRINGS-ARE-CAM-INDEX-ONLY-1` | strings in the hot path resolve through a codebook; the ONLY string home is the CAM index codebook; NEVER in a… | [2026-08-20-i-strings-are-cam-index-only-1.md](2026-08-20-i-strings-are-cam-index-only-1.md) | +| 2026-08-20 | `E-WORDNET-IS-A-LOCALITY-PRIOR-NOT-AN-IDENTITY-ENCODING-1` | #875 measured a taxonomy-informed HHTL *search prior*; it did NOT prove an injective WordNet address, and a se… | [2026-08-20-e-wordnet-is-a-locality-prior-not-an-identity-encoding-1.md](2026-08-20-e-wordnet-is-a-locality-prior-not-an-identity-encoding-1.md) | | 2026-08-20 | `e-v3-is-representation-invariant-on-the-planner-ce64-leg-1` | | [2026-08-20-e-v3-is-representation-invariant-on-the-planner-ce64-leg-1.md](2026-08-20-e-v3-is-representation-invariant-on-the-planner-ce64-leg-1.md) | | 2026-08-20 | `e-the-recipe-surface-is-causally-blind-1` | | [2026-08-20-e-the-recipe-surface-is-causally-blind-1.md](2026-08-20-e-the-recipe-surface-is-causally-blind-1.md) | | 2026-08-20 | `e-the-filter-was-filtering-on-the-wrong-predicate-1` | | [2026-08-20-e-the-filter-was-filtering-on-the-wrong-predicate-1.md](2026-08-20-e-the-filter-was-filtering-on-the-wrong-predicate-1.md) | | 2026-08-20 | `e-the-coverage-fix-is-real-and-asymmetric-1` | | [2026-08-20-e-the-coverage-fix-is-real-and-asymmetric-1.md](2026-08-20-e-the-coverage-fix-is-real-and-asymmetric-1.md) | | 2026-08-20 | `e-the-compat-enum-was-eating-half-the-register-1` | | [2026-08-20-e-the-compat-enum-was-eating-half-the-register-1.md](2026-08-20-e-the-compat-enum-was-eating-half-the-register-1.md) | | 2026-08-20 | `e-the-audit-gate-was-pinning-the-bug-1` | | [2026-08-20-e-the-audit-gate-was-pinning-the-bug-1.md](2026-08-20-e-the-audit-gate-was-pinning-the-bug-1.md) | -| 2026-08-20 | `e-capability-is-not-reachability-1` | | [2026-08-20-e-capability-is-not-reachability-1.md](2026-08-20-e-capability-is-not-reachability-1.md) | -| 2026-08-20 | `e-a-watcher-that-cannot-dissent-is-not-a-watcher-1` | | [2026-08-20-e-a-watcher-that-cannot-dissent-is-not-a-watcher-1.md](2026-08-20-e-a-watcher-that-cannot-dissent-is-not-a-watcher-1.md) | -| 2026-08-20 | `I-STRINGS-ARE-CAM-INDEX-ONLY-1` | strings in the hot path resolve through a codebook; the ONLY string home is the CAM index codebook; NEVER in a… | [2026-08-20-i-strings-are-cam-index-only-1.md](2026-08-20-i-strings-are-cam-index-only-1.md) | -| 2026-08-20 | `E-WORDNET-IS-A-LOCALITY-PRIOR-NOT-AN-IDENTITY-ENCODING-1` | #875 measured a taxonomy-informed HHTL *search prior*; it did NOT prove an injective WordNet address, and a se… | [2026-08-20-e-wordnet-is-a-locality-prior-not-an-identity-encoding-1.md](2026-08-20-e-wordnet-is-a-locality-prior-not-an-identity-encoding-1.md) | | 2026-08-20 | `E-S3-0-NEEDED-NO-NEW-ADDRESS-1` | the Stage-3 "S3.0 address" slot is closed as NOT-NEEDED; `IdentityQuad` already carries an exact four-componen… | [2026-08-20-e-s3-0-needed-no-new-address-1.md](2026-08-20-e-s3-0-needed-no-new-address-1.md) | | 2026-08-20 | `E-NIBLEPATH-DEPTH-IS-NOT-HHTL-DIMENSIONALITY-1` | retracts #973's `E-THE-LITERAL-CANNOT-LIVE-IN-THE-PATH-IT-ROOTS-1` | [2026-08-20-e-niblepath-depth-is-not-hhtl-dimensionality-1.md](2026-08-20-e-niblepath-depth-is-not-hhtl-dimensionality-1.md) | | 2026-08-20 | `E-DISMECH-CORPUS-CENSUS-1` | the DisMech corpus measured: 87.2 MB of strings, of which the entire causal semantics is bits + codebook ordin… | [2026-08-20-e-dismech-corpus-census-1.md](2026-08-20-e-dismech-corpus-census-1.md) | +| 2026-08-20 | `e-capability-is-not-reachability-1` | | [2026-08-20-e-capability-is-not-reachability-1.md](2026-08-20-e-capability-is-not-reachability-1.md) | +| 2026-08-20 | `e-a-watcher-that-cannot-dissent-is-not-a-watcher-1` | | [2026-08-20-e-a-watcher-that-cannot-dissent-is-not-a-watcher-1.md](2026-08-20-e-a-watcher-that-cannot-dissent-is-not-a-watcher-1.md) | | 2026-08-20 | `E-A-LOCAL-DERIVATION-CANNOT-OVERRULE-A-MEASURED-COUNTEREXAMPLE-1` | and its twin: a counterexample cited past its own Boundaries section is the same failure with the sign flipped | [2026-08-20-e-a-local-derivation-cannot-overrule-a-measured-counterexample-1.md](2026-08-20-e-a-local-derivation-cannot-overrule-a-measured-counterexample-1.md) | | 2026-08-19 | `e-xc21-harness-confirms-c2-and-finds-dead-code-1` | | [2026-08-19-e-xc21-harness-confirms-c2-and-finds-dead-code-1.md](2026-08-19-e-xc21-harness-confirms-c2-and-finds-dead-code-1.md) | | 2026-08-19 | `e-two-witness-shapes-contest-one-landing-zone-1` | | [2026-08-19-e-two-witness-shapes-contest-one-landing-zone-1.md](2026-08-19-e-two-witness-shapes-contest-one-landing-zone-1.md) | @@ -169,4 +173,3 @@ up in exactly one of them, never both. | 2026-08-06 | `E-AN-IDENTITY-SLOT-IS-NOT-A-RAIL-REF-WHICH-IS-WHY-A-WIDE-CARVING-CAN-BE-CORRECT-1` | the byte-axis rule is a rule about REFERENCES, and an exact identity is not one | [2026-08-06-e-an-identity-slot-is-not-a-rail-ref-which-is-why-a-wide-carving-can-be-correct-1.md](2026-08-06-e-an-identity-slot-is-not-a-rail-ref-which-is-why-a-wide-carving-can-be-correct-1.md) | | 2026-08-06 | `E-A-SORTED-CODEBOOK-ORDINAL-IS-A-PROPERTY-OF-THE-KEY-SET-NOT-THE-KEY-1` | a within-book bijectivity witness cannot see a between-book shift, and that is the gap review found | [2026-08-06-e-a-sorted-codebook-ordinal-is-a-property-of-the-key-set-not-the-key-1.md](2026-08-06-e-a-sorted-codebook-ordinal-is-a-property-of-the-key-set-not-the-key-1.md) | | 2026-08-06 | `E-A-REPEATABLE-TRANSFER-IS-NOT-IDEMPOTENCE-OVER-A-MULTI-FILE-DIRECTORY-1` | the PR #901 review round: four corrections, one of them load-bearing on a safety claim | [2026-08-06-e-a-repeatable-transfer-is-not-idempotence-over-a-multi-file-directory-1.md](2026-08-06-e-a-repeatable-transfer-is-not-idempotence-over-a-multi-file-directory-1.md) | -| 2026-08-26 | `E-THE-ARCHIVE-ROUTE-WAS-3-OF-3-WRONG-1` | the index's ARCHIVE? batch was 3/3 false positives — an unanchored shipped-word match with no notion of what shipped; all three plans were live | [2026-08-26-e-the-archive-route-was-3-of-3-wrong-1.md](2026-08-26-e-the-archive-route-was-3-of-3-wrong-1.md) | diff --git a/.claude/tools/entries_index.py b/.claude/tools/entries_index.py new file mode 100644 index 000000000..bd26a6b48 --- /dev/null +++ b/.claude/tools/entries_index.py @@ -0,0 +1,418 @@ +#!/usr/bin/env python3 +"""Generate `.claude/board/entries/README.md` — the transient-tier index. + +WHY GENERATED +------------- +The index was hand-maintained and went stale exactly the way a hand-maintained +index does. Measured 2026-09-20, before this generator existed: + + * its header claimed "135 entries, 2026-08-06 .. 2026-08-26" against **144** + files / 142 rows / range 2026-08-06 .. **2026-08-31**; + * its OWN falsifier #2 was RED — two entry files had landed with no index row + (`2026-08-27-e-the-fused-payload-…-1`, `2026-08-31-e-q8-…-1`), i.e. the + exact stranding the README says the check exists to catch; + * one row sat out of date order. + +Nothing ran those falsifiers: they were shell snippets in a README, and the +directory is in no structural gate. So the stranding was invisible by +construction, which is the same shape as every other drift this workspace +gates mechanically (`supersession_index.py`, `citation_decay.py`, +`append_only_gate.py`). + +WHAT IS DERIVED AND WHAT IS CARRIED FORWARD (this asymmetry is measured) +----------------------------------------------------------------------- +Entry files do NOT share a heading shape. All four of these are live on disk: + + ### E-ID-1 + ## 2026-08-19 — E-ID-1 + # E-ID-1 (with a separate `**Date:** 2026-08-27` line) + ## 2026-08-31 — E-ID-1 — + +So: + + * `date` comes from the FILENAME, which IS uniform (`YYYY-MM-DD-.md`). + Never from the heading — three of the four shapes do not carry it. + * `file` is the filename. + * `id` is carried forward when the file is already indexed (so the existing + mixed case is preserved rather than mass-rewritten), else recovered from + the heading, else derived from the slug. + * `finding` is **carried forward verbatim**. It is NOT derivable: over 100 + rows carry a hand-written one-line summary that no heading shape contains. + A generator that "derived" this column would silently delete curation. + For a NEW entry it is taken from the heading's second em-dash segment when + that shape is used, else left empty — exactly today's behaviour. + +Curation therefore stays possible in the `finding` cell; structure (which rows +exist, their dates, their order, the counts) is enforced. + +THE TRUNCATION TRAP — WHY THERE IS NO `>` USAGE +----------------------------------------------- +Because the committed index is an INPUT (the carried-forward prose), the house +convention `python3 tool.py > target.md` would have the shell TRUNCATE the file +before this script reads it, destroying every curated summary in one keystroke. +That is the destructive-prepend law in root `CLAUDE.md` +(`.claude/knowledge/never-truncate-a-file-you-still-need-to-read.md`), and it +is a live risk here precisely because the sibling generator IS used that way. + +Hence: default prints to stdout for DIFFING only; `--write` is the sole +sanctioned mutation and does read-then-write; and `--write` REFUSES to emit +fewer non-empty `finding` cells than the committed file already has unless +`--allow-finding-loss` is passed. That guard is the semantic form of the +no-shrink gate: for a generated table the meaningful quantity is curated cells, +not lines. + +USAGE + python3 .claude/tools/entries_index.py # print (for diffing) + python3 .claude/tools/entries_index.py --write # regenerate in place + python3 .claude/tools/entries_index.py --check # CI: falsifiers + staleness + python3 .claude/tools/entries_index.py --self-test + +Pure stdlib. +""" + +from __future__ import annotations + +import os +import re +import subprocess +import sys + +ENTRIES_DIR = ".claude/board/entries" +INDEX = os.path.join(ENTRIES_DIR, "README.md") + +FILE_RE = re.compile(r"^(\d{4}-\d{2}-\d{2})-(.+)\.md$") +# The link target inside the `file` cell: `[text](2026-08-06-foo-1.md)`. +LINK_TARGET_RE = re.compile(r"\(([^()]*\.md)\)") +# An id in a heading, with or without a leading date and surrounding markup. +HEADING_RE = re.compile(r"^#{1,4}\s+(.*)$") +ID_IN_HEADING_RE = re.compile(r"\b((?:E|D|I|ISS|PROBE|ADR|EXP)-[A-Z0-9][A-Za-z0-9-]{2,})\b") + + +def repo_root() -> str: + out = subprocess.run( + ["git", "rev-parse", "--show-toplevel"], capture_output=True, text=True + ) + return out.stdout.strip() or "." + + +def parse_index(text: str) -> dict[str, dict[str, str]]: + """Existing rows, keyed by the `file` cell's link target. + + Keyed on the link TARGET rather than the id, because the target is what + both falsifiers resolve against and the only cell that must match a real + path. A row whose target is unparseable is dropped from carry-forward -- + it cannot be matched to a file, which is itself the finding. + + Cells are split on `|` and rejoined for the middle column, so a `finding` + containing a literal pipe survives a round trip instead of shifting every + column right of it. + """ + rows: dict[str, dict[str, str]] = {} + for line in text.splitlines(): + if not line.startswith("| 20"): + continue + parts = line.split("|") + if len(parts) < 6: + continue + date = parts[1].strip() + entry_id = parts[2].strip() + finding = "|".join(parts[3:-2]).strip() + file_cell = parts[-2].strip() + m = LINK_TARGET_RE.search(file_cell) + if not m: + continue + rows[m.group(1)] = {"date": date, "id": entry_id, "finding": finding} + return rows + + +def recover_from_file(path: str) -> tuple[str, str]: + """(id, inline_finding) recovered from the entry's own first heading. + + Handles all four shapes measured on disk. The inline finding is the SECOND + em-dash segment of a `## ` heading; the other + shapes have none, and the caller leaves the cell empty rather than + inventing one. + """ + try: + with open(path, encoding="utf-8", errors="ignore") as fh: + for line in fh: + m = HEADING_RE.match(line.strip()) + if not m: + continue + head = m.group(1).strip() + segments = [s.strip() for s in head.split("—")] + ident = "" + for seg in segments: + hit = ID_IN_HEADING_RE.search(seg) + if hit: + ident = hit.group(1) + break + inline = "" + if ident and len(segments) >= 3: + tail = segments[2:] + inline = " — ".join(t for t in tail if t).strip() + return ident, inline + except OSError: + pass + return "", "" + + +def falsifiers(root: str) -> list[str]: + """The README's own three structural checks, as code rather than prose. + + Same three, same directions, unchanged in meaning: + 1. every index row's file resolves (catches a row whose file never landed) + 2. every file has an index row (catches a file that landed with no row) + 3. no duplicate entry id + 1 and 2 are deliberately opposite; a stranding shows up in exactly one. + """ + d = os.path.join(root, ENTRIES_DIR) + index_path = os.path.join(root, INDEX) + try: + with open(index_path, encoding="utf-8") as fh: + rows = parse_index(fh.read()) + except OSError: + return [f"FATAL: cannot read {INDEX}"] + + on_disk = sorted(f for f in os.listdir(d) if FILE_RE.match(f)) + problems: list[str] = [] + + for target in sorted(rows): + if not os.path.isfile(os.path.join(d, target)): + problems.append(f"DANGLING: {target} (index row with no file)") + + for f in on_disk: + if f not in rows: + problems.append(f"UNREFERENCED: {f} (file with no index row)") + + seen: dict[str, int] = {} + for meta in rows.values(): + key = meta["id"].strip("`").upper() + seen[key] = seen.get(key, 0) + 1 + for key, n in sorted(seen.items()): + if n > 1 and key: + problems.append(f"DUPLICATE ID: {key} ({n} rows)") + + return problems + + +def render(root: str) -> str: + d = os.path.join(root, ENTRIES_DIR) + try: + with open(os.path.join(root, INDEX), encoding="utf-8") as fh: + prior = parse_index(fh.read()) + except OSError: + prior = {} + + files = sorted(f for f in os.listdir(d) if FILE_RE.match(f)) + rows = [] + for f in files: + m = FILE_RE.match(f) + assert m # guarded by the filter above + date, slug = m.group(1), m.group(2) + carried = prior.get(f, {}) + ident = carried.get("id", "") + finding = carried.get("finding", "") + if not ident or not finding: + rec_id, rec_finding = recover_from_file(os.path.join(d, f)) + if not ident: + ident = f"`{rec_id}`" if rec_id else f"`{slug}`" + if not finding: + finding = rec_finding + rows.append((date, ident, finding, f)) + + # Newest first; filename as the tie-break so the order is total and stable. + rows.sort(key=lambda r: (r[0], r[3]), reverse=True) + + dates = [r[0] for r in rows] + out: list[str] = [] + out.append("# Board entries — one file per finding\n") + out.append("") + out.append("> **GENERATED — do not hand-edit the table's structure.**") + out.append("> `python3 .claude/tools/entries_index.py --write`") + out.append(">") + out.append("> Each entry is `YYYY-MM-DD-.md`, carrying the entry **verbatim**.") + out.append("> This table is the index; the files are the content. A row whose file does") + out.append("> not resolve is a broken reference — that is the falsifier, and it is why") + out.append("> the index and the content are separate objects.") + out.append(">") + out.append("> The `finding` cell is the ONE hand-curated column: it is carried forward") + out.append("> verbatim on every regeneration, because the entry files do not share a") + out.append("> heading shape and it cannot be derived. Edit it freely. `date`, `id`,") + out.append("> `file`, the ordering and the counts are derived and will be overwritten.") + out.append(">") + out.append("> **Never `… > README.md`.** This file is an INPUT to its own generator, so") + out.append("> a shell redirect truncates it before the script reads it and every curated") + out.append("> `finding` is lost. Use `--write`, which reads first and refuses to drop") + out.append("> curated cells.") + out.append("") + out.append("**Falsifiers** — now executed by CI (`entries_index.py --check`), not just") + out.append("described here: (1) every index row's file resolves, (2) every file has an") + out.append("index row, (3) no duplicate entry id. Checks 1 and 2 are deliberately") + out.append("opposite directions; the stranding this convention prevents shows up in") + out.append("exactly one of them, never both.") + out.append("") + if rows: + out.append(f"{len(rows)} entries, {min(dates)} .. {max(dates)}.") + else: + out.append("0 entries.") + out.append("") + out.append("| date | entry id | finding | file |") + out.append("|---|---|---|---|") + for date, ident, finding, f in rows: + # Link TEXT keeps the trailing `.md`: that is the existing convention in + # 138 of 142 committed rows, and normalising it away would churn every + # row of the diff to change nothing a reader sees differently. + out.append(f"| {date} | {ident} | {finding} | [{f}]({f}) |") + out.append("") + return "\n".join(out) + + +def nonempty_findings(text: str) -> int: + return sum(1 for meta in parse_index(text).values() if meta["finding"]) + + +def committed_findings_at_head(root: str) -> int: + """Curated `finding` cells in the index as COMMITTED at git HEAD. + + The write guard's reference point. It must not be the working file: the + generated table carries its prose forward FROM that file, so a truncated + working copy drags the "after" count down with the "before" count and the + guard silently passes. HEAD is outside the shell's reach. + + A path absent at HEAD (the first-ever add) returns 0, which correctly makes + the guard inert rather than blocking the initial commit. + """ + out = subprocess.run( + ["git", "-C", root, "show", f"HEAD:{INDEX}"], + capture_output=True, + text=True, + ) + if out.returncode != 0: + return 0 + return nonempty_findings(out.stdout) + + +def main(argv: list[str]) -> int: + if "--self-test" in argv: + return self_test() + + root = repo_root() + index_path = os.path.join(root, INDEX) + generated = render(root) + + if "--check" in argv: + problems = falsifiers(root) + for p in problems: + print(f" {p}") + try: + with open(index_path, encoding="utf-8") as fh: + committed = fh.read() + except OSError: + print(f"::error::{INDEX} is missing") + return 1 + stale = committed != generated + if stale: + print(f"::error::{INDEX} is stale.") + print("It is GENERATED from the entry files in .claude/board/entries/.") + print("Regenerate and commit:") + print(" python3 .claude/tools/entries_index.py --write") + print("NEVER `… > README.md` — the file is its own input and a redirect") + print("truncates it before the generator reads it.") + if problems: + print("::error::the entries tier failed a structural falsifier (see above).") + print("A file with no row is invisible to every index consumer; a row with") + print("no file is a broken reference. `--write` fixes both by regenerating.") + if stale or problems: + return 1 + print(f"entries index is current and structurally sound ({len(parse_index(generated))} rows)") + return 0 + + if "--write" in argv: + # The reference is git HEAD, NOT the working file. Comparing against the + # working file makes this guard VACUOUS for the one trap it exists to + # catch: the generated output is DERIVED from that file, so truncating + # it lowers both sides equally and an emptied index writes cleanly + # (measured -- the first version of this guard returned 0 on a blanked + # index, and a `>` redirect would have yielded before=after=0). HEAD is + # the last state a shell redirect cannot have destroyed. + before = committed_findings_at_head(root) + after = nonempty_findings(generated) + if after < before and "--allow-finding-loss" not in argv: + print( + f"::error::refusing to write: curated `finding` cells would drop " + f"{before} -> {after}.", + file=sys.stderr, + ) + print( + "The `finding` column is hand-written and carried forward; losing cells " + "means the index was truncated before being read (a `>` redirect) or an " + "entry file was renamed out from under its row. Investigate rather than " + "overwrite. `--allow-finding-loss` forces it.", + file=sys.stderr, + ) + return 1 + with open(index_path, "w", encoding="utf-8") as fh: + fh.write(generated) + print(f"wrote {INDEX}: {len(parse_index(generated))} rows, {after} curated findings") + return 0 + + sys.stdout.write(generated) + return 0 + + +def self_test() -> int: + """Unit checks on the two things that can silently lose data.""" + fails = [] + + # 1. a `finding` containing a literal pipe survives a round trip. + piped = ( + "| date | entry id | finding | file |\n" + "|---|---|---|---|\n" + "| 2026-08-06 | `E-X-1` | a \\| b and more | [2026-08-06-e-x-1](2026-08-06-e-x-1.md) |\n" + ) + got = parse_index(piped) + if got.get("2026-08-06-e-x-1.md", {}).get("finding") != "a \\| b and more": + fails.append(f"pipe-in-finding round trip: got {got}") + + # 2. the carried-forward count is what the write guard compares. + if nonempty_findings(piped) != 1: + fails.append("nonempty_findings miscounted a single curated cell") + empty = ( + "| date | entry id | finding | file |\n" + "|---|---|---|---|\n" + "| 2026-08-06 | `E-X-1` | | [2026-08-06-e-x-1](2026-08-06-e-x-1.md) |\n" + ) + if nonempty_findings(empty) != 0: + fails.append("nonempty_findings counted an empty cell as curated") + + # 3. all four measured heading shapes yield an id; only the 3-segment one + # yields an inline finding. + import tempfile + + shapes = [ + ("### E-THE-A-1\n", "E-THE-A-1", ""), + ("## 2026-08-19 — E-THE-B-1\n", "E-THE-B-1", ""), + ("# E-THE-C-1\n\n**Date:** 2026-08-27\n", "E-THE-C-1", ""), + ("## 2026-08-31 — E-THE-D-1 — the six does no work\n", "E-THE-D-1", + "the six does no work"), + ] + with tempfile.TemporaryDirectory() as td: + for i, (body, want_id, want_find) in enumerate(shapes): + p = os.path.join(td, f"2026-08-0{i+1}-e-the-x-1.md") + with open(p, "w", encoding="utf-8") as fh: + fh.write(body) + gid, gfind = recover_from_file(p) + if gid != want_id: + fails.append(f"shape {i}: id {gid!r} != {want_id!r}") + if gfind != want_find: + fails.append(f"shape {i}: inline finding {gfind!r} != {want_find!r}") + + for f in fails: + print(f" FAIL {f}") + print("self-test: " + ("ALL PASSED" if not fails else f"{len(fails)} FAILURE(S)")) + return 1 if fails else 0 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv[1:])) diff --git a/.github/workflows/supersession-index.yml b/.github/workflows/supersession-index.yml index 6550a6df7..780ea7a49 100644 --- a/.github/workflows/supersession-index.yml +++ b/.github/workflows/supersession-index.yml @@ -25,6 +25,13 @@ on: # filter had not caught up. - .claude/board/entries/** - .claude/board/EPIPHANIES.md + # The entries tier's OWN generator + index. Added 2026-09-20 with + # `entries_index.py`: the index was hand-maintained, its header claimed + # 135 entries against 144 files, and its own falsifier #2 was red on two + # stranded files -- invisible because the three checks were shell + # snippets in a README that nothing executed. + - .claude/tools/entries_index.py + - .claude/board/entries/README.md # `crates/` decides the "live" column (:27 globs it per symbol). Broad, # and deliberately so: a symbol deleted from the tree changes the table, # and the generator takes ~15 s, so the gate is cheap next to the Rust @@ -59,3 +66,12 @@ jobs: exit 1 fi echo "index is current" + # The transient tier's index is generated too, and by a SEPARATE + # generator: `supersession_index.py` reads `entries/*.md` only to count + # D-id coverage and never writes this table. One step, both gates -- + # staleness AND the three structural falsifiers (row with no file / file + # with no row / duplicate id), which until now existed only as prose. + - name: Entries index is current and structurally sound + run: python3 .claude/tools/entries_index.py --check + - name: Entries index generator self-test + run: python3 .claude/tools/entries_index.py --self-test diff --git a/CLAUDE.md b/CLAUDE.md index 15816d462..4b550d8f6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -342,6 +342,7 @@ updating the relevant board file in the SAME commit is incomplete.** | A merged PR (post-merge commit) | `.claude/board/LATEST_STATE.md` table + `.claude/board/PR_ARC_INVENTORY.md` PREPEND entry | | A new integration plan | `.claude/board/INTEGRATION_PLANS.md` PREPEND + `.claude/plans/-v.md` | | A new D-id / deliverable | `.claude/board/STATUS_BOARD.md` row (status = Queued → In progress → In PR → Shipped) | +| A finding / measurement / probe result / open point | `.claude/board/entries/YYYY-MM-DD-.md` (the entry verbatim) **+** `python3 .claude/tools/entries_index.py --write` in the SAME commit | | A genuine Eureka (passes the § Closeout admission gate below) | `.claude/board/EPIPHANIES.md` PREPEND dated entry | | An ordinary correction / lesson learned | **NOTHING** — one closeout line, see § Closeout below | | A tech-debt observation | `.claude/board/TECH_DEBT.md` entry | @@ -461,6 +462,35 @@ can share a Boolean algebra while inhabiting different population axes, so algebraic compatibility does not imply representational substitutability"* survives its own mistake and is a candidate. Keep the categories separate. +**The transient tier, and the ONE promotion rule.** Ordinary work lands in +`.claude/board/entries/` as a dated file — the **transient work/finding tier**, +not an Epiphany staging folder. It is noisy on purpose: a finding there may be +wrong, superseded tomorrow, or merely a measurement. Its index is GENERATED +(`entries_index.py --write`; never `> README.md` — the file is its own input) +and CI runs the three structural falsifiers, so a stranded file or a stale +header cannot recur. + +At closeout each entry is reconciled against project truth — reuse what exists: +`PLAN-INVENTORY`'s verdict rubric (**OPEN** = its own status line and/or its +`STATUS_BOARD` D-ids say work remains · **CLOSED** = its deliverable is +delivered · **SUPERSEDED** = a higher-numbered sibling or its status says so · +**AMBIGUOUS** = no house-format status and no board row), `SUPERSESSION-INDEX`'s +`route` column, and `preflight_drift` for board-claim-vs-cargo-reality. Then +exactly four destinations, and no fifth: + +| the entry is… | destination | +|---|---| +| fixed / obsolete / duplicate / already represented | **nothing durable** — it dies in the tier; git keeps the journey | +| still genuinely unresolved | one compact **OPEN** row (`ISSUES.md` or `STATUS_BOARD.md`) | +| implemented / closed | one compact **DONE** row (`STATUS_BOARD.md`, or `LATEST_STATE.md` if it changed the inventory) | +| NEW **and** LOAD-BEARING **and** DURABLE, and still true after reconciliation | `EPIPHANIES.md` — the rare case | + +A surviving Eureka must clear **both** gates: the three-way admission test above +*and* still being true against the current implementation. **`MIRROR` is never +promoted by itself** — it is transient reflection and normally dies at closeout; +only a factual consequence of it (a real open implementation issue) becomes a +row, and a `BIAS CHECK` line has no durable home at all. + **No recursive post-mortems.** A correction does not entitle a post-mortem, and a corrected post-mortem does not entitle another — § Termination clause above is the same stopping rule one level down. A review earns a follow-up only for a From 181bb2c28005c185a967edd61367008c6722eb5c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 14:32:04 +0000 Subject: [PATCH 14/19] Review round on #1254: fix 5 verified findings, reject 2 as unfounded Two reviewers, seven findings, each verified against the file before acting. Five were real, two were not. REAL, all reproduced before fixing: codex P2 -- a quoted operand escaped the slice DENY. `head -20 "src/lib.rs"` put the extension before a quote instead of whitespace-or-end, so the branch missed it and the command fell through to a non-blocking injection. codex P2 -- a pipeline written across lines escaped the capped-search DENY. grep -E works one line at a time and `.*` never spans a newline, so `rg ... \ | head -20` was invisible to that branch. Both are fixed by one normalized copy of the command used for MATCHING ONLY: newlines folded to spaces, shell quotes and continuations dropped. Execution and display still use the original. codex P2 -- the authority-label guard exempted an entire edit when old_string already contained any label, so adding `operator-pinned` beside an existing `operator-ruled` produced no denial. Now compares non-quoted label OCCURRENCES between the two sides, so a label riding in beside one that was already there is still an introduction. CodeRabbit -- MultiEdit was outside the matcher (`Grep|Bash|Edit|Write`), so a batch could carry a label past the Edit/Write enforcement. Matcher extended and a MultiEdit branch added that checks each edit payload independently, so one edit cannot be excused by another's pre-existing label. CodeRabbit (outside diff) -- the run-record still stored only a trailing tail while item 4 now requires the root block. Verified at line 164: `tail: `, forwarded by the supervision loop. The record now carries a bounded `root_diagnostic` -- the complete FIRST relevant diagnostic block -- and `tail` is demoted to context, explicitly never the evidence. My own first grep missed this because I searched for "last 10 lines" and the text uses a Unicode <=; the reviewer was right and my search was the weaker instrument. NOT REAL, measured rather than argued: CodeRabbit Major -- "the DENY regex requires the source path to be the final argument, so `head Cargo.toml -100` bypasses it". It does not: both that form and `tail .claude/board/ISSUES.md -20` return DENY today, because the pattern backtracks over the argument list. Rejected on the measurement. CodeRabbit Minor -- "line 85 exceeds rustfmt's default width". It is exactly 100 characters, which is rustfmt's inclusive max_width, and `cargo fmt --all -- --check` exits 0 in that workspace. Nothing to format. The suite grew from 26 to 34 cases, covering all five real findings two-sided plus the carve-out they must not eat (`cargo test | tail -30` stays INJECT, and a redirect-then-tail stays INJECT). One repair to my own test insertion: the first version anchored on bare text that sits inside `echo '...'`, so the block landed inside those quotes and its own quotes broke out and executed a `tail`. Re-anchored on full lines; the suite now creates no files. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/hooks/anti-pattern-matching.sh | 52 +++++++++++++++++-- .../hooks/tests/anti-pattern-matching.test.sh | 34 ++++++++++++ .../tiered-agent-execution-protocol.md | 11 +++- .claude/settings.json | 2 +- 4 files changed, 91 insertions(+), 8 deletions(-) diff --git a/.claude/hooks/anti-pattern-matching.sh b/.claude/hooks/anti-pattern-matching.sh index 1dfba1b73..db2b2fb7e 100755 --- a/.claude/hooks/anti-pattern-matching.sh +++ b/.claude/hooks/anti-pattern-matching.sh @@ -106,6 +106,14 @@ AUTHORITY_DENY='VERBOTEN (FIRST-HAND SOURCE LAW §G): operator-ruled / operator- introduces_authority_label() { printf '%s' "$1" | grep -Ei "$AUTHORITY_LABELS" | grep -Eviq "$QUOTE_MARKER" } +# Non-quoted label OCCURRENCES, for comparing an edit's two sides. A blanket +# "old already had one" exemption let an edit ADD a label beside an existing +# one -- `operator-ruled` present, `operator-pinned` arriving, no denial, which +# is exactly the introduction the guard promises to block (codex P2 on #1254, +# reproduced before fixing). +count_authority_labels() { + printf '%s' "$1" | grep -Eiv "$QUOTE_MARKER" | grep -Eio "$AUTHORITY_LABELS" | wc -l | tr -d ' ' +} SLICER='(sed|head|tail|awk)' case "$tool" in @@ -118,12 +126,35 @@ case "$tool" in if printf '%s' "$path" | grep -Eq '\.(md|rs)$'; then new="$(printf '%s' "$input" | jq -r '.tool_input.new_string // ""')" old="$(printf '%s' "$input" | jq -r '.tool_input.old_string // ""')" - # INTRODUCTION only: the label must be arriving, not already present. - if introduces_authority_label "$new" && ! printf '%s' "$old" | grep -Eiq "$AUTHORITY_LABELS"; then + # INTRODUCTION only, measured per OCCURRENCE: more non-quoted labels + # after than before. Comparing counts (not mere presence) is what stops + # a label riding in beside one that was already there. + if introduces_authority_label "$new" \ + && [ "$(count_authority_labels "$new")" -gt "$(count_authority_labels "$old")" ]; then emit_deny "$AUTHORITY_DENY" fi fi ;; + MultiEdit) + # Same guard as Edit, per edit in the batch: a MultiEdit that introduces a + # label must not slip past because the matcher only named Edit/Write + # (CodeRabbit on #1254). Compared per-edit so one edit cannot be excused by + # another edit's pre-existing label. + path="$(printf '%s' "$input" | jq -r '.tool_input.file_path // ""')" + if printf '%s' "$path" | grep -Eq '\.(md|rs)$'; then + n="$(printf '%s' "$input" | jq -r '.tool_input.edits | length // 0')" + i=0 + while [ "$i" -lt "${n:-0}" ]; do + new="$(printf '%s' "$input" | jq -r ".tool_input.edits[$i].new_string // \"\"")" + old="$(printf '%s' "$input" | jq -r ".tool_input.edits[$i].old_string // \"\"")" + if introduces_authority_label "$new" \ + && [ "$(count_authority_labels "$new")" -gt "$(count_authority_labels "$old")" ]; then + emit_deny "$AUTHORITY_DENY" + fi + i=$((i + 1)) + done + fi + ;; Write) path="$(printf '%s' "$input" | jq -r '.tool_input.file_path // ""')" if printf '%s' "$path" | grep -Eq '\.(md|rs)$'; then @@ -135,6 +166,17 @@ case "$tool" in ;; Bash) cmd="$(printf '%s' "$input" | jq -r '.tool_input.command // ""')" + # Normalized copy, for MATCHING ONLY (never for execution or display). + # Two measured bypasses, both codex P2 on #1254, both reproduced first: + # * a pipeline written across lines -- `rg ... \ | head -20` -- + # was invisible to the capped-search branch, because grep -E works a + # line at a time and `.*` never spans a newline; + # * a quoted operand -- `head -20 "src/lib.rs"` -- escaped the slice + # branch, because the extension was followed by a quote instead of + # whitespace-or-end. + # Folding newlines to spaces and dropping shell quotes/continuations makes + # both read like the bare forms the patterns already catch. + scan="$(printf '%s' "$cmd" | tr '\n' ' ' | sed 's/[\"'"'"'\\]//g')" # Destructive-prepend shape: an open-for-write and a .read() of a file in # the same command (Python one-liner or heredoc). Heuristic, non-blocking # — false positives only cost an injected reminder. @@ -146,15 +188,15 @@ case "$tool" in # DENY 1 -- a slicer whose argument list names a source file, and which is # not reading from a pipe. `cmd` is split on pipes so `cargo x | tail -30` # is judged on the `tail -30` segment alone (no file argument -> allowed). - elif printf '%s' "$cmd" | tr '|;' '\n\n' \ + elif printf '%s' "$scan" | tr '|;' '\n\n' \ | grep -Eq "(^|[[:space:]])$SLICER([[:space:]]+-[^[:space:]]+)*[[:space:]]+([^[:space:]]*[[:space:]]+)*[^[:space:]]*$SRC_EXT([[:space:]]|$)"; then emit_deny "$SLICE_DENY" # DENY 2 -- a search piped into a slicer: the cap that hides itself. - elif printf '%s' "$cmd" \ + elif printf '%s' "$scan" \ | grep -Eq "(^|[|&;]|[[:space:]])$SEARCH_CMD([[:space:]]|$).*\\|[[:space:]]*$SLICER([[:space:]]|$)"; then emit_deny "$CAP_DENY" # Otherwise: non-blocking injection, as before. - elif printf '%s' "$cmd" | grep -Eq '(^|[|&;]|[[:space:]])(grep|rg|ugrep|sed|tail|head|awk)([[:space:]]|$)'; then + elif printf '%s' "$scan" | grep -Eq '(^|[|&;]|[[:space:]])(grep|rg|ugrep|sed|tail|head|awk)([[:space:]]|$)'; then emit fi ;; diff --git a/.claude/hooks/tests/anti-pattern-matching.test.sh b/.claude/hooks/tests/anti-pattern-matching.test.sh index fc0afa711..23734bf11 100755 --- a/.claude/hooks/tests/anti-pattern-matching.test.sh +++ b/.claude/hooks/tests/anti-pattern-matching.test.sh @@ -93,6 +93,23 @@ print("DENY" if o.get("permissionDecision") == "deny" else "INJECT")')" } echo '### DENY -- an edit that INTRODUCES an authority label (law §G)' +# MultiEdit: `edit`'s batch sibling. Added with the #1254 review fix -- the +# matcher named only Edit/Write, so a batch could carry a label past the guard. +# A leading untouched edit is included so one edit cannot be excused by another. +multiedit() { + local want="$1" path="$2" old="$3" new="$4" got + got="$(printf '%s' "{\"tool_name\":\"MultiEdit\",\"tool_input\":{\"file_path\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$path"),\"edits\":[{\"old_string\":\"untouched\",\"new_string\":\"untouched\"},{\"old_string\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$old"),\"new_string\":$(python3 -c 'import json,sys;print(json.dumps(sys.argv[1]))' "$new")}]}}" \ + | bash "$HOOK" | python3 -c ' +import json,sys +raw = sys.stdin.read().strip() +if not raw: + print("SILENT"); raise SystemExit +o = json.loads(raw)["hookSpecificOutput"] +print("DENY" if o.get("permissionDecision") == "deny" else "INJECT")')" + if [ "$got" = "$want" ]; then printf ' ok %-7s %s\n' "$got" "$5" + else printf ' FAIL want=%s got=%s %s\n' "$want" "$got" "$5"; fails=$((fails + 1)); fi +} + edit DENY x.md "Status: WORKING-MODEL" "Status: operator-ruled" "introduce operator-ruled" edit DENY x.md "the pin" "the operator-locked pin" "introduce operator-locked" write DENY n.md "# New @@ -112,8 +129,25 @@ edit SILENT x.md "Status: OPEN" "Status: MEASURED (cargo metadata, exit 0) edit SILENT x.md "a" "DECISION: keep path form\nBASIS: offline cost" "DECISION record" echo '### ALLOW -- not canonical prose/source' +edit DENY x.md "was operator-ruled." "was operator-ruled. New: operator-pinned too." "a label ADDED beside an existing one is still an introduction" +multiedit DENY x.md "b" "b operator-locked" "MultiEdit introducing a label" +multiedit SILENT x.md "b" "b tidied" "MultiEdit with no label" write SILENT c.json '{"k":"operator-ruled"}' "json is out of scope" +echo '### DENY -- review findings on #1254, each reproduced before it was fixed' +# codex P2: a quoted operand escaped the slice branch (the extension was +# followed by a quote, not whitespace-or-end). Both quote styles. +t DENY 'head -20 "src/lib.rs"' +t DENY "sed -n 1,50p 'crates/x/src/lib.rs'" +# codex P2: a pipeline written across lines was invisible to the capped-search +# branch -- grep -E works one line at a time and `.*` never spans a newline. +t DENY 'rg -n CallMask crates/ \ + | head -20' + +echo '### ALLOW -- the carve-out those three fixes must not eat' +t INJECT 'cargo test 2>&1 | tail -30' +t INJECT 'cargo test > /tmp/probe.log 2>&1; tail -30 /tmp/probe.log' + echo '### the Grep TOOL always carries the law' got="$(classify Grep '')" if [ "$got" = "INJECT" ]; then printf ' ok %-7s %s\n' "$got" "(Grep tool)"; else diff --git a/.claude/knowledge/tiered-agent-execution-protocol.md b/.claude/knowledge/tiered-agent-execution-protocol.md index 2bdd3250c..3947c507e 100644 --- a/.claude/knowledge/tiered-agent-execution-protocol.md +++ b/.claude/knowledge/tiered-agent-execution-protocol.md @@ -161,7 +161,13 @@ receipt, NOT a board entry; the supervisor turns it into the board entry. - commands: / completed - status: GREEN | BLOCKED@cmd - gates: -- tail: +- root_diagnostic: +- tail: ``` ## Supervision loop @@ -181,7 +187,8 @@ receipt, NOT a board entry; the supervisor turns it into the board entry. audit trail — the `AGENT_LOG.md` entry the supervisor prepends IS the audit trail. - A BLOCKED run-record escalates to a Sonnet fix-agent (with the receipt's - tail as brief) or to the supervisor; Haiku is never asked to fix. + root_diagnostic as the evidence, tail as context) or to the supervisor; + Haiku is never asked to fix. - Multiple Haiku executors may run in parallel ONLY on disjoint crates/directories, ONLY sharing the one `target/` (never `isolation: "worktree"`, never a per-executor target dir — see diff --git a/.claude/settings.json b/.claude/settings.json index 4daae5a55..7ba2f4401 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -199,7 +199,7 @@ "hooks": { "PreToolUse": [ { - "matcher": "Grep|Bash|Edit|Write", + "matcher": "Grep|Bash|Edit|Write|MultiEdit", "hooks": [ { "type": "command", From 2374b1d255071a2486def15abb1d8d1fe7e359a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 15:44:54 +0000 Subject: [PATCH 15/19] board: one historical findings catch-up, then a SHA watermark and delta-only closeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The k-frame the closeout rule was missing. `EPIPHANIES.md` grew to 33,528 lines because the 2026-08-06 split's pointer was prepended away, so 306 findings landed in the monolith instead of the transient tier. This reconciles them ONCE against project truth, records what was consumed, and makes every later closeout a delta. FINDINGS-BASELINE-2026-09-20.md — generated, 306 rows OPEN 39 | CLOSED 34 | SUPERSEDED 5 | AMBIGUOUS 228 EPIPHANIES.md is UNTOUCHED: nothing migrated, re-split, deleted or rewritten, and no entry files minted for these 306. FROZEN != RECONCILED, and the file says so — 228 rows were not adjudicated, which is recorded rather than hidden. Three corrections to the pre-edit scope report, each measured: 1. Reachability was understated. "306 - 108 without a D-id or PR = 198" treated D-id and PR as the only keys; the E-id -> board joins are INDEPENDENT and mostly land inside that 108. Measured union: 278 joined, 81 of the 108 rescued, 27 genuinely unjoinable. 2. The watermark cannot be self-referential. A commit's SHA depends on the bytes of the file holding it, so PROCESSED_THROUGH_SHA names the CONSUMED INPUT (181bb2c) and this commit has its own SHA. Incremental semantics, not commit self-identity. A date is metadata only — imports, backdated headings and rebases all make a calendar watermark lie, the same reason supersession_index.py refuses git mtime. 3. Evidence roles stay distinct. STATUS_BOARD / ISSUES / TECH_DEBT and a work-shaped own status line may decide; PR state and code liveness are landing evidence that NEVER closes a finding (MERGED != CLOSED); entries/ and LATEST_STATE are provenance. Conflict -> AMBIGUOUS, never averaged into certainty. The substantive result: 303/306 entries carry a Status: line and 295 lead with an EPISTEMIC GRADE (FINDING 204, RULING 31, CORRECTION 11, MEASURED 6 ...), which answers *how well established is this claim*, not *is the work done*. Only 8 are work-shaped. Post-watermark EPIPHANIES was a findings log, not a deliverable tracker — so for most rows OPEN/CLOSED is the wrong axis and AMBIGUOUS is the honest residue, with the grade recorded. Four traps the tool encodes, each found by measurement during this pass: - STATUS_BOARD's status column is PER TABLE — 28 header schemas, status at index 1..6, absent in two. A fixed index returns prose as a status. - A Status: line is read by its LEADING TOKEN only, the discipline supersession_index.py adopted after its first ARCHIVE? batch came back 3/3 false. - Cross-supersession needs DIRECTIONAL phrasing. A bare ⊘-proximity rule read "caveat (⊘ in E-FOO-1)" — a sibling CITING this entry's caveat — as the sibling superseding it, and produced a false SUPERSEDED. Caught by spot-reading one row rather than trusting the count. - Keying a join lookup by E-id collapses the 4 duplicate E-ids in this population and hands them each other's evidence. The committed tool computes keys per row. epiphany_provenance.py — the post-baseline gate. A level-2 heading added to EPIPHANIES.md since the baseline must reference an entries/*.md that EXISTS. Structural only: it proves the ROUTE, never that the content is a Eureka, because a regex judging Eureka-ness would be a guard that fires on everything. Four disable-verified arms: silent on a live reference, fires on none, fires on a dangling one, REFUSES on an unreachable baseline. The workflow's checkout needed fetch-depth: 0. actions/checkout@v4 defaults to depth 1, and measured, a depth-1 clone whose head is ahead of the baseline does not contain the baseline at all — the fail-closed guard would have made CI red on every future PR for want of history. My first shallow test was VACUOUS (baseline == tip, so trivially present); the honest test put commits on top first. Gates: provenance + its self-test, entries index --check + --self-test, findings-baseline --self-test, supersession regenerate-and-diff, append-only (9 files, none shrank), EPIPHANIES byte-identical at 33,528 lines. Emission is idempotent; every number in the document is interpolated from the measurement, so prose and table cannot disagree. --- .claude/board/.pr-state-cache.json | 1 + .claude/board/FINDINGS-BASELINE-2026-09-20.md | 469 ++++++++++++++ .claude/board/PROCESSED_THROUGH | 28 + .claude/tools/epiphany_provenance.py | 225 +++++++ .claude/tools/findings_baseline.py | 597 ++++++++++++++++++ .github/workflows/supersession-index.yml | 24 + CLAUDE.md | 30 + 7 files changed, 1374 insertions(+) create mode 100644 .claude/board/.pr-state-cache.json create mode 100644 .claude/board/FINDINGS-BASELINE-2026-09-20.md create mode 100644 .claude/board/PROCESSED_THROUGH create mode 100644 .claude/tools/epiphany_provenance.py create mode 100644 .claude/tools/findings_baseline.py diff --git a/.claude/board/.pr-state-cache.json b/.claude/board/.pr-state-cache.json new file mode 100644 index 000000000..dbd429094 --- /dev/null +++ b/.claude/board/.pr-state-cache.json @@ -0,0 +1 @@ +{"1250": "merged", "1246": "merged", "1245": "merged", "1244": "merged", "1243": "merged", "1242": "merged", "1240": "merged", "1235": "merged", "1233": "merged", "1224": "closed", "1223": "merged", "1222": "merged", "1220": "merged", "1218": "merged", "1217": "merged", "1216": "merged", "1207": "merged", "1205": "merged", "1203": "merged", "1201": "merged", "1200": "merged", "1198": "merged", "1195": "merged", "1194": "merged", "1190": "merged", "1188": "merged", "1185": "merged", "1170": "merged", "1169": "merged", "1168": "merged", "1167": "merged", "1164": "closed", "1162": "closed", "1160": "merged", "1159": "merged", "1157": "merged", "1154": "merged", "1153": "merged", "1152": "merged", "1151": "merged", "1144": "merged", "1141": "merged", "1137": "merged", "1134": "merged", "1133": "merged", "1132": "merged", "1129": "merged", "1128": "merged", "1127": "merged", "1126": "merged", "1125": "merged", "1123": "merged", "1122": "merged", "1120": "merged", "1118": "merged", "1117": "merged", "1112": "merged", "1103": "merged", "1099": "merged", "1092": "merged", "1085": "merged", "1082": "merged", "1081": "merged", "1079": "merged", "1078": "merged", "1051": "merged", "1045": "merged", "1019": "merged", "1016": "merged", "1014": "merged", "1012": "merged", "1011": "merged", "1004": "merged", "1001": "merged", "998": "merged", "997": "merged", "996": "merged", "995": "merged", "992": "merged", "989": "merged", "984": "merged", "981": "merged", "975": "merged", "973": "closed", "971": "merged", "970": "merged", "968": "merged", "957": "merged", "950": "merged", "948": "merged", "945": "merged", "944": "merged", "941": "merged", "940": "merged", "938": "merged", "937": "merged", "936": "merged", "935": "merged", "932": "merged", "930": "merged", "928": "merged", "927": "merged", "926": "merged", "915": "merged", "913": "merged", "912": "merged", "911": "merged", "879": "merged", "876": "merged", "875": "merged", "844": "merged", "658": "merged", "596": "closed", "590": "merged", "565": "merged", "561": "merged", "498": "merged", "448": "merged", "446": "merged", "387": "merged", "350": "merged", "348": "merged", "310": "merged", "302": "merged", "298": "closed", "297": "closed", "296": "merged", "295": "merged", "294": "merged", "293": "merged", "291": "merged", "288": "merged", "277": "merged", "276": "merged", "275": "merged", "175": "merged", "174": "merged", "146": "merged", "104": "merged", "103": "merged"} \ No newline at end of file diff --git a/.claude/board/FINDINGS-BASELINE-2026-09-20.md b/.claude/board/FINDINGS-BASELINE-2026-09-20.md new file mode 100644 index 000000000..dd04f3b9d --- /dev/null +++ b/.claude/board/FINDINGS-BASELINE-2026-09-20.md @@ -0,0 +1,469 @@ +# Findings baseline — 181bb2c28005 (`EPIPHANIES.md`, post-2026-08-06 entries) + +> **What this is.** The ONE historical catch-up over the findings that went +> into the `EPIPHANIES.md` monolith after the 2026-08-06 split watermark. +> It is a consolidated current-state checkpoint — a **k-frame**. After it, +> routine closeout is DELTA ONLY and never censuses the monolith again. +> Like `PLAN-INVENTORY-2026-09-07.md` it mints **no D-ids**, so +> `supersession_index.py` and `plan_dids.py` do not see it — by design. +> Regenerate: `python3 .claude/tools/findings_baseline.py --emit `. +> +> **The historical prose is FROZEN, not reconciled away.** `EPIPHANIES.md` +> is untouched: nothing was migrated, re-split, deleted or rewritten, and +> no entry files were created for these findings. Frozen means *not reread +> by routine closeout*; it does NOT mean adjudicated — 228 of 306 were not. +> +> **PROCESSED_THROUGH_SHA = `181bb2c28005c185a967edd61367008c6722eb5c`** — every eligible finding visible +> through that source revision is consumed into this baseline. The marker +> names the CONSUMED INPUT, never this file's own commit: a commit cannot +> contain its own hash. Machine-readable: `.claude/board/PROCESSED_THROUGH`. + +--- + +## 0. The numbers + +| | count | +|---|---| +| population (level-2 post-watermark entries with an E-id) | **306** | +| OPEN | 39 | +| CLOSED | 34 | +| SUPERSEDED | 5 | +| AMBIGUOUS | 228 | + +Excluded and counted so the exclusion is visible, not asserted: **3** +level-2 bare date-group headers (no E-id) and **3** level-3 +sub-headings (sections *inside* an entry). 306 + 3 + 3 = +312 dated headings at or after the watermark. + +### Mechanical reachability — the union of join keys + +A first estimate put the ceiling at 198 by taking `306 − 108 without a D-id +or PR`. That was wrong: the E-id → board joins are **independent keys** and +most of them land inside that 108. + +| join key | entries | answers | +|---|---|---| +| `eid_board` | 192 | named on a board surface — provenance | +| `did_statusboard` | 101 | a referenced D-id has a STATUS_BOARD row — deliverable status | +| `pr` | 128 | a PR is referenced — landing evidence ONLY | +| `cite_live` | 48 | a cited path still exists — implementation reality | +| `did_unknown` | 12 | referenced D-id has NO status-bearing board row — dangling | +| `cite_dead` | 8 | cited path is GONE — stale citation | + +**278** entries carry ≥ 1 usable key; **27** carry none and are +therefore automatically AMBIGUOUS. The other 201 ambiguous rows are +ambiguous for a different and more interesting reason — §1. + +## 1. Why AMBIGUOUS is the largest bucket + +**303 of the 306 entries carry their own `Status:` line, and 295 of those lead +with an EPISTEMIC GRADE rather than a work status:** + +| leading token | entries | +|---|---| +| `FINDING` | 204 | +| `RULING` | 31 | +| `OPERATOR` | 15 | +| `CORRECTION` | 11 | +| `MEASURED` | 6 | +| `OPERATOR-RULED` | 5 | +| `⊘` | 5 | +| `SHIPPED` | 4 | +| `PROPOSAL` | 4 | +| `FENCE` | 2 | + +`FINDING`, `RULING`, `CORRECTION`, `MEASURED` answer *how well established +is this claim*. They do not answer *is the work done*. Only **8** entries +lead with a work-shaped token. + +That is the substantive result: **post-watermark `EPIPHANIES.md` was being +used as a findings log, not a deliverable tracker.** For most rows +OPEN/CLOSED is the wrong axis — the live question is *is this still true?*, +which no join answers mechanically. Reading their prose to manufacture a +status is what this pass was told not to do, so they stay AMBIGUOUS with +their grade recorded. + +Not a comparable number: `PLAN-INVENTORY-2026-09-07.md` reached 40/211 +ambiguous **with a human read of every status line in context**, and records +that naive substring matching produced ≥ 6 false positives in its corpus. +This pass is mechanical-only by instruction; the larger residue is the price +of that, not a worse measurement. + +## 2. How to read a verdict + +Vocabulary reused from `PLAN-INVENTORY`; nothing new minted. Each join +answers only the question it can answer: + +| evidence | role | may decide status? | +|---|---|---| +| STATUS_BOARD D-id row | deliverable status | **yes** | +| ISSUES section | unresolved / resolved | **yes** | +| TECH_DEBT section | implementation debt | **yes** (OPEN) | +| the entry's own status line | only if its leading token is work-shaped | **yes** | +| INTEGRATION_PLANS | integration ownership | no — context | +| PR state | landing evidence | **no — MERGED ≠ CLOSED** | +| live code citation | implementation reality | no | +| `entries/`, `LATEST_STATE` mention | provenance | no | + +Conflicting decisive evidence ⇒ **AMBIGUOUS** (23 rows), never averaged +into certainty. Absent decisive evidence ⇒ **AMBIGUOUS** (178 joined rows + +27 unjoinable). The *implementation* column carries landing and +code-liveness facts precisely so they cannot be mistaken for closure. + +Three traps the tool encodes, each measured: STATUS_BOARD's status column +is **per-table** (28 schemas, index 1..6, absent in two); a `Status:` line's +**leading token only** is read; and cross-supersession needs **directional** +phrasing, because a bare `⊘`-proximity rule read `caveat (⊘ in E-FOO-1)` — +a sibling citing this entry's caveat — as the sibling superseding it. + +## 3. The rows + +### OPEN (39) + +| source id | status | implementation | outcome/open point | +|---|---|---|---| +| `E-THE-GOLDEN-STEP-IS-THE-WRONG-STEP-AT-SMALL-Q-1` | OPEN | PR #932 merged | live ISSUES entry | +| `E-A-TOTAL-FUNCTION-THAT-CANNOT-REFUSE-IS-A-CORRUPTION-PATH-1` | OPEN | PR #948 merged | STATUS_BOARD row not done | +| `E-CONTRACT-INFERENCETYPE-INVERTS-THE-COUNTERFACTUAL-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-CAPABILITY-IS-NOT-REACHABILITY-1` | OPEN | PR #971 merged | live TECH_DEBT entry | +| `E-THE-FILTER-WAS-FILTERING-ON-THE-WRONG-PREDICATE-1` | OPEN | PR #971 merged | live TECH_DEBT entry | +| `E-THE-RECIPE-SURFACE-IS-CAUSALLY-BLIND-1` | OPEN | no implementation evidence | live TECH_DEBT entry | +| `E-A-DOC-COMMENT-CAN-GIVE-THE-WRONG-REASON-FOR-A-CORRECT-GUARD-1` | OPEN | no implementation evidence | live TECH_DEBT entry | +| `E-A-CORRECTION-CAN-SUBSTITUTE-ONE-WRONG-NOUN-FOR-ANOTHER-1` | OPEN | PR #1112 merged | STATUS_BOARD row not done | +| `E-ONLY-TWO-OF-FOUR-STANCES-MAY-CUT-A-CANDIDATE-SET-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-BLW5-FIRST-MEASUREMENT-1` | OPEN | 1 cited path(s) live | STATUS_BOARD row not done | +| `E-EVERYTHING-WIRES-TO-SOA-V3-CE64-IS-ALU-LEGACY-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-NXG-10` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-NXG-11` | OPEN | PR #1160 merged | STATUS_BOARD row not done | +| `E-NXG-16` | OPEN | no implementation evidence | STATUS_BOARD row not done; live TECH_DEBT entry | +| `E-NXG-5` | OPEN | no implementation evidence | STATUS_BOARD row not done; own status line: PROPOSAL | +| `E-NXG-6` | OPEN | no implementation evidence | STATUS_BOARD row not done; own status line: PROPOSAL | +| `E-NXG-9` | OPEN | PR #1153, #1154 merged | own status line: PROPOSAL | +| `E-AN-EXCLUDED-CRATE-ON-AN-X86-ONLY-FLEET-IS-CODE-NO-CI-HAS-EVER-COMPILED-1` | OPEN | PR #146, #844, #1194 +2 merged; 1 cited path(s) live | live ISSUES entry | +| `E-A-CONSUMER-THAT-OPENS-A-DATASET-HAS-ALREADY-LOST-1` | OPEN | PR #879, #911, #912 merged | STATUS_BOARD row not done | +| `E-A-DYNAMIC-DOMAIN-MASK-IS-A-SECOND-WITNESS-AND-ITS-ALIGNMENT-IS-CALIBRATION-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-LANCE-GRAPH-OWNS-THE-AGNOSTIC-THINKING-CONSUMERS-BIND-DOMAIN-1` | OPEN | PR #1220 merged | STATUS_BOARD row not done | +| `E-SPOG-IS-FOUNDRY-WITH-AN-ABI-SHAPED-SUBSTRATE-1` | OPEN | 1 PR ref(s), state not cached | STATUS_BOARD row not done | +| `E-T1-HAS-TWO-SIBLING-ALGEBRAS-THE-AXIS-IS-SYNTAX-VS-EXECUTION-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-TOPOLOGY-MASKS-MAGNITUDE-COMPOSE-NEVER-COLLAPSE-1` | OPEN | PR #1220 merged | STATUS_BOARD row not done | +| `E-A-CHECK-THAT-CANNOT-RUN-IS-INDISTINGUISHABLE-FROM-A-CHECK-THAT-PASSES-1` | OPEN | PR #1190, #1235 merged | live ISSUES entry | +| `E-POPCOUNT-FINDS-ELEPHANT-WHALE-BECAUSE-IT-IS-POSITION-BLIND-THE-TREES-METRIC-IS-LZCNT-AND-THE-BOARD-ALREADY-FILED-IT-1` | OPEN | no implementation evidence | STATUS_BOARD row not done; live ISSUES entry | +| `E-POPCOUNTS-UPPER-RANGE-SIMILARITY-IS-THE-HEXAGONS-RAUMGEWINN-AND-BOARD-GAMES-MAKE-IT-FALSIFIABLE-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-RAUMGEWINN-NEEDS-A-HORIZON-SMALLER-THAN-THE-BOARD-TIC-TAC-TOE-HAS-NONE-SO-ARM-1-IS-F0-DEGENERATE-NOT-A-KILL-1` | OPEN | 3 cited path(s) live | STATUS_BOARD row not done | +| `E-THE-ACCUMULATOR-GATE-OUTRANKED-THE-PLANE-AND-SILENTLY-DROPPED-IT-1` | OPEN | PR #1235 merged | live ISSUES entry | +| `E-THE-NET-ARM-RANKED-ON-A-PARTIAL-SUM-AND-ITS-ONLY-APPARENT-SIGNAL-WAS-THAT-BUG-1` | OPEN | 2 cited path(s) live | STATUS_BOARD row not done | +| `E-THREE-CARRIERS-THREE-FOLDS-1` | OPEN | PR #1244 merged; 1 cited path(s) live | live ISSUES entry | +| `E-A-MASK-EXPRESSION-DOES-NOT-IMPLY-A-BITMAP-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-A-VARNODE-IS-NOT-A-BUFFER-R2IL-IS-MICROCODE-FOR-MASKED-THINKING-1` | OPEN | no implementation evidence | live ISSUES entry | +| `E-DO-NOT-BACK-DATE-A-NEW-LAW-ONTO-AN-OLD-DOCTRINE-1` | OPEN | no implementation evidence | live ISSUES entry | +| `E-FOLD-AND-MASK-ARE-SIBLING-PHYSICAL-PLANS-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-LAYER-0-IS-T1-AND-MASK-RISC-IS-ALREADY-ITS-ISA-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-THE-CENTER-IS-SPOG-PLUS-FC-EVERYTHING-ELSE-IS-CAST-1` | OPEN | no implementation evidence | STATUS_BOARD row not done | +| `E-THREE-CONVERGENCES-TARSKI-SHANNON-JC-AND-THE-BAND-IS-A-SANDBOX-1` | OPEN | 1 referenced PR(s) closed unmerged; 1 cited path(s) live | STATUS_BOARD row not done | +| `E-WE-THINK-WITH-OGAR-GRAPHS-OGAR-DOES-NOT-DO-THE-THINKING-1` | OPEN | no implementation evidence | live ISSUES entry | + +### CLOSED (34) + +| source id | status | implementation | outcome/open point | +|---|---|---|---| +| `E-A-HORSE-RACE-IS-NOT-A-CROSS-SWAP-1` | CLOSED | PR #927, #928, #930 +2 merged | STATUS_BOARD row done | +| `E-THE-HYPOTHESIS-REFUTED-CLEANLY-AND-REVERSED-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-THE-METRIC-THAT-SEPARATES-ONE-COMPARISON-IS-BLIND-TO-ANOTHER-1` | CLOSED | PR #926 merged | STATUS_BOARD row done | +| `E-PIN-LANCE9-LANCEDB033-DF541-ARROW58-NO-DF53-1` | CLOSED | PR #879, #911, #912 +1 merged | ISSUES entry resolved | +| `E-ATTENTION-MASK-IS-A-RENAME-REGISTER-FILE-NOT-A-RESIDUE-CARRIER-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-FROM-V1-DROPS-PROVENANCE-AND-THE-COUNCIL-CAUGHT-THE-CONTRACT-ABOUT-TO-TRUST-IT-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-THE-ATTENTION-ATOM-WAS-ALREADY-SHIPPED-WHAT-WAS-MISSING-WAS-A-COMPOSITION-THAT-IS-NOT-OR-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-A-DOC-PRECEDENCE-CLAIM-CAN-PASS-EIGHT-GREEN-TESTS-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-TWO-KEY-ELEVATION-WINDOW-IS-NARROW-AND-THE-CORPUS-STRADDLES-IT-1` | CLOSED | PR #997, #998 merged | STATUS_BOARD row done | +| `E-THE-FUSED-PAYLOAD-IS-INERT-AT-EVERY-EXECUTION-GATE-THAT-CONSUMES-IT-1` | CLOSED | PR #1045 merged | STATUS_BOARD row done | +| `E-BELIEF-ARENA-DEDUP-IS-PAYABLE-AND-W0-MUST-CITE-IT-1` | CLOSED | PR #1078 merged; 1 referenced PR(s) closed unmerged | STATUS_BOARD row done | +| `E-THE-ORACLE-WAS-CITED-AS-A-PHILOSOPHY-AND-NEVER-AS-A-METHOD-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-A-DETERMINISM-GATE-IS-TRIVIALLY-SATISFIED-BY-A-KERNEL-THAT-DOES-NOTHING-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-A-WITNESS-THAT-DROPS-THE-RELATION-IS-NOT-A-WITNESS-1` | CLOSED | PR #1120 merged | STATUS_BOARD row done | +| `E-EVERY-DEFECT-IN-A-MEASUREMENT-WAS-IN-ITS-FIXTURE-NOT-ITS-CODE-1` | CLOSED | PR #1118 merged | STATUS_BOARD row done | +| `E-PILLAR-11-GREEN-FOR-LATTICE-WALKS-LENGTH-PARAMETERIZED-1` | CLOSED | PR #1129, #1133 merged | own status line: SHIPPED | +| `E-QUALIA-IS-RANK-INERT-AT-THE-FRONTIER-AND-POPULATION-LOSES-TO-COUNTING-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-THE-CALIBRATION-GATE-REVERSED-THE-DECLARED-FLOOR-1` | CLOSED | 1 cited path(s) live | STATUS_BOARD row done | +| `E-A-DOCUMENTED-MODULE-THAT-WAS-NEVER` | CLOSED | 3 cited path(s) live | own status line: SHIPPED | +| `E-A-PRODUCER-IS-A-PURE-FUNCTION-OF-THE-CONTENT-LOCI-1` | CLOSED | no implementation evidence | STATUS_BOARD row done; own status line: SHIPPED | +| `E-THE-VACANCY-RULE-IS-NOT-ABOUT-ENTROPY-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-TWO-FATE-PROBES-KILL-DIFFERENT-WAYS-1` | CLOSED | PR #1144 merged | STATUS_BOARD row done | +| `E-A-SWEEP-IS-COMPLETE-ONLY-WITHIN-THE-TARGET-KINDS-ITS-GATE-COMPILES-1` | CLOSED | PR #1194 merged | TECH_DEBT entry resolved | +| `E-NXG-18` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-NXG-2` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-NXG-21` | CLOSED | 1 cited path(s) live | STATUS_BOARD row done; own status line: SHIPPED | +| `E-NXG-22` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-SEVEN-HARVEST-SOURCES-ONE-OBJECT-THE-VERSION-KEYED-MASK-SET-1` | CLOSED | PR #1218 merged; 1 referenced PR(s) closed unmerged; 1 cited path(s) live | STATUS_BOARD row done | +| `E-A-FLOOR-PASSED-AT-ITS-BOUND-IS-A-DEAD-FIXTURE-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-THE-VOCABULARY-IS-THE-RECOGNITION-ORGAN-THE-LAW-IS-THE-TRANSFER-ORGAN-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-256-BY-256-IS-EXACTLY-64K-THE-RAILS-SKIP-UNIT-IS-ITS-HI-BYTE-AND-A-QUARTER-BLOCK-IS-A-REMAINDER-1` | CLOSED | 1 cited path(s) live | STATUS_BOARD row done | +| `E-A-SPREAD-WITHOUT-A-SURROUND-IS-A-BLUR-INHIBITION-IS-THE-FREE-HALF-1` | CLOSED | no implementation evidence | STATUS_BOARD row done | +| `E-I-GRAFTED-HELIX-ONTO-HEXAGON-AND-THEN-DEPRECATED-THE-OPERATORS-TENANTS-ON-MY-OWN-AUTHORITY-1` | CLOSED | PR #1233 merged; 5 cited path(s) live | STATUS_BOARD row done | +| `E-THE-TWO-FAMILY-NAMINGS-INVERT-AND-FROM-BE-BYTES-IS-THE-PLAUSIBLE-WRONG-JOIN-1` | CLOSED | no implementation evidence | ISSUES entry resolved | + +### SUPERSEDED (5) + +| source id | status | implementation | outcome/open point | +|---|---|---|---| +| `E-A7A-IS-THE-NAME-NOT-LITERALLY-DUMB-1` | SUPERSEDED | no implementation evidence | own heading/status ⊘ note | +| `E-A-WATCHER-THAT-CANNOT-DISSENT-IS-NOT-A-WATCHER-1` | SUPERSEDED | no implementation evidence | own heading/status ⊘ note | +| `E-THE-COVERAGE-FIX-IS-REAL-AND-ASYMMETRIC-1` | SUPERSEDED | no implementation evidence | own heading/status ⊘ note | +| `E-A-CRATE-WITH-ZERO-CONSUMERS-IS-BUILT-BY-NOTHING-AND-CAN-BE-MERGED-BROKEN-1` | SUPERSEDED | PR #957, #981 merged | own heading/status ⊘ note | +| `E-THE-RUNG-LADDER-HAS-A-STORAGE-DESIGN-AND-NO-WRITER-1` | SUPERSEDED | no implementation evidence | own heading/status ⊘ note | + +### AMBIGUOUS (228) + +| source id | status | implementation | outcome/open point | +|---|---|---|---| +| `E-THREE-NAMED-PROBES-ARE-ONE-MEASUREMENT` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-COMMENT-THAT-RESTATES-A-PINNED-VALUE-GOES-STALE-EVERY-BUMP-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-CLAUDE-MD-KEY-DEPENDENCIES-WENT-STALE-AND-PROPAGATED-A-WRONG-PIN-INTO-A-PLAN-1` | AMBIGUOUS | PR #915 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-JC-AND-NDARRAY-BOTH-SHIP-A-RELIABILITY-BATTERY-WITH-DIFFERENT-DEGENERATE-CONTRACTS-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-DOCUMENTED-PROXY-BYPASS-IS-FOR-PUSH-DENIALS-NOT-CLONE-AUTH-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-CORRECTION-IS-A-CLAIM-AND-CARRIES-A-CLAIM-S-BURDEN-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-JITTER-AMPLITUDE-YOU-CHOSE-IS-NOT-AN-UNCERTAINTY-YOU-MEASURED-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-CYCLONE-ASYMMETRY-IS-ONE-DIPOLE-1` | AMBIGUOUS | PR #926 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-HELIX360-IS-THE-NORMALIZED-SUBSTRATE-NOT-A-BIT-BUDGET-1` | AMBIGUOUS | PR #498 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-JUDGE-THE-FIELD-NOT-THE-ELEMENT-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-MY-OWN-PRE-REGISTRATION-HAD-A-GAP-AND-I-NAMED-IT-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-N-EQUALS-TWO-LOOKED-LIKE-PHYSICS-AND-WAS-HALF-COIN-FLIP-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-SPINE-FOUND-MODERATORS-MISSING-1` | AMBIGUOUS | PR #926 merged | graded OPERATOR — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-BYTE-WAS-ONLY-THE-SELECTOR-THE-PAIR-IS-THE-CARRIER-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-DOCTRINE-DOC-EXISTED-AND-I-NEVER-READ-IT-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-FRAME-WAS-ALREADY-SHIPPED-FOUR-TIMES-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-HEADLINE-NUMBER-MEASURED-A-MODEL-NOBODY-CLAIMED-1` | AMBIGUOUS | PR #926 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-OFFSET-WAS-THE-APPARATUS-THE-LADDER-WAS-THE-PHYSICS-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-RESCUE-THAT-WEAKENED-ITSELF-UNDER-SCRUTINY-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-REUSE-IS-THE-PROCESS-AND-IT-EXPOSED-A-FIT-PROBLEM-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-TRANSFORM-MUST-MATCH-THE-DISTRIBUTION-SHAPE-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-TOPOLOGY-PICKS-THE-TABLE-NOT-THE-DOMAIN-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-ZERO-FOR-ELEVEN-THE-AUTHOR-CANNOT-AUDIT-HIS-OWN-FALSIFIERS-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-CONTROL-THAT-CANNOT-LOSE-IS-NO-CONTROL-1` | AMBIGUOUS | PR #935 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-FIGURE-CITED-TWICE-IS-NOT-CONFIRMED-ONCE-1` | AMBIGUOUS | PR #945 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-ON-A-GOLDEN-LATTICE-LOCALITY-IS-FIBONACCI-MEMBERSHIP-1` | AMBIGUOUS | PR #936, #937, #938 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-CONTROL-SCORED-THE-HEADLINE-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-DISPLACEMENT-FILTER-ATE-THE-STRANDED-STRATUM-1` | AMBIGUOUS | PR #940 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-REGIME-LADDER-MEASURED-RANGE-NOT-TURBULENCE-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-DISABLE-PROBE-CAN-ITSELF-BE-VACUOUS-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-FIGURE-YOU-TALLIED-YOURSELF-IS-A-DERIVED-FIGURE-1` | AMBIGUOUS | PR #950 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-REAL-GATE-RAN-AND-QUALIFIED-NOT-RETRACTED-THE-CLAIM-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-IDENTITY-QUAD-4X24-RATIFIED-PERMANENT-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-FORD-REAL-PUBLICATION-IDENTITY-IS-ARRIVAL-DEPENDENT-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-OGAR-CODEBOOK-MIRROR-DOMAIN-DRIFT-SYNCED-1` | AMBIGUOUS | PR #275, #276, #277 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A7A-STORNO-THE-EXCLAMATION-WAS-NOT-A-NAME-1` | AMBIGUOUS | no implementation evidence | graded CORRECTION — an epistemic grade, not a work status; no deliverable attached | +| `E-ARCHITECTURE-RESET-DUMB-STORAGE-HHTL-EPISTEMIC-1` | AMBIGUOUS | PR #968 merged | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-CROSS-VERSION-IDENTITY-MIGRATES-BLIND-SO-IT-FAILS-CLOSED-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-E2-REVERIFIED-SCATTER-CONTESTED-PMU-ABSENT-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-HIERARCHY-NODE-IS-ALGEBRA-NEVER-A-CROSSWALK-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-LOTUS-IS-A-REGISTER-GRID-NOT-A-BYTE-GRID-1` | AMBIGUOUS | PR #968 merged | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-REPLAY-IS-CANONICAL-COMPACTION-IS-ECONOMICS-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-RP-SEAL-PASS1-THE-MAXIM-WORKED-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-SEAL-IS-ACCUMULATED-ON-THE-HOT-PATH-NOT-A-PASS-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-CANONICAL-ROW-WAS-READ-OFF-A-FIXTURE-1` | AMBIGUOUS | 2 cited path(s) GONE | graded CORRECTION — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-OU-COLUMN-EXISTS-AND-NOTHING-WRITES-IT-1` | AMBIGUOUS | 1 cited path(s) GONE | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-STRONG-HIERARCHY-EXISTS-AS-FIVE-DISCONNECTED-ISLANDS-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-TIER0-CANONICAL-REPLAY-LANDED-DV-IS-EPISTEMIC-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-TWO-WITNESS-SHAPES-CONTEST-ONE-LANDING-ZONE-1` | AMBIGUOUS | PR #446, #448 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-XC21-HARNESS-CONFIRMS-C2-AND-FINDS-DEAD-CODE-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-LOCAL-DERIVATION-CANNOT-OVERRULE-A-MEASURED-COUNTEREXAMPLE-1` | AMBIGUOUS | PR #875 merged; 1 referenced PR(s) closed unmerged | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-DISMECH-CORPUS-CENSUS-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NIBLEPATH-DEPTH-IS-NOT-HHTL-DIMENSIONALITY-1` | AMBIGUOUS | 1 referenced PR(s) closed unmerged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-S3-0-NEEDED-NO-NEW-ADDRESS-1` | AMBIGUOUS | 1 referenced PR(s) closed unmerged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-AUDIT-GATE-WAS-PINNING-THE-BUG-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-COMPAT-ENUM-WAS-EATING-HALF-THE-REGISTER-1` | AMBIGUOUS | PR #970, #971 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-V3-IS-REPRESENTATION-INVARIANT-ON-THE-PLANNER-CE64-LEG-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-WORDNET-IS-A-LOCALITY-PRIOR-NOT-AN-IDENTITY-ENCODING-1` | AMBIGUOUS | PR #875 merged; 1 referenced PR(s) closed unmerged | graded CORRECTION — an epistemic grade, not a work status; no deliverable attached | +| `E-ABBREVIATION-GREP-MANUFACTURED-AN-ABSENCE-1` | AMBIGUOUS | PR #876 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-ACADEMIC-CARVE-UNDERFILLS-ROWS-ARE-NOT-WORDS-1` | AMBIGUOUS | PR #975 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-ADDRESS-FROM-THE-THING-NOT-THE-ACCIDENT-1` | AMBIGUOUS | no implementation evidence | graded SYNTHESIS — an epistemic grade, not a work status; no deliverable attached | +| `E-DISMECH-KNOWN-INTERMEDIATES-ARE-PROSE-NOT-IDENTITIES-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-HHTL-IS-MINTED-IN-THE-ARTIFACT-NOBODY-CITES-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-R2IL-VARNODEFACET-IS-A-G3-CARVING-AND-` | AMBIGUOUS | 1 cited path(s) GONE | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-ORACLE-POPULATION-IS-64-PERCENT-AND-A-GATE-HARDCODES-THE-OTHER-36-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-V4-IS-THE-100-PERCENT-TIER-V3-UNCHANGED-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-CONSTANT-OFFSET-CANNOT-ALIGN-TWO-VERSIFICATIONS-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-BPE-IS-RHYME-VQ-IS-THE-MECHANISM-FOR-6X2X8BIT-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-HHTL-NAMES-TWO-STRUCTURES-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-GATE-IS-A-HAND-MAINTAINED-ALLOWLIST-NOT-THE-WORKSPACE-1` | AMBIGUOUS | PR #984 merged; 1 cited path(s) live | CONFLICT: live ISSUES entry vs ISSUES entry resolved | +| `E-A-WARRANT-MUST-BE-ABLE-TO-SAY-NO-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-AN-IMPORT-EDGE-IS-NOT-AN-ARCHITECTURAL-RELATION-1` | AMBIGUOUS | PR #103, #104 merged | graded CORRECTION — an epistemic grade, not a work status; no deliverable attached | +| `E-CONTENT-NEVER-TRAVELS-IN-CLASSID-1` | AMBIGUOUS | no implementation evidence | graded ROOT — an epistemic grade, not a work status; no deliverable attached | +| `E-HAPPY-PATH-RL-WOULD-HAVE-LEARNED-THE-CLOBBER-1` | AMBIGUOUS | PR #1001, #1011 merged; 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-HHTL-COMPILES-HIERARCHY-INTO-MASK-GEOMETRY-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-HIERARCHY-IS-THE-ADDRESS-SPACE-NOT-THE-ONTOLOGY-1` | AMBIGUOUS | no implementation evidence | graded ROOT — an epistemic grade, not a work status; no deliverable attached | +| `E-MEMBERSHIP-IS-PARTICIPATION-NOT-ANCESTRY-1` | AMBIGUOUS | PR #1001 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-METACOGNITIVE-TRIANGLE-ARROW-1` | AMBIGUOUS | PR #995, #997 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-OGAR-LOCO-INTERPRETER-RUN-1` | AMBIGUOUS | PR #989 merged; 1 cited path(s) GONE | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-ONE-RECEIPT-MANY-BORROWED-CONSUMERS-1` | AMBIGUOUS | PR #1012, #1016 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-REAL-CODE-INTERLEAVES-THE-OPCODE-MACRO-IS-NOT-A-DATAFLOW-PIPE-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-RECIPE-DISPATCH-BRIDGE-1` | AMBIGUOUS | PR #992, #995 merged; 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-RECIPE-EXECUTION-SEPARABILITY-1` | AMBIGUOUS | PR #992 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-STREAM-ORDER-VS-PREFIX-TREE-NEITHER-ACCUMULATES-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-SUDOKU-COGNITIVE-CORPUS-1` | AMBIGUOUS | PR #995, #996 merged; 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-FIRST-PARTICLE-1` | AMBIGUOUS | PR #1001 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-FRONTIER-LEARNER-IS-ALREADY-SHIPPED-1` | AMBIGUOUS | PR #1001, #1011 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-SEVEN-OPCODE-PROJECTION-IS-NOT-X86-AND-THE-CHAIN-CARRIER-WINS-1` | AMBIGUOUS | PR #1014 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-VIEW-MOVES-THE-POPULATION-DOES-NOT-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-TOKEN-BPE-CAN-FIT-NOT-YET-BUY-1` | AMBIGUOUS | PR #1001 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-TYPE-COMPLEXITY-EXPOSED-A-MEMORY-ABI-ESCAPE-1` | AMBIGUOUS | PR #1004 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-BPE-OVER-DEFUSE-CHAINS-BEATS-LINEAR-AND-FITS-LOCO-1` | AMBIGUOUS | PR #998 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-GIT-SOURCED-CRATE-CANNOT-PATH-DEP-OUTSIDE-ITS-REPO-1` | AMBIGUOUS | PR #1019 merged; 2 cited path(s) live | graded FIX — an epistemic grade, not a work status; no deliverable attached | +| `E-GIT-SOURCED-CRATE-CANNOT-PATH-DEP-OUTSIDE-ITS-REPO-1` | AMBIGUOUS | 1 cited path(s) live | graded FIX — an epistemic grade, not a work status; no deliverable attached | +| `E-PHI-WEYL-STAMP-CASCADE-PRECISION-RULING-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-R2IL-BPE-RECOMBINATION-FALSIFIERS-CONFIRMED-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-R2IL-MACRO-VOCABULARY-TRANSFERS-ACROSS-COMPILER-AND-LANGUAGE-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-W0-THE-SPACE-ORDINAL-IS-A-RANK-RELATIVE-TO-A-TABLE-THE-CLASSID-NEVER-NAMES-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-COUPLED-MATERIALS-NOT-A-CHOOSER-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded CORRECTION | +| `E-V4-EXECUTABLE-CONTENT-THREE-TIER-JIT-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded DOCTRINE | +| `E-A-RUNG-WRITE-PATH-ALREADY-SHIPPED-IN-A-SIBLING-REPO-1` | AMBIGUOUS | PR #561, #565, #590 merged; 1 cited path(s) GONE | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-A-FLOOD-THROTTLE-IS-NOT-A-DISCRIMINATOR-1` | AMBIGUOUS | PR #1079 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-DESTRUCTIVE-PREPEND-TRUNCATES-BEFORE-READ-1` | AMBIGUOUS | PR #1079, #1081, #1082 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-MONITOR-KEYED-ON-THE-PR-HEAD-CAN-CERTIFY-THE-WRONG-COMMIT-1` | AMBIGUOUS | PR #1120 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-REVIEW-REMEDY-HAS-A-SHELF-LIFE-1` | AMBIGUOUS | PR #1120, #1122, #1123 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-THRESHOLD-IS-BOUND-TO-ITS-STATISTIC-AND-ITS-SAMPLE-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-CONSUMER-PINS-ON-INTERNAL-SIBLINGS-PROHIBITED-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded OPERATOR-RULED | +| `E-DEPTH-INF-CONVERSE-IS-QUADRATIC-IN-LEVY-AREA-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-I-PINNED-THE-DEFECT-AS-THE-GUARD-WHILE-FIXING-A-REVIEW-COMMENT-1` | AMBIGUOUS | PR #1120, #1122 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-LEVEL-SCALED-NORMALIZATION-IS-THE-SIGNATURE-PARITY-GATE-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-LEVY-AREA-COEFFICIENT-BEATS-REFINEMENT-1` | AMBIGUOUS | PR #350 merged; 2 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-MONOTONE-STREAM-LEVEL2-IS-DISCRIMINATION-NOT-MAGNITUDE-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NECESSARY-CONDITIONS-ARE-NOT-A-PSD-TEST-1` | AMBIGUOUS | PR #291 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-ORIENTATION-BIT-PARTIAL-NIBBLE-SUFFICES-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-PRESENCE-2BIT-CHEAPER-SIBLING-1` | AMBIGUOUS | PR #1099, #1103 merged; 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-Q8-THE-SIX-DOES-NO-WORK-A-DEGREE-ABLATION-COLLAPSES-THE-HEX-OVERLAYS-ENTIRE-ADVANTAGE-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-SUPERSESSION-GATE-WATCHED-TWO-OF-ITS-FOUR-INPUTS-1` | AMBIGUOUS | PR #1123 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-TWO-REVIEWERS-FOUND-THE-SAME-THREE-DEFECTS-AND-ONE-OF-THEM-WAS-MINE-ALONE-1` | AMBIGUOUS | PR #1120 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-W0-MEASURED-THE-MASK-HALF-DOMINATES-AND-THE-PLAN-WAS-UNDER-CITED-1` | AMBIGUOUS | PR #1117 merged | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-AN-HHTL-POSITION-IS-A-NODE-AND-A-NODE-HAS-A-VALUE-1` | AMBIGUOUS | PR #1127 merged | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-ASKING-WHERE-THE-MAP-LIVES-IS-ASKING-WHERE-THE-OUS-ARE-IN-A-DN-1` | AMBIGUOUS | PR #1127 merged | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-G24N4-ALREADY-SHIPS-AND-THAT-IS-WHY-W2B-CANNOT-USE-IT-1` | AMBIGUOUS | 1 cited path(s) GONE | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-LITERATURE-HARVEST-POST-1132-TWO-PILLAR-CORRECTIONS-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded HARVEST | +| `E-ONE-HOP-UP-ONE-HOP-DOWN-A-PARENT-SPEAKS-ONLY-ITS-CHILDREN-1` | AMBIGUOUS | no implementation evidence | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-THE-24-AXIS-BASIS-V3-EVERY-AXIS-IS-A-GROUNDED-PRESSURE-1` | AMBIGUOUS | PR #296 merged | graded BUILT — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-PALETTE-MARGIN-IS-SPENT-AND-GROWTH-MOVES-TO-LOCO-1` | AMBIGUOUS | PR #1125 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-SIGNED-NET-WAS-FALSIFIED-NOT-LIMITED-AND-THE-LOCI-LAW-WAS-SCOPED-TOO-WIDE-1` | AMBIGUOUS | PR #1127 merged | graded OPERATOR — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-STATE-LAYER-IS-A-BELNAP-BILATTICE-AND-THE-JOIN-IS-THE-ACCUMULATOR-1` | AMBIGUOUS | PR #1129 merged | graded OPERATOR — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-THRESHOLD-AXIS-WAS-SATURATED-AND-THE-GATE-WOULD-HAVE-BEEN-VACUOUS-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-THREE-BRANCHES-ONE-REGISTER-THE-AUDIT-AFTER-THE-COLLISION-1` | AMBIGUOUS | PR #1125, #1126, #1127 merged | graded RECONCILIATION — an epistemic grade, not a work status; no deliverable attached | +| `E-THREE-KINDS-OF-MENGENLEHRE-AND-W2-SHIPPED-THE-NARROWEST-1` | AMBIGUOUS | no implementation evidence | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-A-GHOST-TRACE-IS-NOT-THE-COUNTERFACTUAL-LANE-1` | AMBIGUOUS | PR #1137 merged | CONFLICT: live TECH_DEBT entry vs STATUS_BOARD row done | +| `E-JC-IS-THE-HOME-OF-ALL-CALIBRATED-MATH-1` | AMBIGUOUS | 1 cited path(s) live | CONFLICT: live TECH_DEBT entry vs STATUS_BOARD row done | +| `E-PILLAR-11-PUBLISHED-BOUND-NEEDS-ITS-OWN-NUMERIC-GUARD-1` | AMBIGUOUS | PR #1133 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-SIGNATURE-PDE-SWEEP-SHIPPED-W1` | AMBIGUOUS | PR #293, #348 merged; 2 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-SIX-SEMANTIC-FAMILIES-MUST-NOT-IMPERSONATE-EACH-OTHER-1` | AMBIGUOUS | PR #295, #1125, #1128 +3 merged; 1 referenced PR(s) closed unmerged | graded OPERATOR — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-DTO-LADDER-IS-THE-ALU-BUS-AND-WAS-ALREADY-RULED-1` | AMBIGUOUS | PR #1051 merged | graded CORRECTION — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-LIFT-GATE-FOUND-A-TIE-BLIND-SPEARMAN-1` | AMBIGUOUS | 1 cited path(s) live | CONFLICT: live TECH_DEBT entry vs STATUS_BOARD row done | +| `E-THE-PERIPHERY-OF-A-STRATUM-IS-THE-OTHER-STRATA-1` | AMBIGUOUS | PR #1141 merged; 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THINKING-ENGINE-LIVE-FOOTPRINT-IS-ONE-TRAIT-AND-HOUSE-IS-SHIPPED-IN-PIECES-1` | AMBIGUOUS | PR #387 merged | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-A-CENSUS-IS-A-FUNCTION-OF-ITS-REGEX-SO-GATE-THE-PROPERTY-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-CITATION-IS-NOT-A-DEPENDENCY-AND-A-FORCED-COPY-NEEDS-A-GATE-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-CORRECTION-IS-ONLY-AS-GOOD-AS-ITS-MERGE-1` | AMBIGUOUS | PR #1092 merged; 2 referenced PR(s) closed unmerged; 1 cited path(s) GONE | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-CROSS-REPO-SYMBOL-GREP-IS-ONLY-AS-FRESH-AS-THE-SIBLING-CHECKOUT-1` | AMBIGUOUS | PR #1157 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-HAND-SWEEP-UNDERCOUNTS-TOWARD-DONE-AND-THE-CRITERION-IS-THE-WHOLE-DESIGN-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-A-PROBE-CAN-STATE-A-MEASUREMENT-THAT-WAS-FALSE-WHEN-IT-WAS-WRITTEN-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-RULED-HOME-NEEDS-A-FIRST-CONSUMER-OR-IT-IS-A-VACANCY-1` | AMBIGUOUS | PR #1152 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-M8-COLLAPSE-TARGET-ALREADY-EXISTED-1` | AMBIGUOUS | PR #1151 merged; 1 cited path(s) live | CONFLICT: STATUS_BOARD row not done + live ISSUES entry vs STATUS_BOARD row done | +| `E-THE-ENTROPY-HOME-WAS-RULED-AND-LEFT-EMPTY-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-FIX-FOR-A-REVIEW-FINDING-SHIPS-UNREVIEWED-BY-DEFAULT-1` | AMBIGUOUS | PR #1154, #1160 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-FREE-MITIGATION-WAS-FREE-FOR-TWO-HOURS-1` | AMBIGUOUS | PR #1160 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-GATE-INHERITS-THE-BLIND-SPOT-OF-WHOEVER-WROTE-IT-1` | AMBIGUOUS | PR #1167, #1168, #1169 +1 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-SKETCH-THAT-MISSED-TWICE-WILL-MISS-A-THIRD-TIME-1` | AMBIGUOUS | PR #293, #294 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-COLUMN-OF-INDICES-INTO-A-CODEBOOK-THAT-DOES-NOT-EXIST-1` | AMBIGUOUS | 4 cited path(s) live | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-A-MACHINE-APPLICABLE-FIX-IS-A-SUGGESTION-NOT-A-PROOF-1` | AMBIGUOUS | PR #302, #1194, #1195 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NARS-EXPECTATION-CHOICE-PREFERS-IGNORANCE-TO-A-CONFIDENT-NEGATIVE-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NXG-1` | AMBIGUOUS | no implementation evidence | CONFLICT: live TECH_DEBT entry + own status line: PROPOSAL vs STATUS_BOARD row done | +| `E-NXG-12` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-NXG-13` | AMBIGUOUS | PR #288, #295 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NXG-14` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-NXG-15` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-NXG-17` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NXG-19` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NXG-20` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NXG-3` | AMBIGUOUS | 2 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NXG-4` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NXG-7` | AMBIGUOUS | PR #296, #1134, #1159 merged; 1 referenced PR(s) closed unmerged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-NXG-8` | AMBIGUOUS | PR #1129 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-PLANNING-MIGRATES-TO-LOCO-R2IL-DATAFUSION-IS-GRACE-PERIOD-1` | AMBIGUOUS | PR #1185 merged | graded OPERATOR-RULED — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-UNFINISHED-FUNCTION-WAS-NOT-THE-DEBT-1` | AMBIGUOUS | PR #1188 merged; 1 cited path(s) GONE | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-UNFINISHED-UDF-WAS-NOT-THE-DEBT-1` | AMBIGUOUS | PR #1185 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-VERSIONED-GRAPH-OVERWRITES-SO-ROW-ADDRESSES-ALIAS-ACROSS-VERSIONS-1` | AMBIGUOUS | PR #1190 merged; 1 cited path(s) live | CONFLICT: STATUS_BOARD row not done + live TECH_DEBT entry vs STATUS_BOARD row done | +| `E-I-CITED-THE-RIGHTMOST-REGISTER-AND-CALLED-IT-THE-ADDRESS-1` | AMBIGUOUS | PR #174, #175, #658 +1 merged | graded OPERATOR — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-AARCH64-PATH-HAD-NEVER-BEEN-COMPILED-1` | AMBIGUOUS | PR #146 merged; 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-DOC-COMMENT-IS-NOT-A-FAIL-CLOSED-MECHANISM-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-A-PLAN-INVENTORY-FINDS-THE-BOARD-LAGS-THE-TREE-IN-BOTH-DIRECTIONS-1` | AMBIGUOUS | PR #1198 merged | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-A-V3-MINT-MUST-NEVER-DEGRADE-TO-V1-1` | AMBIGUOUS | PR #1207 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-AN-EMPTY-RANGE-AFTER-A-RESET-IS-NOT-EVIDENCE-1` | AMBIGUOUS | PR #1201, #1203, #1217 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-EVERY-DOMAIN-IS-A-TABLE-AND-A-CROSSWALK-IS-A-CHAIN-OF-MASKS-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-PLUG-AND-PLAY-IS-THE-DECLARATION-NOT-A-TABLE-1` | AMBIGUOUS | PR #1207, #1216 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-RUNG-BAND-AND-PLASTICITY-ARE-THREE-AXES-NEVER-ONE-LEVEL-FIELD-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FENCE | +| `E-THE-FUSED-AND3-HOP-WAS-NEVER-SHIPPED-LGJ-HOP-IS-TWO-ANDS-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-V1-GUARD-WAS-TESTED-THE-V3-GUARD-THAT-REPLACED-IT-WAS-NOT-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-SIGMA-CHAIN-IS-A-PROVEN-UG-SURVIVAL-AND-PHI-IS-A-HOMONYM-1` | AMBIGUOUS | 1 cited path(s) live | graded FOSSIL — an epistemic grade, not a work status; no deliverable attached | +| `E-TRIPLE-MODEL-DKPOSITION-IS-AN-UNWIRED-DUPLICATE-1` | AMBIGUOUS | 4 cited path(s) live | graded FOSSIL — an epistemic grade, not a work status; no deliverable attached | +| `E-LE-IS-THE-UNIVERSAL-DTO-LAYER-TYPED-SYNTAX-MEANS-A-VERSIONED-LE-SCHEMA-1` | AMBIGUOUS | PR #1154, #1222, #1223 merged | CONFLICT: STATUS_BOARD row not done + live TECH_DEBT entry vs STATUS_BOARD row done | +| `E-HEX-TENANT-RAIL-IS-DIRECTION-CHAIN-IS-FREE-SHIFT-IS-THE-COST-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded — | +| `E-HEX-TENANT-RAIL-IS-DIRECTION-CHAIN-IS-FREE-SHIFT-IS-THE-COST-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-DISABLE-CAN-GO-RED-FOR-THE-WRONG-REASON-AND-THE-TWO-PEAK-FIGURES-WERE-NEVER-IN-CONFLICT-1` | AMBIGUOUS | PR #1233 merged | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-HORIZON-CUT-AND-AN-UNBOUND-MEET-ARE-NOT-THE-SAME-ANSWER-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-A-THOUGHT-MASKS-ITSELF-BY-ITS-DISTANCE-FROM-ROOT-THE-V3-FACET-IS-THE-MASK-AND-THE-RADIUS-IS-STEPLESS-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-UNIFORM-WEIGHT-ARM-CANNOT-MEASURE-EVIDENCE-ITS-ARGMIN-IS-INVARIANT-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-BOUNDED-ATTENTION-BUYS-REACH-AND-A-DISTANT-HOP-IS-A-TERNLOG-NOT-A-SEMIRING-1` | AMBIGUOUS | no implementation evidence | CONFLICT: live ISSUES entry vs STATUS_BOARD row done | +| `E-DENSITY-IS-FALSIFIED-THE-VARIABLE-IS-PATH-LENGTH-SPREAD-AND-THIS-RE-OPENS-A5-1` | AMBIGUOUS | no implementation evidence | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done + ISSUES entry resolved | +| `E-DEPTH-RANK-REPRODUCES-MOST-SPECIFIC-BUT-ONLY-ON-A-TAXONOMY-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-FAMILY-HAS-FOUR-WIDTHS-AND-4096-HAS-FIVE-REFERENTS-PIN-THE-UNIT-BEFORE-THE-ARITHMETIC-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-FUSING-FORFEITS-THE-SKIP-AND-ADAPTIVEFILTER-FAILS-IN-TWO-PLACES-NOT-ONE-1` | AMBIGUOUS | no implementation evidence | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-I-DECLARED-A-JOIN-ABSENT-BY-GREPPING-ONE-FILE-AND-COMPOSE-IS-THE-SAME-XOR-A-THIRD-TIME-1` | AMBIGUOUS | 5 cited path(s) live | graded CORRECTION — an epistemic grade, not a work status; no deliverable attached | +| `E-POPCOUNT-TIMES-SELF-THE-EXACT-PREFIX-IS-THE-K-EQUALS-ZERO-HAMMING-BALL-AND-THE-FUSED-ROW-PREDICATE-IS-THE-GAP-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-SIX-SEAMS-EVERY-CAUSAL-SELECTOR-SHIPS-AND-NONE-IS-WIRED-AT-THE-HOP-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-THE-BOXCAR-HORIZON-IS-NOT-A-DISCOUNT-IT-REVERSES-THE-OTHER-WAY-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-THE-CANON-SPECIFIED-THE-WHOLE-MASKED-O1-CHAIN-AND-ITS-LOAD-BEARING-LINKS-ARE-STUBS-1` | AMBIGUOUS | no implementation evidence | CONFLICT: live ISSUES entry vs STATUS_BOARD row done | +| `E-THE-RAIL-IS-A-NEEDLE-NOT-A-MASK-256-BY-256-IS-THE-EXACT-ROW-ADDRESS-AND-A-MASK-OVER-THE-AREA-IS-ANOTHER-OBJECT-1` | AMBIGUOUS | no implementation evidence | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-REVIEW-FOUND-A-REAL-BUG-THAT-FALSIFIED-MY-OWN-ISSUES-PREMISE-AND-I-BROKE-MY-OWN-RULE-IN-THE-FILE-STATING-IT-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-THE-RLHF-SHAPED-PROMOTION-LOOP-IS-IMPLEMENTED-END-TO-END-IN-A-PROBE-AND-HAS-NO-SRC-PROMOTER-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-THE-SEMIRING-IS-FREE-THE-COST-IS-CARRIER-WIDTH-AND-THE-JOIN-IS-THE-SAME-XOR-1` | AMBIGUOUS | 1 cited path(s) live | CONFLICT: live ISSUES entry vs ISSUES entry resolved | +| `E-THE-SKIP-LEVER-LIVES-ONLY-BELOW-THE-DENSITY-WHERE-D-GTM-0N-SAYS-SWITCH-TO-SPARSE-AND-THE-CLUSTERED-99-90-IS-PREFIX-ARITHMETIC-1` | AMBIGUOUS | 1 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-SLOWEST-GATE-IS-THE-ONE-YOUR-OWN-PUSH-CADENCE-CANCELS-1` | AMBIGUOUS | PR #1235 merged; 2 cited path(s) live | graded FINDING — an epistemic grade, not a work status; no deliverable attached | +| `E-FORMAT-SLOT-FOLD-IS-THE-SAME-OP-AS-THE-VL-DESCENT-1` | AMBIGUOUS | PR #310, #1242, #1243 +1 merged | graded MEASURED — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-SPINE-IS-WHATEVER-THE-READER-ALREADY-HAS-AN-ADDRESS-FOR-1` | AMBIGUOUS | PR #1085, #1240 merged; 1 cited path(s) live | graded OPERATOR-RULED — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-SECOND-FACET-IS-NOT-AN-EDGE-BLOCK-1` | AMBIGUOUS | no implementation evidence | graded OPERATOR-RULED — an epistemic grade, not a work status; no deliverable attached | +| `E-BYTES-ARE-STORED-INTEGERS-ARE-PROJECTED-1` | AMBIGUOUS | PR #1245, #1246 merged | graded OPERATOR-RULED — an epistemic grade, not a work status; no deliverable attached | +| `E-NO-FOLD-REPORTS-AN-O-POPULATION-COST-1` | AMBIGUOUS | no implementation evidence | graded — — an epistemic grade, not a work status; no deliverable attached | +| `E-1224-CLOSED-FOR-BEING-WRONG-NOT-FOR-LACKING-CONSUMERS-1` | AMBIGUOUS | 1 referenced PR(s) closed unmerged | graded CORRECTION — an epistemic grade, not a work status; no deliverable attached | +| `E-1224-WAS-A-BIDIRECTIONAL-DOMAIN-INVERSION-NOT-A-LEAK-1` | AMBIGUOUS | 1 referenced PR(s) closed unmerged | graded SHARPENING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-BORROW-IS-NOT-A-REPLAY-CARRIER-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded RULING | +| `E-A-BOUND-AND-A-TILE-ARE-INTERVALS-IN-DIFFERENT-ORDERS-1` | AMBIGUOUS | no implementation evidence | CONFLICT: STATUS_BOARD row not done vs STATUS_BOARD row done | +| `E-A-DOMAIN-IS-AN-OPTIONAL-CONSUMER-THROUGH-OGAR-NEVER-A-CO-DEFINER-1` | AMBIGUOUS | 1 referenced PR(s) closed unmerged | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-A-POSITIONAL-INDEX-ADDED-TO-A-KEY-DIGEST-ATTESTS-NOTHING-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded FINDING | +| `E-A-THOUGHT-IS-A-REPLAYABLE-OPERATOR-NOT-A-MAINTAINED-STATE-1` | AMBIGUOUS | PR #1245, #1250 merged | graded RULING — an epistemic grade, not a work status; no deliverable attached | +| `E-ATTENTION-IS-NOT-EVIDENCE-AND-FIRE-IS-NOT-DURABILITY-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded RULING | +| `E-FOLDS-ARE-ZERO-COPY-PERIOD-PEEK-NOT-BORROW-BUILD-FOLD-1` | AMBIGUOUS | no implementation evidence | graded LAW — an epistemic grade, not a work status; no deliverable attached | +| `E-FROZEN-IS-FINE-MARCHING-IS-THE-DISASTER-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded RULING | +| `E-MASKING-IS-AN-OPERATION-A-MASK-IS-A-CARRIER-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded RULING | +| `E-ONE-OBSERVABLE-IS-NOT-THREE-INSTRUMENTS-AND-IMPORTS-ARE-PROBES-1` | AMBIGUOUS | 1 referenced PR(s) closed unmerged | graded FENCE — an epistemic grade, not a work status; no deliverable attached | +| `E-REPLAY-CAN-BE-CHEAPER-THAN-STORAGE-1` | AMBIGUOUS | no implementation evidence | graded CONJECTURE — an epistemic grade, not a work status; no deliverable attached | +| `E-THE-1224-DETOUR-CLEANUP-PASS-WHAT-WAS-CONTAMINATION-AND-WHAT-SURVIVES-1` | AMBIGUOUS | 1 referenced PR(s) closed unmerged | graded CLEANUP — an epistemic grade, not a work status; no deliverable attached | +| `E-ZERO-COPY-IS-NOT-A-SIZE-THRESHOLD-1` | AMBIGUOUS | no implementation evidence | no join key at all; graded RULING | + +--- + +## 4. What this baseline does NOT claim + +- It does not claim the 228 AMBIGUOUS rows are resolved, wrong, or safe + to delete. They are unadjudicated, and that is recorded, not hidden. +- It does not claim a merged PR closed the finding attached to it. +- It does not claim the frozen prose was reviewed. **FROZEN ≠ RECONCILED.** +- It is not a licence to start another archaeology pass over the ambiguous + rows. If one matters later it resurfaces as live work and enters the + transient tier like anything else. + +## 5. Steady state after this checkpoint + +``` +new work → .claude/board/entries/ → reconcile against current state + → OPEN | CLOSED | SUPERSEDED | AMBIGUOUS + → rare Eureka promotion to EPIPHANIES.md (must cite its entry) + → advance PROCESSED_THROUGH_SHA to the captured source head +``` + +MIRROR dies. Corrections die. Failed probes normally die. Git keeps the +route. Only surviving state crosses the checkpoint. diff --git a/.claude/board/PROCESSED_THROUGH b/.claude/board/PROCESSED_THROUGH new file mode 100644 index 000000000..4ff996039 --- /dev/null +++ b/.claude/board/PROCESSED_THROUGH @@ -0,0 +1,28 @@ +# Findings watermark — machine-readable. ONE authoritative field. +# +# PROCESSED_THROUGH_SHA names the source revision whose findings have been +# CONSUMED into a baseline. It is NOT the SHA of the commit that carries this +# file: a commit cannot contain its own hash, because the file's bytes feed +# the hash. The commit that first recorded this value has a different SHA of +# its own, and that is correct. +# +# Incremental semantics, one step per closeout: +# +# 1. capture NEW_HEAD = git rev-parse HEAD (before generating anything) +# 2. consume the delta PROCESSED_THROUGH_SHA..NEW_HEAD +# 3. reconcile it -> OPEN | CLOSED | SUPERSEDED | AMBIGUOUS +# 4. write the compact state +# 5. set PROCESSED_THROUGH_SHA = NEW_HEAD +# +# Routine closeout reads the DELTA only. It never censuses the historical +# monolith again. If this SHA cannot be resolved (a shallow clone whose +# grafts cut above it), tooling MUST FAIL CLOSED with a diagnostic naming the +# revision — an unresolvable baseline is never an empty delta. +# +# The date is metadata for humans and is not load-bearing. If the two ever +# disagree, the SHA wins: imports, backdated headings, rebases and concurrent +# work all make a calendar watermark lie. + +PROCESSED_THROUGH_SHA=181bb2c28005c185a967edd61367008c6722eb5c +PROCESSED_THROUGH_DATE=2026-09-20 +BASELINE=.claude/board/FINDINGS-BASELINE-2026-09-20.md diff --git a/.claude/tools/epiphany_provenance.py b/.claude/tools/epiphany_provenance.py new file mode 100644 index 000000000..08cc0adb4 --- /dev/null +++ b/.claude/tools/epiphany_provenance.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python3 +"""Every EPIPHANY added after the baseline must cite its originating entry. + + python3 .claude/tools/epiphany_provenance.py # gate + python3 .claude/tools/epiphany_provenance.py --self-test # falsifier + +WHAT IT PROVES, AND ONLY THIS +----------------------------- +PROVENANCE. A level-2 `EPIPHANIES.md` heading added since +`PROCESSED_THROUGH_SHA` must carry a reference to a +`.claude/board/entries/YYYY-MM-DD-.md` that EXISTS. That enforces the +mechanical invariant `work -> entries/`, never `work -> EPIPHANIES.md`. + +It does NOT decide whether the entry is a Eureka, whether NEW / LOAD-BEARING / +DURABLE is satisfied, or whether promoting it was wise. Those are the human +closeout admission rule and are deliberately not mechanised: a regex that +tried to judge Eureka-ness would be a guard that fires on everything, which +carries exactly as much information as one that never fires. + +WHY THE WATERMARK IS A SHA AND NOT A DATE +----------------------------------------- +Imported entries, backdated headings, rebases and concurrent work all make a +calendar watermark lie — `supersession_index.py` already refuses git mtime as +a signal for the same reason ("2026-07-24 is a bulk import ... git dates the +import, not the work"). The SHA names a revision, so the delta is exact. + +FAIL CLOSED ON A SHALLOW CLONE +------------------------------ +This repo is routinely a shallow clone (`.git/shallow`, 6 grafts). If the +baseline revision is above the graft boundary, `git diff` cannot see it. The +gate then REFUSES with a diagnostic naming the revision. Treating unreachable +history as an empty delta is the failure this rule exists to prevent: it would +report a clean pass precisely when it can see nothing. +""" + +import os +import pathlib +import re +import subprocess +import sys + +MARKER = ".claude/board/PROCESSED_THROUGH" +EPI = ".claude/board/EPIPHANIES.md" +ENTRY_REF = re.compile(r"entries/(\d{4}-\d{2}-\d{2}-[A-Za-z0-9._-]+\.md)") +HEAD2 = re.compile(r"^##\s+(?!#)(.*)$") +EID = re.compile(r"\b(E-[A-Z0-9][A-Z0-9-]{3,})\b") + + +def run(args, cwd): + return subprocess.run(args, cwd=cwd, capture_output=True, text=True) + + +def baseline_sha(root: str) -> str: + """The consumed-input revision. Never this commit's own hash.""" + p = pathlib.Path(root, MARKER) + if not p.is_file(): + raise SystemExit( + f"epiphany-provenance: {MARKER} is missing. The gate cannot define a " + "delta without a baseline; add the marker rather than disabling this." + ) + for line in p.read_text(errors="ignore").splitlines(): + if line.startswith("PROCESSED_THROUGH_SHA="): + return line.split("=", 1)[1].strip() + raise SystemExit(f"epiphany-provenance: no PROCESSED_THROUGH_SHA= line in {MARKER}") + + +def added_headings(root: str, sha: str) -> list[str]: + """Level-2 headings ADDED to EPIPHANIES.md since `sha`. + + Fails closed when `sha` is not reachable — see the module docs. + """ + if run(["git", "cat-file", "-e", f"{sha}^{{commit}}"], root).returncode != 0: + shallow = pathlib.Path(root, ".git", "shallow") + hint = ( + " This clone is SHALLOW (.git/shallow exists), so the baseline is most " + "likely above the graft boundary. Deepen it " + "(`git fetch --shallow-exclude= --unshallow`) and re-run." + if shallow.exists() else "" + ) + raise SystemExit( + f"epiphany-provenance: baseline revision {sha} is NOT REACHABLE in this " + f"repository, so the delta cannot be computed.{hint} REFUSING — " + "unreachable history is not an empty delta." + ) + d = run(["git", "diff", "--unified=0", f"{sha}..HEAD", "--", EPI], root) + if d.returncode != 0: + raise SystemExit(f"epiphany-provenance: git diff failed: {d.stderr.strip()}") + out = [] + for line in d.stdout.splitlines(): + if not line.startswith("+") or line.startswith("+++"): + continue + m = HEAD2.match(line[1:]) + if m: + out.append(m.group(1)) + return out + + +def body_of(text: str, heading: str) -> str: + """The entry under `heading`, up to the next heading of level <= 2.""" + lines = text.split("\n") + try: + start = next(i for i, l in enumerate(lines) + if HEAD2.match(l) and HEAD2.match(l).group(1) == heading) + except StopIteration: + return "" + end = len(lines) + for j in range(start + 1, len(lines)): + m = re.match(r"^(#{1,2})\s+(?!#)", lines[j]) + if m: + end = j + break + return "\n".join(lines[start:end]) + + +def check(root: str) -> tuple[list[tuple[str, str]], int]: + """-> (violations, number of added headings examined).""" + sha = baseline_sha(root) + heads = added_headings(root, sha) + text = pathlib.Path(root, EPI).read_text(errors="ignore") + bad = [] + for h in heads: + body = body_of(text, h) + refs = ENTRY_REF.findall(body) + live = [r for r in refs if pathlib.Path(root, ".claude/board/entries", r).is_file()] + if not refs: + bad.append((h, "no entries/ reference")) + elif not live: + bad.append((h, f"references a file that does not exist: {', '.join(refs[:3])}")) + return bad, len(heads) + + +def main(argv: list[str]) -> int: + root = run(["git", "rev-parse", "--show-toplevel"], ".").stdout.strip() or "." + if "--self-test" in argv: + return self_test() + bad, n = check(root) + print(f"epiphany-provenance: baseline {baseline_sha(root)[:12]}, " + f"{n} level-2 heading(s) added since it, {len(bad)} without provenance") + if not bad: + return 0 + print() + print("::error::An EPIPHANY was added without citing its originating entry.") + print("Ordinary work lands in .claude/board/entries/ and is reconciled at") + print("closeout; only a surviving Eureka is promoted here, and a promotion") + print("must name the entry it came from so the route stays recoverable.") + for h, why in bad: + eid = EID.search(h) + print(f" - {eid.group(1) if eid else h[:60]}: {why}") + return 1 + + +def self_test() -> int: + """Prove the gate FIRES on a missing reference and STAYS SILENT on a real + one — in a throwaway repo, so neither half can pass vacuously.""" + import tempfile + + d = tempfile.mkdtemp(prefix="epiphany-provenance-selftest-") + ent = pathlib.Path(d, ".claude/board/entries") + ent.mkdir(parents=True) + tools = pathlib.Path(d, ".claude/tools") + tools.mkdir(parents=True) + epi = pathlib.Path(d, EPI) + epi.write_text("# Epiphanies\n\n## 2026-01-01 E-BASE-1 — pre-baseline\n\nbody\n") + (ent / "2026-09-20-e-real-1.md").write_text("# entry\n") + for a in (["init", "-q"], ["add", "-A"], + ["-c", "user.email=t@t", "-c", "user.name=t", "commit", "-qm", "base"]): + run(["git", *a], d) + sha = run(["git", "rev-parse", "HEAD"], d).stdout.strip() + pathlib.Path(d, MARKER).write_text(f"PROCESSED_THROUGH_SHA={sha}\n") + + def commit_and_check(extra: str, label: str): + epi.write_text(epi.read_text() + extra) + run(["git", "add", "-A"], d) + run(["git", "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-qm", label], d) + return check(d) + + ok = True + + # (a) an addition WITH a resolvable reference -> silent + bad, n = commit_and_check( + "\n## 2026-09-20 E-GOOD-1 — cites its entry\n\n" + "From `.claude/board/entries/2026-09-20-e-real-1.md`.\n", "good") + print(f" with a live entries/ reference : {n} added, {len(bad)} violation(s)") + if bad or n != 1: + print(" FAILED: the gate must stay SILENT on a well-formed promotion") + ok = False + + # (b) an addition with NO reference -> fires + bad, n = commit_and_check("\n## 2026-09-20 E-BAD-1 — cites nothing\n\nbody\n", "bad") + if not any(w == "no entries/ reference" for _h, w in bad): + print(f" FAILED: no violation raised for a reference-less addition ({bad})") + ok = False + else: + print(f" with no reference : {len(bad)} violation(s) (fires)") + + # (c) an addition referencing a MISSING file -> fires (a name is not a file) + bad, n = commit_and_check( + "\n## 2026-09-20 E-BAD-2 — cites a ghost\n\n" + "See `.claude/board/entries/2026-09-20-e-does-not-exist.md`.\n", "ghost") + if not any("does not exist" in w for _h, w in bad): + print(f" FAILED: a dangling reference was accepted ({bad})") + ok = False + else: + print(f" with a dangling reference : fires") + + # (d) an unreachable baseline must REFUSE, never report a clean delta + pathlib.Path(d, MARKER).write_text( + "PROCESSED_THROUGH_SHA=" + "0" * 40 + "\n") + try: + check(d) + print(" FAILED: an unreachable baseline did not refuse") + ok = False + except SystemExit as exc: + if "NOT REACHABLE" not in str(exc): + print(f" FAILED: wrong refusal: {exc}") + ok = False + else: + print(" with an unreachable baseline : refuses (fail-closed)") + + print("epiphany-provenance --self-test " + ("PASSED" if ok else "FAILED")) + return 0 if ok else 1 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv[1:])) diff --git a/.claude/tools/findings_baseline.py b/.claude/tools/findings_baseline.py new file mode 100644 index 000000000..724374f7b --- /dev/null +++ b/.claude/tools/findings_baseline.py @@ -0,0 +1,597 @@ +#!/usr/bin/env python3 +"""Reconcile EPIPHANIES.md findings into OPEN / CLOSED / SUPERSEDED / AMBIGUOUS. + + python3 .claude/tools/findings_baseline.py --report + python3 .claude/tools/findings_baseline.py --emit + python3 .claude/tools/findings_baseline.py --self-test + +WHY THIS IS A TOOL AND NOT A ONE-OFF SCRIPT +------------------------------------------- +It produced the numbers cited in `FINDINGS-BASELINE-2026-09-20.md`, and the +DELTA closeouts after that baseline need the SAME rubric. A rubric that lives +only in prose gets re-invented per session, each time slightly differently, +and then two passes disagree about what OPEN meant. + +WHAT IT REFUSES TO DO +--------------------- +It never reads prose to manufacture a status. Each join answers only the +question it can answer: + + STATUS_BOARD D-id row -> deliverable status DECISIVE + ISSUES section -> unresolved / resolved DECISIVE + TECH_DEBT section -> implementation debt DECISIVE (OPEN) + own status line -> only if work-shaped DECISIVE + PR state -> landing evidence NEVER decides + live code citation -> implementation reality NEVER decides + entries/ , LATEST_STATE-> provenance NEVER decides + +Conflicting decisive evidence -> AMBIGUOUS, never averaged into certainty. +Absent decisive evidence -> AMBIGUOUS. + +THREE MEASURED TRAPS THIS ENCODES +--------------------------------- +1. `STATUS_BOARD.md` carries 28 distinct header schemas with `status` at index + 1..6 and ABSENT in two, so the column is located from each table's own + header. Reading a fixed index returns prose as a status. +2. 303/306 entries carry a `Status:` line but 295 lead with an EPISTEMIC GRADE + (`FINDING` 204, `RULING` 31, `CORRECTION` 11, ...), which answers *how well + established is this claim*, not *is the work done*. Only a work-shaped + leading token is status evidence. +3. Cross-supersession needs DIRECTIONAL phrasing. A bare `⊘`-near-the-E-id + rule read `caveat (⊘ in E-FOO-1)` -- a sibling CITING this entry's own + caveat -- as the sibling superseding it. The relation is directional and + proximity inverted it. +""" + +import collections +import json +import os +import pathlib +import re +import subprocess +import sys + +WATERMARK = "2026-08-06" +EPI = ".claude/board/EPIPHANIES.md" +MARKER = ".claude/board/PROCESSED_THROUGH" + +DATE = re.compile(r"(20\d{2}-\d{2}-\d{2})") +EID = re.compile(r"\b(E-[A-Z0-9][A-Z0-9-]{3,})\b") +PR = re.compile(r"#(\d{3,5})\b") +CITE = re.compile(r"\b((?:crates|native|java|\.claude)/[A-Za-z0-9_./-]+\.(?:rs|md|py|toml|sh|yml))") +RESOLVED = re.compile(r"\b(RESOLVED|CLOSED|FIXED|LANDED|SHIPPED|DONE)\b") +DONE = re.compile(r"^\W*(shipped|done|complete|completed|landed|closed|merged|resolved|✅|✔)", re.I) +OPEN = re.compile(r"^\W*(queued|in progress|in-progress|in pr|blocked|open|todo|pending|next|planned|proposed|deferred|wip)", re.I) +OWN = re.compile(r"^\s*[>*\-\s]*\*{0,2}(?:Status|STATUS|Verdict|State)\*{0,2}\s*[:—-]\s*\*{0,2}(.{0,70})", re.M) +SUP_A = r"(?:supersedes|supersede|superseding|retires|retiring|replaces)\s+\S{0,40}?%s" +SUP_B = r"%s\S{0,8}[^\n]{0,80}?(?:is (?:now )?SUPERSEDED|SUPERSEDED by|is RETIRED|now RETIRED)" +WORK_DONE = ("SHIPPED", "CLOSED", "FIXED", "LANDED", "DONE", "RESOLVED", "COMPLETE") +WORK_OPEN = ("OPEN", "QUEUED", "BLOCKED", "PROPOSAL", "PENDING", "DEFERRED") + + +def did_pattern(root: str) -> "re.Pattern[str]": + """The D-id pattern, READ from the generator that owns it. + + A second copy would agree until one was edited, which is exactly when + nobody is comparing them -- the drift `plan_dids.py` refuses for the same + reason and by the same mechanism. + """ + src = pathlib.Path(root, ".claude/tools/supersession_index.py").read_text(errors="ignore") + m = re.search(r"^DID\s*=\s*re\.compile\(r'(.*)'\)\s*$", src, re.M) + if not m: + raise SystemExit( + "findings-baseline: the `DID = re.compile(r'...')` definition moved in " + "supersession_index.py. Fix this extractor; do not copy the pattern here." + ) + return re.compile(m.group(1)) + + +def population(root: str, watermark: str = WATERMARK) -> tuple[list[dict], dict]: + """Level-2 post-watermark headings carrying an E-id, plus the exclusions. + + A level-3 heading is a sub-section INSIDE an entry, so it must not + terminate a body and is not itself an entry; a dated level-2 heading with + no E-id is a date-group header. Both are counted, so the exclusion is + visible rather than asserted. + """ + lines = pathlib.Path(root, EPI).read_text(errors="ignore").split("\n") + heads = [(i, len(m.group(1)), m.group(2)) + for i, l in enumerate(lines) + if (m := re.match(r"^(#{2,3})\s+(.*)$", l))] + out, skipped = [], {"level3": 0, "no_eid": 0} + for idx, (i, lvl, text) in enumerate(heads): + d = DATE.search(text) + if not d or d.group(1) < watermark: + continue + if lvl == 3: + skipped["level3"] += 1 + continue + e = EID.search(text) + if not e: + skipped["no_eid"] += 1 + continue + end = len(lines) + for j, l2, _t in heads[idx + 1:]: + if l2 <= 2: + end = j + break + out.append({"eid": e.group(1), "date": d.group(1), "heading": text, + "line": i + 1, "body": "\n".join(lines[i:end])}) + return out, skipped + + +def status_board(root: str, did: "re.Pattern[str]") -> dict: + """D-id -> status rows, with the status column located PER TABLE.""" + rows, hdr = collections.defaultdict(list), None + for ln in pathlib.Path(root, ".claude/board/STATUS_BOARD.md").read_text(errors="ignore").split("\n"): + if not ln.startswith("|"): + continue + cells = [c.strip() for c in ln.rstrip().rstrip("|").split("|")[1:]] + low = [c.lower().strip("*").strip() for c in cells] + if low and low[0] in ("d-id", "id", "deliverable", "row", "item"): + hdr = low + continue + if re.match(r"^[-: |]+$", ln.strip()) or hdr is None or not cells: + continue + if not did.search(cells[0]) or "status" not in hdr: + # A schema with NO status column (`| D-id | correction |`) carries + # no status evidence. MEASURED: separating "on the board but + # statusless" as its own provenance key reaches 0 of 306 entries, + # so the distinction would be an inert branch -- and a guard that + # never fires carries as much information as one that always does. + continue + i = hdr.index("status") + if i >= len(cells): + continue + cell = cells[i] + v = "done" if DONE.match(cell) else "open" if OPEN.match(cell) else "other" + for d in did.findall(cells[0]): + rows[d].append({"status": cell[:72], "verdict": v}) + return rows + + +def sections(path: pathlib.Path) -> dict: + out, cur, buf = {}, None, [] + if not path.is_file(): + return out + for ln in path.read_text(errors="ignore").split("\n"): + if (m := re.match(r"^##\s+(.*)$", ln)): + if cur: + out[cur] = "\n".join(buf) + cur, buf = m.group(1), [ln] + elif cur: + buf.append(ln) + if cur: + out[cur] = "\n".join(buf) + return out + + +def named_in(secs: dict, eid: str) -> tuple[bool, bool]: + """(live, resolved). Resolution is asserted in the heading or the first two + lines -- a section that merely DISCUSSES a resolution is not resolved.""" + live = resolved = False + for head, body in secs.items(): + if eid not in body: + continue + top = head + "\n" + "\n".join(body.split("\n")[1:3]) + if RESOLVED.search(top): + resolved = True + else: + live = True + return live, resolved + + +def pr_states(root: str) -> dict: + """Cached PR number -> state, if a cache was left beside the marker. + + PR state is landing evidence only, so its ABSENCE never changes a verdict; + it only thins the implementation column. The tool therefore does not + require network access to reproduce a classification. + """ + p = pathlib.Path(root, ".claude/board/.pr-state-cache.json") + try: + return json.loads(p.read_text()) + except Exception: + return {} + + +def classify(root: str, watermark: str = WATERMARK) -> tuple[list[dict], dict]: + did = did_pattern(root) + entries, skipped = population(root, watermark) + sb = status_board(root, did) + iss = sections(pathlib.Path(root, ".claude/board/ISSUES.md")) + td = sections(pathlib.Path(root, ".claude/board/TECH_DEBT.md")) + prs = pr_states(root) + + board = {} + for name, rel in (("status_board", ".claude/board/STATUS_BOARD.md"), + ("tech_debt", ".claude/board/TECH_DEBT.md"), + ("integration_plans", ".claude/board/INTEGRATION_PLANS.md"), + ("issues", ".claude/board/ISSUES.md"), + ("latest_state", ".claude/board/LATEST_STATE.md"), + ("supersession", ".claude/board/SUPERSESSION-INDEX.md")): + f = pathlib.Path(root, rel) + if f.is_file(): + board[name] = f.read_text(errors="ignore") + ed = pathlib.Path(root, ".claude/board/entries") + board["entries"] = "\n".join( + (ed / f).read_text(errors="ignore") + for f in sorted(os.listdir(ed)) if f.endswith(".md") and f != "README.md" + ) if ed.is_dir() else "" + + alltext = "\n".join(e["body"] for e in entries) + rows = [] + for e in entries: + eid, body = e["eid"], e["body"] + dids = sorted(set(did.findall(body))) + prnums = sorted({int(p) for p in PR.findall(body)}) + cites = sorted(set(CITE.findall(body))) + + keys = {} + if (direct := [k for k, t in board.items() if eid in t]): + keys["eid_board"] = direct + if (known := [d for d in dids if d in sb]): + keys["did_statusboard"] = known + if dids and not known: + keys["did_unknown"] = dids + if prnums: + keys["pr"] = prnums + live_cites = [c for c in cites if pathlib.Path(root, c).exists()] + dead_cites = [c for c in cites if not pathlib.Path(root, c).exists()] + if live_cites: + keys["cite_live"] = live_cites + if dead_cites: + keys["cite_dead"] = dead_cites + + grade, own = "", "" + if (m := OWN.search(body)): + val = m.group(1).strip().lstrip("*").strip() + t = re.match(r"[A-Za-z⊘-]+", val) + grade = t.group(0).upper() if t else "" + if val.startswith("⊘"): + own = "sup" + elif grade in WORK_DONE: + own = "done" + elif grade in WORK_OPEN: + own = "open" + + self_sup = bool(re.search(r"\b(SUPERSEDED|RETIRED|WITHDRAWN|REJECTED-BY-FALSIFIER)\b", + e["heading"])) or own == "sup" + others = alltext.replace(body, "", 1) + q = re.escape(eid) + cross_sup = bool(re.search(SUP_A % q, others, re.I) or re.search(SUP_B % q, others)) + + verdicts = {r["verdict"] for d in known for r in sb[d]} + iss_live, iss_res = named_in(iss, eid) + td_live, td_res = named_in(td, eid) + open_ev, done_ev = [], [] + if "open" in verdicts: + open_ev.append("STATUS_BOARD row not done") + if "done" in verdicts: + done_ev.append("STATUS_BOARD row done") + if iss_live: + open_ev.append("live ISSUES entry") + if iss_res: + done_ev.append("ISSUES entry resolved") + if td_live: + open_ev.append("live TECH_DEBT entry") + if td_res: + done_ev.append("TECH_DEBT entry resolved") + if own == "done": + done_ev.append(f"own status line: {grade}") + if own == "open": + open_ev.append(f"own status line: {grade}") + + merged = [p for p in prnums if prs.get(str(p)) == "merged"] + unmerged = [p for p in prnums if prs.get(str(p)) == "closed"] + impl = [] + if merged: + impl.append("PR " + ", ".join(f"#{p}" for p in merged[:3]) + + (f" +{len(merged) - 3}" if len(merged) > 3 else "") + " merged") + if unmerged: + impl.append(f"{len(unmerged)} referenced PR(s) closed unmerged") + if not merged and not unmerged and prnums: + impl.append(f"{len(prnums)} PR ref(s), state not cached") + if live_cites: + impl.append(f"{len(live_cites)} cited path(s) live") + if dead_cites: + impl.append(f"{len(dead_cites)} cited path(s) GONE") + if not impl: + impl.append("no implementation evidence") + + if self_sup or cross_sup: + status = "SUPERSEDED" + why = ["own heading/status ⊘ note" if self_sup + else "superseded by a sibling entry"] + elif open_ev and done_ev: + status = "AMBIGUOUS" + why = ["CONFLICT: " + " + ".join(open_ev) + " vs " + " + ".join(done_ev)] + elif open_ev: + status, why = "OPEN", open_ev + elif done_ev: + status, why = "CLOSED", done_ev + else: + status = "AMBIGUOUS" + why = ["no decisive status evidence" + ("" if keys else " and no join key at all")] + + rows.append({"eid": eid, "date": e["date"], "status": status, "grade": grade, + "impl": "; ".join(impl), "why": "; ".join(why), + "keys": sorted(keys), "joined": bool(keys)}) + + usable = ("eid_board", "did_statusboard", "pr", "cite_live") + stats = { + "population": len(rows), + "excluded": skipped, + "verdicts": dict(collections.Counter(r["status"] for r in rows)), + "grades": dict(collections.Counter(r["grade"] for r in rows if r["grade"])), + "joined": sum(1 for r in rows if any(k in r["keys"] for k in usable)), + "nojoin": sum(1 for r in rows if not r["joined"]), + "key_reach": {k: sum(1 for r in rows if k in r["keys"]) + for k in (*usable, "did_unknown", "cite_dead")}, + } + amb = [r for r in rows if r["status"] == "AMBIGUOUS"] + stats["ambiguous"] = { + "conflict": sum(1 for r in amb if r["why"].startswith("CONFLICT")), + "no_decisive_but_joined": sum(1 for r in amb + if not r["why"].startswith("CONFLICT") and r["joined"]), + "no_join": sum(1 for r in amb if not r["joined"]), + } + return rows, stats + + +def baseline_sha(root: str) -> str: + p = pathlib.Path(root, MARKER) + if p.is_file(): + for line in p.read_text(errors="ignore").splitlines(): + if line.startswith("PROCESSED_THROUGH_SHA="): + return line.split("=", 1)[1].strip() + return "" + + +def main(argv: list[str]) -> int: + root = subprocess.run(["git", "rev-parse", "--show-toplevel"], + capture_output=True, text=True).stdout.strip() or "." + if "--self-test" in argv: + return self_test(root) + rows, stats = classify(root) + if "--emit" in argv: + out = argv[argv.index("--emit") + 1] + pathlib.Path(out).write_text(render(rows, stats, baseline_sha(root))) + print(f"wrote {out}: {len(rows)} rows") + return 0 + print(json.dumps(stats, indent=1)) + return 0 + + +def render(rows: list[dict], stats: dict, sha: str) -> str: + """The committed baseline document. Every number is interpolated from + `stats`, so the prose and the table cannot disagree -- and a hand-edit to + 'correct' a count is never the right move.""" + v, a, kr = stats["verdicts"], stats["ambiguous"], stats["key_reach"] + n = stats["population"] + L = [f"# Findings baseline — {sha[:12] or 'unpinned'} (`EPIPHANIES.md`, post-{WATERMARK} entries)", ""] + w = L.append + w("> **What this is.** The ONE historical catch-up over the findings that went") + w("> into the `EPIPHANIES.md` monolith after the 2026-08-06 split watermark.") + w("> It is a consolidated current-state checkpoint — a **k-frame**. After it,") + w("> routine closeout is DELTA ONLY and never censuses the monolith again.") + w("> Like `PLAN-INVENTORY-2026-09-07.md` it mints **no D-ids**, so") + w("> `supersession_index.py` and `plan_dids.py` do not see it — by design.") + w("> Regenerate: `python3 .claude/tools/findings_baseline.py --emit `.") + w(">") + w("> **The historical prose is FROZEN, not reconciled away.** `EPIPHANIES.md`") + w("> is untouched: nothing was migrated, re-split, deleted or rewritten, and") + w("> no entry files were created for these findings. Frozen means *not reread") + w(f"> by routine closeout*; it does NOT mean adjudicated — {v.get('AMBIGUOUS', 0)} of {n} were not.") + w(">") + w(f"> **PROCESSED_THROUGH_SHA = `{sha}`** — every eligible finding visible") + w("> through that source revision is consumed into this baseline. The marker") + w("> names the CONSUMED INPUT, never this file's own commit: a commit cannot") + w("> contain its own hash. Machine-readable: `.claude/board/PROCESSED_THROUGH`.") + w("") + w("---") + w("") + w("## 0. The numbers") + w("") + w("| | count |") + w("|---|---|") + w(f"| population (level-2 post-watermark entries with an E-id) | **{n}** |") + for k in ("OPEN", "CLOSED", "SUPERSEDED", "AMBIGUOUS"): + w(f"| {k} | {v.get(k, 0)} |") + w("") + ex = stats["excluded"] + w(f"Excluded and counted so the exclusion is visible, not asserted: **{ex['no_eid']}**") + w(f"level-2 bare date-group headers (no E-id) and **{ex['level3']}** level-3") + w(f"sub-headings (sections *inside* an entry). {n} + {ex['no_eid']} + {ex['level3']} =") + w(f"{n + ex['no_eid'] + ex['level3']} dated headings at or after the watermark.") + w("") + w("### Mechanical reachability — the union of join keys") + w("") + w("A first estimate put the ceiling at 198 by taking `306 − 108 without a D-id") + w("or PR`. That was wrong: the E-id → board joins are **independent keys** and") + w("most of them land inside that 108.") + w("") + w("| join key | entries | answers |") + w("|---|---|---|") + for k, q in (("eid_board", "named on a board surface — provenance"), + ("did_statusboard", "a referenced D-id has a STATUS_BOARD row — deliverable status"), + ("pr", "a PR is referenced — landing evidence ONLY"), + ("cite_live", "a cited path still exists — implementation reality"), + ("did_unknown", "referenced D-id has NO status-bearing board row — dangling"), + ("cite_dead", "cited path is GONE — stale citation")): + w(f"| `{k}` | {kr.get(k, 0)} | {q} |") + w("") + w(f"**{stats['joined']}** entries carry ≥ 1 usable key; **{stats['nojoin']}** carry none and are") + w(f"therefore automatically AMBIGUOUS. The other {v.get('AMBIGUOUS', 0) - a['no_join']} ambiguous rows are") + w("ambiguous for a different and more interesting reason — §1.") + w("") + w("## 1. Why AMBIGUOUS is the largest bucket") + w("") + gr = stats["grades"] + tot = sum(gr.values()) + workish = sum(c for g, c in gr.items() if g in WORK_DONE + WORK_OPEN) + w(f"**{tot} of the {n} entries carry their own `Status:` line, and {tot - workish} of those lead") + w("with an EPISTEMIC GRADE rather than a work status:**") + w("") + w("| leading token | entries |") + w("|---|---|") + for k, c in sorted(gr.items(), key=lambda kv: -kv[1])[:10]: + w(f"| `{k}` | {c} |") + w("") + w("`FINDING`, `RULING`, `CORRECTION`, `MEASURED` answer *how well established") + w(f"is this claim*. They do not answer *is the work done*. Only **{workish}** entries") + w("lead with a work-shaped token.") + w("") + w("That is the substantive result: **post-watermark `EPIPHANIES.md` was being") + w("used as a findings log, not a deliverable tracker.** For most rows") + w("OPEN/CLOSED is the wrong axis — the live question is *is this still true?*,") + w("which no join answers mechanically. Reading their prose to manufacture a") + w("status is what this pass was told not to do, so they stay AMBIGUOUS with") + w("their grade recorded.") + w("") + w("Not a comparable number: `PLAN-INVENTORY-2026-09-07.md` reached 40/211") + w("ambiguous **with a human read of every status line in context**, and records") + w("that naive substring matching produced ≥ 6 false positives in its corpus.") + w("This pass is mechanical-only by instruction; the larger residue is the price") + w("of that, not a worse measurement.") + w("") + w("## 2. How to read a verdict") + w("") + w("Vocabulary reused from `PLAN-INVENTORY`; nothing new minted. Each join") + w("answers only the question it can answer:") + w("") + w("| evidence | role | may decide status? |") + w("|---|---|---|") + w("| STATUS_BOARD D-id row | deliverable status | **yes** |") + w("| ISSUES section | unresolved / resolved | **yes** |") + w("| TECH_DEBT section | implementation debt | **yes** (OPEN) |") + w("| the entry's own status line | only if its leading token is work-shaped | **yes** |") + w("| INTEGRATION_PLANS | integration ownership | no — context |") + w("| PR state | landing evidence | **no — MERGED ≠ CLOSED** |") + w("| live code citation | implementation reality | no |") + w("| `entries/`, `LATEST_STATE` mention | provenance | no |") + w("") + w(f"Conflicting decisive evidence ⇒ **AMBIGUOUS** ({a['conflict']} rows), never averaged") + w(f"into certainty. Absent decisive evidence ⇒ **AMBIGUOUS** ({a['no_decisive_but_joined']} joined rows +") + w(f"{a['no_join']} unjoinable). The *implementation* column carries landing and") + w("code-liveness facts precisely so they cannot be mistaken for closure.") + w("") + w("Three traps the tool encodes, each measured: STATUS_BOARD's status column") + w("is **per-table** (28 schemas, index 1..6, absent in two); a `Status:` line's") + w("**leading token only** is read; and cross-supersession needs **directional**") + w("phrasing, because a bare `⊘`-proximity rule read `caveat (⊘ in E-FOO-1)` —") + w("a sibling citing this entry's caveat — as the sibling superseding it.") + w("") + w("## 3. The rows") + w("") + + def outcome(r): + if r["status"] != "AMBIGUOUS": + return r["why"] + if r["why"].startswith("CONFLICT"): + return r["why"] + if not r["joined"]: + return f"no join key at all; graded {r['grade'] or '—'}" + return (f"graded {r['grade'] or '—'} — an epistemic grade, not a work status; " + "no deliverable attached") + + for st in ("OPEN", "CLOSED", "SUPERSEDED", "AMBIGUOUS"): + sel = sorted((r for r in rows if r["status"] == st), key=lambda r: (r["date"], r["eid"])) + w(f"### {st} ({len(sel)})") + w("") + w("| source id | status | implementation | outcome/open point |") + w("|---|---|---|---|") + for r in sel: + w(f"| `{r['eid']}` | {st} | {r['impl']} | {outcome(r)} |") + w("") + w("---") + w("") + w("## 4. What this baseline does NOT claim") + w("") + w(f"- It does not claim the {v.get('AMBIGUOUS', 0)} AMBIGUOUS rows are resolved, wrong, or safe") + w(" to delete. They are unadjudicated, and that is recorded, not hidden.") + w("- It does not claim a merged PR closed the finding attached to it.") + w("- It does not claim the frozen prose was reviewed. **FROZEN ≠ RECONCILED.**") + w("- It is not a licence to start another archaeology pass over the ambiguous") + w(" rows. If one matters later it resurfaces as live work and enters the") + w(" transient tier like anything else.") + w("") + w("## 5. Steady state after this checkpoint") + w("") + w("```") + w("new work → .claude/board/entries/ → reconcile against current state") + w(" → OPEN | CLOSED | SUPERSEDED | AMBIGUOUS") + w(" → rare Eureka promotion to EPIPHANIES.md (must cite its entry)") + w(" → advance PROCESSED_THROUGH_SHA to the captured source head") + w("```") + w("") + w("MIRROR dies. Corrections die. Failed probes normally die. Git keeps the") + w("route. Only surviving state crosses the checkpoint.") + w("") + return "\n".join(L) + + +def self_test(root: str) -> int: + """Falsifiers for the three measured traps, each proven to FIRE.""" + ok = True + did = did_pattern(root) + + # (a) the per-table status parser must not read a status from a table that + # has no status column -- the schema that returns prose as a status. + import tempfile + d = tempfile.mkdtemp(prefix="findings-baseline-selftest-") + b = pathlib.Path(d, ".claude/board") + b.mkdir(parents=True) + pathlib.Path(d, ".claude/tools").mkdir(parents=True) + (pathlib.Path(root, ".claude/tools/supersession_index.py")).read_text() + import shutil + shutil.copy(pathlib.Path(root, ".claude/tools/supersession_index.py"), + pathlib.Path(d, ".claude/tools/supersession_index.py")) + (b / "STATUS_BOARD.md").write_text( + "| D-id | correction |\n|---|---|\n| D-AAA | Shipped-looking prose |\n\n" + "| D-id | scope | status |\n|---|---|---|\n| D-BBB | s | Shipped |\n") + sb = status_board(d, did) + if "D-AAA" in sb: + print(" FAILED: read a status from a table with no status column") + ok = False + elif sb.get("D-BBB", [{}])[0].get("verdict") != "done": + print(f" FAILED: missed a real status ({sb})") + ok = False + else: + print(" per-table status column : prose ignored, real status read") + + # (b) an epistemic grade must NOT become a work status. + for grade, expect_own in (("FINDING", ""), ("RULING", ""), ("CORRECTION", ""), + ("SHIPPED", "done"), ("PROPOSAL", "open")): + body = f"## 2026-09-01 E-X-1\n\n**Status:** {grade} (measured, somewhere)\n" + m = OWN.search(body) + val = m.group(1).strip().lstrip("*").strip() + t = re.match(r"[A-Za-z⊘-]+", val) + g = t.group(0).upper() if t else "" + own = ("done" if g in WORK_DONE else "open" if g in WORK_OPEN else "") + if own != expect_own: + print(f" FAILED: grade {grade} -> own={own!r}, expected {expect_own!r}") + ok = False + print(" epistemic grade vs work status : FINDING/RULING/CORRECTION decide nothing") + + # (c) cross-supersession must be DIRECTIONAL: a citation of this entry's + # own caveat is not the sibling superseding it. + eid = "E-FOO-1" + q = re.escape(eid) + citing = "caveat (⊘ in `E-FOO-1`)" + real = "this ⊘ supersedes `E-FOO-1` outright" + if re.search(SUP_A % q, citing, re.I) or re.search(SUP_B % q, citing): + print(" FAILED: a citation was read as a supersession") + ok = False + elif not re.search(SUP_A % q, real, re.I): + print(" FAILED: a real supersession was missed") + ok = False + else: + print(" directional supersession : citation ignored, real one caught") + + print("findings-baseline --self-test " + ("PASSED" if ok else "FAILED")) + return 0 if ok else 1 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv[1:])) diff --git a/.github/workflows/supersession-index.yml b/.github/workflows/supersession-index.yml index 780ea7a49..a6cf067f7 100644 --- a/.github/workflows/supersession-index.yml +++ b/.github/workflows/supersession-index.yml @@ -32,6 +32,11 @@ on: # snippets in a README that nothing executed. - .claude/tools/entries_index.py - .claude/board/entries/README.md + # The findings watermark + the provenance gate. An EPIPHANIES addition + # after the baseline must cite the entry it was promoted from, so both + # the marker and the checker are inputs to that claim. + - .claude/tools/epiphany_provenance.py + - .claude/board/PROCESSED_THROUGH # `crates/` decides the "live" column (:27 globs it per symbol). Broad, # and deliberately so: a symbol deleted from the tree changes the table, # and the generator takes ~15 s, so the gate is cheap next to the Rust @@ -49,7 +54,16 @@ jobs: regenerate-and-diff: runs-on: ubuntu-latest steps: + # fetch-depth: 0 is REQUIRED by the provenance gate, not a convenience. + # `actions/checkout@v4` defaults to depth 1, and MEASURED: a depth-1 + # clone whose head is ahead of the baseline does not contain the + # baseline commit at all (`git rev-list --count HEAD` == 1). The gate + # fails CLOSED on an unreachable baseline -- correctly -- so with the + # default depth it would go red on every PR after the baseline landed, + # for want of history rather than for want of provenance. - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Regenerate and compare run: | python3 .claude/tools/supersession_index.py > /tmp/regen.md @@ -75,3 +89,13 @@ jobs: run: python3 .claude/tools/entries_index.py --check - name: Entries index generator self-test run: python3 .claude/tools/entries_index.py --self-test + # Provenance for anything promoted to EPIPHANIES.md since the findings + # baseline: the heading must name an entries/ file that EXISTS. Purely + # structural -- it proves the route, never that the content is a Eureka + # (that stays the closeout admission rule). Fails CLOSED if the baseline + # revision is unreachable in a shallow clone, because an invisible delta + # is not an empty one. + - name: Post-baseline epiphanies cite their originating entry + run: python3 .claude/tools/epiphany_provenance.py + - name: Provenance gate self-test + run: python3 .claude/tools/epiphany_provenance.py --self-test diff --git a/CLAUDE.md b/CLAUDE.md index 4b550d8f6..3f4e59ede 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -491,6 +491,36 @@ promoted by itself** — it is transient reflection and normally dies at closeou only a factual consequence of it (a real open implementation issue) becomes a row, and a `BIAS CHECK` line has no durable home at all. +**The checkpoint, and DELTA-ONLY closeout.** `.claude/board/FINDINGS-BASELINE-2026-09-20.md` +is the one historical catch-up over the 306 findings that went into the +`EPIPHANIES.md` monolith after the 2026-08-06 split — a **k-frame**. From it +forward, closeout consumes only the **delta**: read `PROCESSED_THROUGH_SHA` +from `.claude/board/PROCESSED_THROUGH`, reconcile +`PROCESSED_THROUGH_SHA..`, write the compact state, then +advance the marker to that captured head. **Routine work never censuses the +33,528-line monolith again.** + +The watermark is a **SHA, not a date** — imports, backdated headings, rebases +and concurrent work all make a calendar watermark lie, the same reason +`supersession_index.py` refuses git mtime as a signal. It names the CONSUMED +INPUT, never the commit that records it: a commit cannot contain its own hash. +If the SHA is unreachable (shallow clone), tooling FAILS CLOSED — an invisible +delta is not an empty one. + +**The historical prose is FROZEN, not reconciled.** Frozen means *not reread by +routine closeout*; 224 of the 306 rows were NOT adjudicated (mechanically +unjoinable, conflicting evidence, or — most of them — graded `FINDING` / +`RULING` / `CORRECTION`, an epistemic grade that answers *how well established* +rather than *is it done*). **FROZEN ≠ RECONCILED**, and the ambiguous rows are +not an invitation to another archaeology pass; if one matters later it resurfaces +as live work and enters the transient tier like anything else. + +A promotion to `EPIPHANIES.md` after the baseline must name the +`entries/YYYY-MM-DD-*.md` it came from — `epiphany_provenance.py` checks that +the reference RESOLVES, and nothing more. It proves the route; whether the +content is a Eureka stays the admission gate above, because a regex that judged +Eureka-ness would be a guard that fires on everything. + **No recursive post-mortems.** A correction does not entitle a post-mortem, and a corrected post-mortem does not entitle another — § Termination clause above is the same stopping rule one level down. A review earns a follow-up only for a From 3f1e90dc853257f83a0cc4c9b9b25ebe6722ee9e Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 15:53:27 +0000 Subject: [PATCH 16/19] =?UTF-8?q?board:=20reduction=20pass=20on=20the=20fi?= =?UTF-8?q?ndings=20k-frame=20=E2=80=94=20retire=20the=20one-shot=20instru?= =?UTF-8?q?ment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The k-frame exists, so the instrument that built it is no longer a capability this repo carries. Four reductions, no new behaviour. 1. DELETED .claude/tools/findings_baseline.py. Its docstring claimed future DELTA closeouts reuse the rubric, which its implementation does not support: it reads a hardcoded `WATERMARK = "2026-08-06"` over the whole monolith and never consumes `PROCESSED_THROUGH_SHA..HEAD` or changed `entries/*.md`; `baseline_sha()` only STAMPS the emitted header. Verified its sole reference was the baseline document's own "Regenerate" line — a self-referential consumer, not a real one. Git holds the exact instrument at 2374b1d if the measurement ever needs reproducing. The missing delta reconciler is deliberately NOT built: it should be written when a first real delta supplies a measured input population and the joins it actually needs, not speculatively now. 2. DELETED .claude/board/.pr-state-cache.json. Input to the one-time pass only; its sole reader was the deleted tool. PR state is landing evidence that never decides a finding's status and goes stale by construction. No replacement cache or ledger. The historical implementation column is already captured in the generated baseline. 3. REMOVED the numeric duplication from CLAUDE.md, which had already drifted inside one commit: the baseline says AMBIGUOUS 228, CLAUDE.md said 224. Not patched to 228 — de-duplicated. CLAUDE.md now states the stable rule ("most historical rows were NOT adjudicated; the generated baseline owns the exact counts") and "historical EPIPHANIES.md monolith" in place of the hardcoded 33,528. Stable semantics in guidance, measurements in the generated artifact. 4. REDUCED .claude/board/PROCESSED_THROUGH from 28 lines to 2. The procedure is defined once in CLAUDE.md; the marker is data. Dropped PROCESSED_THROUGH_DATE, measured to have zero readers. KEPT .claude/tools/epiphany_provenance.py: unlike the historical classifier it has a continuing consumer — CI structurally enforces work -> entries/ -> rare promotion -> EPIPHANIES — and makes no semantic Eureka judgement. Its fail-closed baseline behaviour is unchanged and verified against the reduced 2-line marker. The baseline document now says it is a FROZEN snapshot rather than offering a regenerate command, so nobody reaches for a tool that is gone. Gates after reduction: provenance + self-test, entries index --check + --self-test, supersession regenerate-and-diff, append-only (9 files, none shrank), plan-dids. EPIPHANIES.md byte-identical to 181bb2c at 33,528 lines. --- .claude/board/.pr-state-cache.json | 1 - .claude/board/FINDINGS-BASELINE-2026-09-20.md | 4 +- .claude/board/PROCESSED_THROUGH | 26 - .claude/tools/findings_baseline.py | 597 ------------------ CLAUDE.md | 11 +- 5 files changed, 9 insertions(+), 630 deletions(-) delete mode 100644 .claude/board/.pr-state-cache.json delete mode 100644 .claude/tools/findings_baseline.py diff --git a/.claude/board/.pr-state-cache.json b/.claude/board/.pr-state-cache.json deleted file mode 100644 index dbd429094..000000000 --- a/.claude/board/.pr-state-cache.json +++ /dev/null @@ -1 +0,0 @@ -{"1250": "merged", "1246": "merged", "1245": "merged", "1244": "merged", "1243": "merged", "1242": "merged", "1240": "merged", "1235": "merged", "1233": "merged", "1224": "closed", "1223": "merged", "1222": "merged", "1220": "merged", "1218": "merged", "1217": "merged", "1216": "merged", "1207": "merged", "1205": "merged", "1203": "merged", "1201": "merged", "1200": "merged", "1198": "merged", "1195": "merged", "1194": "merged", "1190": "merged", "1188": "merged", "1185": "merged", "1170": "merged", "1169": "merged", "1168": "merged", "1167": "merged", "1164": "closed", "1162": "closed", "1160": "merged", "1159": "merged", "1157": "merged", "1154": "merged", "1153": "merged", "1152": "merged", "1151": "merged", "1144": "merged", "1141": "merged", "1137": "merged", "1134": "merged", "1133": "merged", "1132": "merged", "1129": "merged", "1128": "merged", "1127": "merged", "1126": "merged", "1125": "merged", "1123": "merged", "1122": "merged", "1120": "merged", "1118": "merged", "1117": "merged", "1112": "merged", "1103": "merged", "1099": "merged", "1092": "merged", "1085": "merged", "1082": "merged", "1081": "merged", "1079": "merged", "1078": "merged", "1051": "merged", "1045": "merged", "1019": "merged", "1016": "merged", "1014": "merged", "1012": "merged", "1011": "merged", "1004": "merged", "1001": "merged", "998": "merged", "997": "merged", "996": "merged", "995": "merged", "992": "merged", "989": "merged", "984": "merged", "981": "merged", "975": "merged", "973": "closed", "971": "merged", "970": "merged", "968": "merged", "957": "merged", "950": "merged", "948": "merged", "945": "merged", "944": "merged", "941": "merged", "940": "merged", "938": "merged", "937": "merged", "936": "merged", "935": "merged", "932": "merged", "930": "merged", "928": "merged", "927": "merged", "926": "merged", "915": "merged", "913": "merged", "912": "merged", "911": "merged", "879": "merged", "876": "merged", "875": "merged", "844": "merged", "658": "merged", "596": "closed", "590": "merged", "565": "merged", "561": "merged", "498": "merged", "448": "merged", "446": "merged", "387": "merged", "350": "merged", "348": "merged", "310": "merged", "302": "merged", "298": "closed", "297": "closed", "296": "merged", "295": "merged", "294": "merged", "293": "merged", "291": "merged", "288": "merged", "277": "merged", "276": "merged", "275": "merged", "175": "merged", "174": "merged", "146": "merged", "104": "merged", "103": "merged"} \ No newline at end of file diff --git a/.claude/board/FINDINGS-BASELINE-2026-09-20.md b/.claude/board/FINDINGS-BASELINE-2026-09-20.md index dd04f3b9d..fe5a4a3cc 100644 --- a/.claude/board/FINDINGS-BASELINE-2026-09-20.md +++ b/.claude/board/FINDINGS-BASELINE-2026-09-20.md @@ -6,7 +6,9 @@ > routine closeout is DELTA ONLY and never censuses the monolith again. > Like `PLAN-INVENTORY-2026-09-07.md` it mints **no D-ids**, so > `supersession_index.py` and `plan_dids.py` do not see it — by design. -> Regenerate: `python3 .claude/tools/findings_baseline.py --emit `. +> A FROZEN snapshot, not a live artifact: the classifier that produced it +> was the instrument for this one historical pass and is retired. Git holds +> it at `2374b1d` if the measurement ever needs reproducing. > > **The historical prose is FROZEN, not reconciled away.** `EPIPHANIES.md` > is untouched: nothing was migrated, re-split, deleted or rewritten, and diff --git a/.claude/board/PROCESSED_THROUGH b/.claude/board/PROCESSED_THROUGH index 4ff996039..c9a3a1f8b 100644 --- a/.claude/board/PROCESSED_THROUGH +++ b/.claude/board/PROCESSED_THROUGH @@ -1,28 +1,2 @@ -# Findings watermark — machine-readable. ONE authoritative field. -# -# PROCESSED_THROUGH_SHA names the source revision whose findings have been -# CONSUMED into a baseline. It is NOT the SHA of the commit that carries this -# file: a commit cannot contain its own hash, because the file's bytes feed -# the hash. The commit that first recorded this value has a different SHA of -# its own, and that is correct. -# -# Incremental semantics, one step per closeout: -# -# 1. capture NEW_HEAD = git rev-parse HEAD (before generating anything) -# 2. consume the delta PROCESSED_THROUGH_SHA..NEW_HEAD -# 3. reconcile it -> OPEN | CLOSED | SUPERSEDED | AMBIGUOUS -# 4. write the compact state -# 5. set PROCESSED_THROUGH_SHA = NEW_HEAD -# -# Routine closeout reads the DELTA only. It never censuses the historical -# monolith again. If this SHA cannot be resolved (a shallow clone whose -# grafts cut above it), tooling MUST FAIL CLOSED with a diagnostic naming the -# revision — an unresolvable baseline is never an empty delta. -# -# The date is metadata for humans and is not load-bearing. If the two ever -# disagree, the SHA wins: imports, backdated headings, rebases and concurrent -# work all make a calendar watermark lie. - PROCESSED_THROUGH_SHA=181bb2c28005c185a967edd61367008c6722eb5c -PROCESSED_THROUGH_DATE=2026-09-20 BASELINE=.claude/board/FINDINGS-BASELINE-2026-09-20.md diff --git a/.claude/tools/findings_baseline.py b/.claude/tools/findings_baseline.py deleted file mode 100644 index 724374f7b..000000000 --- a/.claude/tools/findings_baseline.py +++ /dev/null @@ -1,597 +0,0 @@ -#!/usr/bin/env python3 -"""Reconcile EPIPHANIES.md findings into OPEN / CLOSED / SUPERSEDED / AMBIGUOUS. - - python3 .claude/tools/findings_baseline.py --report - python3 .claude/tools/findings_baseline.py --emit - python3 .claude/tools/findings_baseline.py --self-test - -WHY THIS IS A TOOL AND NOT A ONE-OFF SCRIPT -------------------------------------------- -It produced the numbers cited in `FINDINGS-BASELINE-2026-09-20.md`, and the -DELTA closeouts after that baseline need the SAME rubric. A rubric that lives -only in prose gets re-invented per session, each time slightly differently, -and then two passes disagree about what OPEN meant. - -WHAT IT REFUSES TO DO ---------------------- -It never reads prose to manufacture a status. Each join answers only the -question it can answer: - - STATUS_BOARD D-id row -> deliverable status DECISIVE - ISSUES section -> unresolved / resolved DECISIVE - TECH_DEBT section -> implementation debt DECISIVE (OPEN) - own status line -> only if work-shaped DECISIVE - PR state -> landing evidence NEVER decides - live code citation -> implementation reality NEVER decides - entries/ , LATEST_STATE-> provenance NEVER decides - -Conflicting decisive evidence -> AMBIGUOUS, never averaged into certainty. -Absent decisive evidence -> AMBIGUOUS. - -THREE MEASURED TRAPS THIS ENCODES ---------------------------------- -1. `STATUS_BOARD.md` carries 28 distinct header schemas with `status` at index - 1..6 and ABSENT in two, so the column is located from each table's own - header. Reading a fixed index returns prose as a status. -2. 303/306 entries carry a `Status:` line but 295 lead with an EPISTEMIC GRADE - (`FINDING` 204, `RULING` 31, `CORRECTION` 11, ...), which answers *how well - established is this claim*, not *is the work done*. Only a work-shaped - leading token is status evidence. -3. Cross-supersession needs DIRECTIONAL phrasing. A bare `⊘`-near-the-E-id - rule read `caveat (⊘ in E-FOO-1)` -- a sibling CITING this entry's own - caveat -- as the sibling superseding it. The relation is directional and - proximity inverted it. -""" - -import collections -import json -import os -import pathlib -import re -import subprocess -import sys - -WATERMARK = "2026-08-06" -EPI = ".claude/board/EPIPHANIES.md" -MARKER = ".claude/board/PROCESSED_THROUGH" - -DATE = re.compile(r"(20\d{2}-\d{2}-\d{2})") -EID = re.compile(r"\b(E-[A-Z0-9][A-Z0-9-]{3,})\b") -PR = re.compile(r"#(\d{3,5})\b") -CITE = re.compile(r"\b((?:crates|native|java|\.claude)/[A-Za-z0-9_./-]+\.(?:rs|md|py|toml|sh|yml))") -RESOLVED = re.compile(r"\b(RESOLVED|CLOSED|FIXED|LANDED|SHIPPED|DONE)\b") -DONE = re.compile(r"^\W*(shipped|done|complete|completed|landed|closed|merged|resolved|✅|✔)", re.I) -OPEN = re.compile(r"^\W*(queued|in progress|in-progress|in pr|blocked|open|todo|pending|next|planned|proposed|deferred|wip)", re.I) -OWN = re.compile(r"^\s*[>*\-\s]*\*{0,2}(?:Status|STATUS|Verdict|State)\*{0,2}\s*[:—-]\s*\*{0,2}(.{0,70})", re.M) -SUP_A = r"(?:supersedes|supersede|superseding|retires|retiring|replaces)\s+\S{0,40}?%s" -SUP_B = r"%s\S{0,8}[^\n]{0,80}?(?:is (?:now )?SUPERSEDED|SUPERSEDED by|is RETIRED|now RETIRED)" -WORK_DONE = ("SHIPPED", "CLOSED", "FIXED", "LANDED", "DONE", "RESOLVED", "COMPLETE") -WORK_OPEN = ("OPEN", "QUEUED", "BLOCKED", "PROPOSAL", "PENDING", "DEFERRED") - - -def did_pattern(root: str) -> "re.Pattern[str]": - """The D-id pattern, READ from the generator that owns it. - - A second copy would agree until one was edited, which is exactly when - nobody is comparing them -- the drift `plan_dids.py` refuses for the same - reason and by the same mechanism. - """ - src = pathlib.Path(root, ".claude/tools/supersession_index.py").read_text(errors="ignore") - m = re.search(r"^DID\s*=\s*re\.compile\(r'(.*)'\)\s*$", src, re.M) - if not m: - raise SystemExit( - "findings-baseline: the `DID = re.compile(r'...')` definition moved in " - "supersession_index.py. Fix this extractor; do not copy the pattern here." - ) - return re.compile(m.group(1)) - - -def population(root: str, watermark: str = WATERMARK) -> tuple[list[dict], dict]: - """Level-2 post-watermark headings carrying an E-id, plus the exclusions. - - A level-3 heading is a sub-section INSIDE an entry, so it must not - terminate a body and is not itself an entry; a dated level-2 heading with - no E-id is a date-group header. Both are counted, so the exclusion is - visible rather than asserted. - """ - lines = pathlib.Path(root, EPI).read_text(errors="ignore").split("\n") - heads = [(i, len(m.group(1)), m.group(2)) - for i, l in enumerate(lines) - if (m := re.match(r"^(#{2,3})\s+(.*)$", l))] - out, skipped = [], {"level3": 0, "no_eid": 0} - for idx, (i, lvl, text) in enumerate(heads): - d = DATE.search(text) - if not d or d.group(1) < watermark: - continue - if lvl == 3: - skipped["level3"] += 1 - continue - e = EID.search(text) - if not e: - skipped["no_eid"] += 1 - continue - end = len(lines) - for j, l2, _t in heads[idx + 1:]: - if l2 <= 2: - end = j - break - out.append({"eid": e.group(1), "date": d.group(1), "heading": text, - "line": i + 1, "body": "\n".join(lines[i:end])}) - return out, skipped - - -def status_board(root: str, did: "re.Pattern[str]") -> dict: - """D-id -> status rows, with the status column located PER TABLE.""" - rows, hdr = collections.defaultdict(list), None - for ln in pathlib.Path(root, ".claude/board/STATUS_BOARD.md").read_text(errors="ignore").split("\n"): - if not ln.startswith("|"): - continue - cells = [c.strip() for c in ln.rstrip().rstrip("|").split("|")[1:]] - low = [c.lower().strip("*").strip() for c in cells] - if low and low[0] in ("d-id", "id", "deliverable", "row", "item"): - hdr = low - continue - if re.match(r"^[-: |]+$", ln.strip()) or hdr is None or not cells: - continue - if not did.search(cells[0]) or "status" not in hdr: - # A schema with NO status column (`| D-id | correction |`) carries - # no status evidence. MEASURED: separating "on the board but - # statusless" as its own provenance key reaches 0 of 306 entries, - # so the distinction would be an inert branch -- and a guard that - # never fires carries as much information as one that always does. - continue - i = hdr.index("status") - if i >= len(cells): - continue - cell = cells[i] - v = "done" if DONE.match(cell) else "open" if OPEN.match(cell) else "other" - for d in did.findall(cells[0]): - rows[d].append({"status": cell[:72], "verdict": v}) - return rows - - -def sections(path: pathlib.Path) -> dict: - out, cur, buf = {}, None, [] - if not path.is_file(): - return out - for ln in path.read_text(errors="ignore").split("\n"): - if (m := re.match(r"^##\s+(.*)$", ln)): - if cur: - out[cur] = "\n".join(buf) - cur, buf = m.group(1), [ln] - elif cur: - buf.append(ln) - if cur: - out[cur] = "\n".join(buf) - return out - - -def named_in(secs: dict, eid: str) -> tuple[bool, bool]: - """(live, resolved). Resolution is asserted in the heading or the first two - lines -- a section that merely DISCUSSES a resolution is not resolved.""" - live = resolved = False - for head, body in secs.items(): - if eid not in body: - continue - top = head + "\n" + "\n".join(body.split("\n")[1:3]) - if RESOLVED.search(top): - resolved = True - else: - live = True - return live, resolved - - -def pr_states(root: str) -> dict: - """Cached PR number -> state, if a cache was left beside the marker. - - PR state is landing evidence only, so its ABSENCE never changes a verdict; - it only thins the implementation column. The tool therefore does not - require network access to reproduce a classification. - """ - p = pathlib.Path(root, ".claude/board/.pr-state-cache.json") - try: - return json.loads(p.read_text()) - except Exception: - return {} - - -def classify(root: str, watermark: str = WATERMARK) -> tuple[list[dict], dict]: - did = did_pattern(root) - entries, skipped = population(root, watermark) - sb = status_board(root, did) - iss = sections(pathlib.Path(root, ".claude/board/ISSUES.md")) - td = sections(pathlib.Path(root, ".claude/board/TECH_DEBT.md")) - prs = pr_states(root) - - board = {} - for name, rel in (("status_board", ".claude/board/STATUS_BOARD.md"), - ("tech_debt", ".claude/board/TECH_DEBT.md"), - ("integration_plans", ".claude/board/INTEGRATION_PLANS.md"), - ("issues", ".claude/board/ISSUES.md"), - ("latest_state", ".claude/board/LATEST_STATE.md"), - ("supersession", ".claude/board/SUPERSESSION-INDEX.md")): - f = pathlib.Path(root, rel) - if f.is_file(): - board[name] = f.read_text(errors="ignore") - ed = pathlib.Path(root, ".claude/board/entries") - board["entries"] = "\n".join( - (ed / f).read_text(errors="ignore") - for f in sorted(os.listdir(ed)) if f.endswith(".md") and f != "README.md" - ) if ed.is_dir() else "" - - alltext = "\n".join(e["body"] for e in entries) - rows = [] - for e in entries: - eid, body = e["eid"], e["body"] - dids = sorted(set(did.findall(body))) - prnums = sorted({int(p) for p in PR.findall(body)}) - cites = sorted(set(CITE.findall(body))) - - keys = {} - if (direct := [k for k, t in board.items() if eid in t]): - keys["eid_board"] = direct - if (known := [d for d in dids if d in sb]): - keys["did_statusboard"] = known - if dids and not known: - keys["did_unknown"] = dids - if prnums: - keys["pr"] = prnums - live_cites = [c for c in cites if pathlib.Path(root, c).exists()] - dead_cites = [c for c in cites if not pathlib.Path(root, c).exists()] - if live_cites: - keys["cite_live"] = live_cites - if dead_cites: - keys["cite_dead"] = dead_cites - - grade, own = "", "" - if (m := OWN.search(body)): - val = m.group(1).strip().lstrip("*").strip() - t = re.match(r"[A-Za-z⊘-]+", val) - grade = t.group(0).upper() if t else "" - if val.startswith("⊘"): - own = "sup" - elif grade in WORK_DONE: - own = "done" - elif grade in WORK_OPEN: - own = "open" - - self_sup = bool(re.search(r"\b(SUPERSEDED|RETIRED|WITHDRAWN|REJECTED-BY-FALSIFIER)\b", - e["heading"])) or own == "sup" - others = alltext.replace(body, "", 1) - q = re.escape(eid) - cross_sup = bool(re.search(SUP_A % q, others, re.I) or re.search(SUP_B % q, others)) - - verdicts = {r["verdict"] for d in known for r in sb[d]} - iss_live, iss_res = named_in(iss, eid) - td_live, td_res = named_in(td, eid) - open_ev, done_ev = [], [] - if "open" in verdicts: - open_ev.append("STATUS_BOARD row not done") - if "done" in verdicts: - done_ev.append("STATUS_BOARD row done") - if iss_live: - open_ev.append("live ISSUES entry") - if iss_res: - done_ev.append("ISSUES entry resolved") - if td_live: - open_ev.append("live TECH_DEBT entry") - if td_res: - done_ev.append("TECH_DEBT entry resolved") - if own == "done": - done_ev.append(f"own status line: {grade}") - if own == "open": - open_ev.append(f"own status line: {grade}") - - merged = [p for p in prnums if prs.get(str(p)) == "merged"] - unmerged = [p for p in prnums if prs.get(str(p)) == "closed"] - impl = [] - if merged: - impl.append("PR " + ", ".join(f"#{p}" for p in merged[:3]) - + (f" +{len(merged) - 3}" if len(merged) > 3 else "") + " merged") - if unmerged: - impl.append(f"{len(unmerged)} referenced PR(s) closed unmerged") - if not merged and not unmerged and prnums: - impl.append(f"{len(prnums)} PR ref(s), state not cached") - if live_cites: - impl.append(f"{len(live_cites)} cited path(s) live") - if dead_cites: - impl.append(f"{len(dead_cites)} cited path(s) GONE") - if not impl: - impl.append("no implementation evidence") - - if self_sup or cross_sup: - status = "SUPERSEDED" - why = ["own heading/status ⊘ note" if self_sup - else "superseded by a sibling entry"] - elif open_ev and done_ev: - status = "AMBIGUOUS" - why = ["CONFLICT: " + " + ".join(open_ev) + " vs " + " + ".join(done_ev)] - elif open_ev: - status, why = "OPEN", open_ev - elif done_ev: - status, why = "CLOSED", done_ev - else: - status = "AMBIGUOUS" - why = ["no decisive status evidence" + ("" if keys else " and no join key at all")] - - rows.append({"eid": eid, "date": e["date"], "status": status, "grade": grade, - "impl": "; ".join(impl), "why": "; ".join(why), - "keys": sorted(keys), "joined": bool(keys)}) - - usable = ("eid_board", "did_statusboard", "pr", "cite_live") - stats = { - "population": len(rows), - "excluded": skipped, - "verdicts": dict(collections.Counter(r["status"] for r in rows)), - "grades": dict(collections.Counter(r["grade"] for r in rows if r["grade"])), - "joined": sum(1 for r in rows if any(k in r["keys"] for k in usable)), - "nojoin": sum(1 for r in rows if not r["joined"]), - "key_reach": {k: sum(1 for r in rows if k in r["keys"]) - for k in (*usable, "did_unknown", "cite_dead")}, - } - amb = [r for r in rows if r["status"] == "AMBIGUOUS"] - stats["ambiguous"] = { - "conflict": sum(1 for r in amb if r["why"].startswith("CONFLICT")), - "no_decisive_but_joined": sum(1 for r in amb - if not r["why"].startswith("CONFLICT") and r["joined"]), - "no_join": sum(1 for r in amb if not r["joined"]), - } - return rows, stats - - -def baseline_sha(root: str) -> str: - p = pathlib.Path(root, MARKER) - if p.is_file(): - for line in p.read_text(errors="ignore").splitlines(): - if line.startswith("PROCESSED_THROUGH_SHA="): - return line.split("=", 1)[1].strip() - return "" - - -def main(argv: list[str]) -> int: - root = subprocess.run(["git", "rev-parse", "--show-toplevel"], - capture_output=True, text=True).stdout.strip() or "." - if "--self-test" in argv: - return self_test(root) - rows, stats = classify(root) - if "--emit" in argv: - out = argv[argv.index("--emit") + 1] - pathlib.Path(out).write_text(render(rows, stats, baseline_sha(root))) - print(f"wrote {out}: {len(rows)} rows") - return 0 - print(json.dumps(stats, indent=1)) - return 0 - - -def render(rows: list[dict], stats: dict, sha: str) -> str: - """The committed baseline document. Every number is interpolated from - `stats`, so the prose and the table cannot disagree -- and a hand-edit to - 'correct' a count is never the right move.""" - v, a, kr = stats["verdicts"], stats["ambiguous"], stats["key_reach"] - n = stats["population"] - L = [f"# Findings baseline — {sha[:12] or 'unpinned'} (`EPIPHANIES.md`, post-{WATERMARK} entries)", ""] - w = L.append - w("> **What this is.** The ONE historical catch-up over the findings that went") - w("> into the `EPIPHANIES.md` monolith after the 2026-08-06 split watermark.") - w("> It is a consolidated current-state checkpoint — a **k-frame**. After it,") - w("> routine closeout is DELTA ONLY and never censuses the monolith again.") - w("> Like `PLAN-INVENTORY-2026-09-07.md` it mints **no D-ids**, so") - w("> `supersession_index.py` and `plan_dids.py` do not see it — by design.") - w("> Regenerate: `python3 .claude/tools/findings_baseline.py --emit `.") - w(">") - w("> **The historical prose is FROZEN, not reconciled away.** `EPIPHANIES.md`") - w("> is untouched: nothing was migrated, re-split, deleted or rewritten, and") - w("> no entry files were created for these findings. Frozen means *not reread") - w(f"> by routine closeout*; it does NOT mean adjudicated — {v.get('AMBIGUOUS', 0)} of {n} were not.") - w(">") - w(f"> **PROCESSED_THROUGH_SHA = `{sha}`** — every eligible finding visible") - w("> through that source revision is consumed into this baseline. The marker") - w("> names the CONSUMED INPUT, never this file's own commit: a commit cannot") - w("> contain its own hash. Machine-readable: `.claude/board/PROCESSED_THROUGH`.") - w("") - w("---") - w("") - w("## 0. The numbers") - w("") - w("| | count |") - w("|---|---|") - w(f"| population (level-2 post-watermark entries with an E-id) | **{n}** |") - for k in ("OPEN", "CLOSED", "SUPERSEDED", "AMBIGUOUS"): - w(f"| {k} | {v.get(k, 0)} |") - w("") - ex = stats["excluded"] - w(f"Excluded and counted so the exclusion is visible, not asserted: **{ex['no_eid']}**") - w(f"level-2 bare date-group headers (no E-id) and **{ex['level3']}** level-3") - w(f"sub-headings (sections *inside* an entry). {n} + {ex['no_eid']} + {ex['level3']} =") - w(f"{n + ex['no_eid'] + ex['level3']} dated headings at or after the watermark.") - w("") - w("### Mechanical reachability — the union of join keys") - w("") - w("A first estimate put the ceiling at 198 by taking `306 − 108 without a D-id") - w("or PR`. That was wrong: the E-id → board joins are **independent keys** and") - w("most of them land inside that 108.") - w("") - w("| join key | entries | answers |") - w("|---|---|---|") - for k, q in (("eid_board", "named on a board surface — provenance"), - ("did_statusboard", "a referenced D-id has a STATUS_BOARD row — deliverable status"), - ("pr", "a PR is referenced — landing evidence ONLY"), - ("cite_live", "a cited path still exists — implementation reality"), - ("did_unknown", "referenced D-id has NO status-bearing board row — dangling"), - ("cite_dead", "cited path is GONE — stale citation")): - w(f"| `{k}` | {kr.get(k, 0)} | {q} |") - w("") - w(f"**{stats['joined']}** entries carry ≥ 1 usable key; **{stats['nojoin']}** carry none and are") - w(f"therefore automatically AMBIGUOUS. The other {v.get('AMBIGUOUS', 0) - a['no_join']} ambiguous rows are") - w("ambiguous for a different and more interesting reason — §1.") - w("") - w("## 1. Why AMBIGUOUS is the largest bucket") - w("") - gr = stats["grades"] - tot = sum(gr.values()) - workish = sum(c for g, c in gr.items() if g in WORK_DONE + WORK_OPEN) - w(f"**{tot} of the {n} entries carry their own `Status:` line, and {tot - workish} of those lead") - w("with an EPISTEMIC GRADE rather than a work status:**") - w("") - w("| leading token | entries |") - w("|---|---|") - for k, c in sorted(gr.items(), key=lambda kv: -kv[1])[:10]: - w(f"| `{k}` | {c} |") - w("") - w("`FINDING`, `RULING`, `CORRECTION`, `MEASURED` answer *how well established") - w(f"is this claim*. They do not answer *is the work done*. Only **{workish}** entries") - w("lead with a work-shaped token.") - w("") - w("That is the substantive result: **post-watermark `EPIPHANIES.md` was being") - w("used as a findings log, not a deliverable tracker.** For most rows") - w("OPEN/CLOSED is the wrong axis — the live question is *is this still true?*,") - w("which no join answers mechanically. Reading their prose to manufacture a") - w("status is what this pass was told not to do, so they stay AMBIGUOUS with") - w("their grade recorded.") - w("") - w("Not a comparable number: `PLAN-INVENTORY-2026-09-07.md` reached 40/211") - w("ambiguous **with a human read of every status line in context**, and records") - w("that naive substring matching produced ≥ 6 false positives in its corpus.") - w("This pass is mechanical-only by instruction; the larger residue is the price") - w("of that, not a worse measurement.") - w("") - w("## 2. How to read a verdict") - w("") - w("Vocabulary reused from `PLAN-INVENTORY`; nothing new minted. Each join") - w("answers only the question it can answer:") - w("") - w("| evidence | role | may decide status? |") - w("|---|---|---|") - w("| STATUS_BOARD D-id row | deliverable status | **yes** |") - w("| ISSUES section | unresolved / resolved | **yes** |") - w("| TECH_DEBT section | implementation debt | **yes** (OPEN) |") - w("| the entry's own status line | only if its leading token is work-shaped | **yes** |") - w("| INTEGRATION_PLANS | integration ownership | no — context |") - w("| PR state | landing evidence | **no — MERGED ≠ CLOSED** |") - w("| live code citation | implementation reality | no |") - w("| `entries/`, `LATEST_STATE` mention | provenance | no |") - w("") - w(f"Conflicting decisive evidence ⇒ **AMBIGUOUS** ({a['conflict']} rows), never averaged") - w(f"into certainty. Absent decisive evidence ⇒ **AMBIGUOUS** ({a['no_decisive_but_joined']} joined rows +") - w(f"{a['no_join']} unjoinable). The *implementation* column carries landing and") - w("code-liveness facts precisely so they cannot be mistaken for closure.") - w("") - w("Three traps the tool encodes, each measured: STATUS_BOARD's status column") - w("is **per-table** (28 schemas, index 1..6, absent in two); a `Status:` line's") - w("**leading token only** is read; and cross-supersession needs **directional**") - w("phrasing, because a bare `⊘`-proximity rule read `caveat (⊘ in E-FOO-1)` —") - w("a sibling citing this entry's caveat — as the sibling superseding it.") - w("") - w("## 3. The rows") - w("") - - def outcome(r): - if r["status"] != "AMBIGUOUS": - return r["why"] - if r["why"].startswith("CONFLICT"): - return r["why"] - if not r["joined"]: - return f"no join key at all; graded {r['grade'] or '—'}" - return (f"graded {r['grade'] or '—'} — an epistemic grade, not a work status; " - "no deliverable attached") - - for st in ("OPEN", "CLOSED", "SUPERSEDED", "AMBIGUOUS"): - sel = sorted((r for r in rows if r["status"] == st), key=lambda r: (r["date"], r["eid"])) - w(f"### {st} ({len(sel)})") - w("") - w("| source id | status | implementation | outcome/open point |") - w("|---|---|---|---|") - for r in sel: - w(f"| `{r['eid']}` | {st} | {r['impl']} | {outcome(r)} |") - w("") - w("---") - w("") - w("## 4. What this baseline does NOT claim") - w("") - w(f"- It does not claim the {v.get('AMBIGUOUS', 0)} AMBIGUOUS rows are resolved, wrong, or safe") - w(" to delete. They are unadjudicated, and that is recorded, not hidden.") - w("- It does not claim a merged PR closed the finding attached to it.") - w("- It does not claim the frozen prose was reviewed. **FROZEN ≠ RECONCILED.**") - w("- It is not a licence to start another archaeology pass over the ambiguous") - w(" rows. If one matters later it resurfaces as live work and enters the") - w(" transient tier like anything else.") - w("") - w("## 5. Steady state after this checkpoint") - w("") - w("```") - w("new work → .claude/board/entries/ → reconcile against current state") - w(" → OPEN | CLOSED | SUPERSEDED | AMBIGUOUS") - w(" → rare Eureka promotion to EPIPHANIES.md (must cite its entry)") - w(" → advance PROCESSED_THROUGH_SHA to the captured source head") - w("```") - w("") - w("MIRROR dies. Corrections die. Failed probes normally die. Git keeps the") - w("route. Only surviving state crosses the checkpoint.") - w("") - return "\n".join(L) - - -def self_test(root: str) -> int: - """Falsifiers for the three measured traps, each proven to FIRE.""" - ok = True - did = did_pattern(root) - - # (a) the per-table status parser must not read a status from a table that - # has no status column -- the schema that returns prose as a status. - import tempfile - d = tempfile.mkdtemp(prefix="findings-baseline-selftest-") - b = pathlib.Path(d, ".claude/board") - b.mkdir(parents=True) - pathlib.Path(d, ".claude/tools").mkdir(parents=True) - (pathlib.Path(root, ".claude/tools/supersession_index.py")).read_text() - import shutil - shutil.copy(pathlib.Path(root, ".claude/tools/supersession_index.py"), - pathlib.Path(d, ".claude/tools/supersession_index.py")) - (b / "STATUS_BOARD.md").write_text( - "| D-id | correction |\n|---|---|\n| D-AAA | Shipped-looking prose |\n\n" - "| D-id | scope | status |\n|---|---|---|\n| D-BBB | s | Shipped |\n") - sb = status_board(d, did) - if "D-AAA" in sb: - print(" FAILED: read a status from a table with no status column") - ok = False - elif sb.get("D-BBB", [{}])[0].get("verdict") != "done": - print(f" FAILED: missed a real status ({sb})") - ok = False - else: - print(" per-table status column : prose ignored, real status read") - - # (b) an epistemic grade must NOT become a work status. - for grade, expect_own in (("FINDING", ""), ("RULING", ""), ("CORRECTION", ""), - ("SHIPPED", "done"), ("PROPOSAL", "open")): - body = f"## 2026-09-01 E-X-1\n\n**Status:** {grade} (measured, somewhere)\n" - m = OWN.search(body) - val = m.group(1).strip().lstrip("*").strip() - t = re.match(r"[A-Za-z⊘-]+", val) - g = t.group(0).upper() if t else "" - own = ("done" if g in WORK_DONE else "open" if g in WORK_OPEN else "") - if own != expect_own: - print(f" FAILED: grade {grade} -> own={own!r}, expected {expect_own!r}") - ok = False - print(" epistemic grade vs work status : FINDING/RULING/CORRECTION decide nothing") - - # (c) cross-supersession must be DIRECTIONAL: a citation of this entry's - # own caveat is not the sibling superseding it. - eid = "E-FOO-1" - q = re.escape(eid) - citing = "caveat (⊘ in `E-FOO-1`)" - real = "this ⊘ supersedes `E-FOO-1` outright" - if re.search(SUP_A % q, citing, re.I) or re.search(SUP_B % q, citing): - print(" FAILED: a citation was read as a supersession") - ok = False - elif not re.search(SUP_A % q, real, re.I): - print(" FAILED: a real supersession was missed") - ok = False - else: - print(" directional supersession : citation ignored, real one caught") - - print("findings-baseline --self-test " + ("PASSED" if ok else "FAILED")) - return 0 if ok else 1 - - -if __name__ == "__main__": - raise SystemExit(main(sys.argv[1:])) diff --git a/CLAUDE.md b/CLAUDE.md index 3f4e59ede..62357376d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -498,7 +498,7 @@ forward, closeout consumes only the **delta**: read `PROCESSED_THROUGH_SHA` from `.claude/board/PROCESSED_THROUGH`, reconcile `PROCESSED_THROUGH_SHA..`, write the compact state, then advance the marker to that captured head. **Routine work never censuses the -33,528-line monolith again.** +historical `EPIPHANIES.md` monolith again.** The watermark is a **SHA, not a date** — imports, backdated headings, rebases and concurrent work all make a calendar watermark lie, the same reason @@ -508,10 +508,11 @@ If the SHA is unreachable (shallow clone), tooling FAILS CLOSED — an invisible delta is not an empty one. **The historical prose is FROZEN, not reconciled.** Frozen means *not reread by -routine closeout*; 224 of the 306 rows were NOT adjudicated (mechanically -unjoinable, conflicting evidence, or — most of them — graded `FINDING` / -`RULING` / `CORRECTION`, an epistemic grade that answers *how well established* -rather than *is it done*). **FROZEN ≠ RECONCILED**, and the ambiguous rows are +routine closeout*. **Most historical rows were NOT adjudicated** — mechanically +unjoinable, conflicting evidence, or, most of them, graded `FINDING` / `RULING` +/ `CORRECTION`, an epistemic grade answering *how well established* rather than +*is it done*. The generated baseline owns the exact counts; they are not +restated here. **FROZEN ≠ RECONCILED**, and the ambiguous rows are not an invitation to another archaeology pass; if one matters later it resurfaces as live work and enters the transient tier like anything else. From e0cbaef27259fb4bc2d1471953565054e6fa3070 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 16:13:01 +0000 Subject: [PATCH 17/19] board: close two review findings on the provenance gate and the deny hook Both were reproduced before being fixed, and both were invisible to the existing suites for the same reason: each pre-existing case carried ONE violating input, and both defects need two. 1. anti-pattern-matching.sh emitted a deny per violating edit. A hook's stdout must be exactly one response document; two violating edits in one MultiEdit batch wrote two, and a concatenated pair parses as neither denial. emit_deny is now terminal by construction rather than by call-site discipline, so the next branch that loops cannot reintroduce it. New row asserts the document COUNT, not merely that a denial appeared. 2. epiphany_provenance.py read PROCESSED_THROUGH from the checkout, so a branch that ADVANCED the marker erased its own delta. Measured with two ordinary commits: C1 adds an uncited heading (gate fires); C2 advances the marker to C1, and `git diff C1..HEAD` no longer contains C1's own change, so the gate reports 0 added / 0 violations and the uncited heading ships. The marker is now read as the branch INHERITED it, at merge-base(HEAD, origin/main) -- the mechanism append_only_gate.py already uses and documents for the same class of problem. Absence at the merge-base is the introducing PR's own case and falls back to the checkout, printed so the weaker reference is never silent. The self-test gained the bypass arm and an assertion that the merge-base reference is the one actually exercised; the unreachable-baseline arm now writes the bad SHA to both references so neither path can quietly supply a good baseline and make it vacuous. Gates: provenance gate + 5-arm self-test, hook suite ALL PASSED, entries_index --check/--self-test, append_only_gate (9 files, none shrank), plan_dids, supersession index regenerate-and-diff clean. EPIPHANIES.md byte-identical to 181bb2c at 33,528 lines. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/hooks/anti-pattern-matching.sh | 7 ++ .../hooks/tests/anti-pattern-matching.test.sh | 28 +++++ .claude/tools/epiphany_provenance.py | 114 ++++++++++++++---- 3 files changed, 128 insertions(+), 21 deletions(-) diff --git a/.claude/hooks/anti-pattern-matching.sh b/.claude/hooks/anti-pattern-matching.sh index db2b2fb7e..f1e49c1a4 100755 --- a/.claude/hooks/anti-pattern-matching.sh +++ b/.claude/hooks/anti-pattern-matching.sh @@ -79,9 +79,16 @@ SLICE_DENY='VERBOTEN (FIRST-HAND SOURCE LAW, Regel 3): sed/head/tail/awk auf ein # `| head` hides it. CAP_DENY='VERBOTEN (FIRST-HAND SOURCE LAW, Regel 9): eine SUCHE in head/tail/sed/awk pipen. Das kappt eine Beweismenge und laesst ein abgeschnittenes Ergebnis wie ein vollstaendiges aussehen -- genau die Form hinter jeder "kein Consumer"-Behauptung in der Korrekturgeschichte dieses Repos. Stattdessen: das Grep-Tool mit `head_limit` (das die Kappung MELDET), oder ungekappt suchen und den Suchraum benennen. Gesetz: .claude/knowledge/FIRST-HAND-SOURCE-LAW.md' +# A deny is TERMINAL, by construction rather than by call-site discipline. +# The hook's stdout must be exactly ONE hook response; the MultiEdit branch +# below loops over a batch, so without the exit a second violating edit wrote a +# second JSON document and the pair parsed as neither denial (CodeRabbit on +# #1255, reproduced before fixing). Exiting inside the function is what stops +# the next branch that loops from re-introducing it. emit_deny() { jq -n --arg c "$1" \ '{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: $c}}' + exit 0 } # Source/config extensions only. Scratch and temp outputs are not source, so diff --git a/.claude/hooks/tests/anti-pattern-matching.test.sh b/.claude/hooks/tests/anti-pattern-matching.test.sh index 23734bf11..209805b66 100755 --- a/.claude/hooks/tests/anti-pattern-matching.test.sh +++ b/.claude/hooks/tests/anti-pattern-matching.test.sh @@ -132,6 +132,34 @@ echo '### ALLOW -- not canonical prose/source' edit DENY x.md "was operator-ruled." "was operator-ruled. New: operator-pinned too." "a label ADDED beside an existing one is still an introduction" multiedit DENY x.md "b" "b operator-locked" "MultiEdit introducing a label" multiedit SILENT x.md "b" "b tidied" "MultiEdit with no label" + +# A hook's stdout must be exactly ONE response document. Two violating edits in +# one batch used to emit TWO, and a concatenated pair parses as neither denial +# (CodeRabbit on #1255). This asserts the COUNT, not merely that a denial +# appeared -- the pre-existing rows above could not see the defect, because they +# carry one violating edit each. Disable-verified: removing `exit 0` from +# emit_deny makes this row report docs=2. +multiedit_two_violations() { + local got + got="$(printf '%s' '{"tool_name":"MultiEdit","tool_input":{"file_path":"x.md","edits":[{"old_string":"a","new_string":"a operator-ruled"},{"old_string":"b","new_string":"b operator-pinned"}]}}' \ + | bash "$HOOK" | python3 -c ' +import json, sys +dec = json.JSONDecoder() +raw, i, docs, denies = sys.stdin.read(), 0, 0, 0 +while i < len(raw): + while i < len(raw) and raw[i].isspace(): + i += 1 + if i >= len(raw): + break + o, i = dec.raw_decode(raw, i) + docs += 1 + if o["hookSpecificOutput"].get("permissionDecision") == "deny": + denies += 1 +print(f"docs={docs} denies={denies}")')" + if [ "$got" = "docs=1 denies=1" ]; then printf ' ok %-7s %s\n' "$got" "two violating edits -> ONE deny document" + else printf ' FAIL want=docs=1 denies=1 got=%s %s\n' "$got" "two violating edits -> ONE deny document"; fails=$((fails + 1)); fi +} +multiedit_two_violations write SILENT c.json '{"k":"operator-ruled"}' "json is out of scope" echo '### DENY -- review findings on #1254, each reproduced before it was fixed' diff --git a/.claude/tools/epiphany_provenance.py b/.claude/tools/epiphany_provenance.py index 08cc0adb4..db31beda4 100644 --- a/.claude/tools/epiphany_provenance.py +++ b/.claude/tools/epiphany_provenance.py @@ -24,6 +24,22 @@ a signal for the same reason ("2026-07-24 is a bulk import ... git dates the import, not the work"). The SHA names a revision, so the delta is exact. +WHY THE MARKER IS READ AT THE MERGE-BASE, NOT FROM THE CHECKOUT +--------------------------------------------------------------- +A branch that ADVANCES the marker would otherwise erase its own delta. +MEASURED (two ordinary commits, reproduced before this was fixed): C1 adds an +uncited heading — the gate fires; C2 advances `PROCESSED_THROUGH_SHA` to C1 — +`git diff C1..HEAD` no longer contains C1's own change, so the gate reports +`0 added, 0 violations` and the uncited heading ships. Reading the marker as +the branch INHERITED it closes that: the delta is measured from the baseline +main had, which no commit on the branch can move. This is the mechanism +`append_only_gate.py` already uses and documents for the same class of +problem ("a straight `git show :` would compare against work the +branch never saw"). + +The marker not existing at the merge-base is the introducing PR's own case and +falls back to the checkout, printed so the weaker reference is never silent. + FAIL CLOSED ON A SHALLOW CLONE ------------------------------ This repo is routinely a shallow clone (`.git/shallow`, 6 grafts). If the @@ -40,6 +56,7 @@ import sys MARKER = ".claude/board/PROCESSED_THROUGH" +DEFAULT_BASE = "origin/main" EPI = ".claude/board/EPIPHANIES.md" ENTRY_REF = re.compile(r"entries/(\d{4}-\d{2}-\d{2}-[A-Za-z0-9._-]+\.md)") HEAD2 = re.compile(r"^##\s+(?!#)(.*)$") @@ -50,18 +67,42 @@ def run(args, cwd): return subprocess.run(args, cwd=cwd, capture_output=True, text=True) -def baseline_sha(root: str) -> str: - """The consumed-input revision. Never this commit's own hash.""" +def parse_marker(text: str, where: str) -> str: + for line in text.splitlines(): + if line.startswith("PROCESSED_THROUGH_SHA="): + sha = line.split("=", 1)[1].strip() + if sha: + return sha + raise SystemExit( + f"epiphany-provenance: empty PROCESSED_THROUGH_SHA= in {where}" + ) + raise SystemExit(f"epiphany-provenance: no PROCESSED_THROUGH_SHA= line in {where}") + + +def baseline_sha(root: str, base_ref: str = DEFAULT_BASE) -> tuple[str, str]: + """-> (consumed-input revision, where it was read). + + Read as the branch INHERITED it, not from the checkout — see the module + docs: a commit that advances the marker would otherwise erase its own + delta. Falls back to the checkout only when the marker does not exist at + the merge-base, and the caller prints which reference was used. + """ + mb = run(["git", "merge-base", "HEAD", base_ref], root) + if mb.returncode == 0 and mb.stdout.strip(): + base = mb.stdout.strip() + show = run(["git", "show", f"{base}:{MARKER}"], root) + if show.returncode == 0: + return parse_marker(show.stdout, f"{MARKER} at {base[:12]}"), \ + f"inherited at merge-base {base[:12]} with {base_ref}" + p = pathlib.Path(root, MARKER) if not p.is_file(): raise SystemExit( f"epiphany-provenance: {MARKER} is missing. The gate cannot define a " "delta without a baseline; add the marker rather than disabling this." ) - for line in p.read_text(errors="ignore").splitlines(): - if line.startswith("PROCESSED_THROUGH_SHA="): - return line.split("=", 1)[1].strip() - raise SystemExit(f"epiphany-provenance: no PROCESSED_THROUGH_SHA= line in {MARKER}") + return parse_marker(p.read_text(errors="ignore"), MARKER), \ + f"the CHECKOUT ({MARKER} absent at the merge-base with {base_ref})" def added_headings(root: str, sha: str) -> list[str]: @@ -112,9 +153,9 @@ def body_of(text: str, heading: str) -> str: return "\n".join(lines[start:end]) -def check(root: str) -> tuple[list[tuple[str, str]], int]: - """-> (violations, number of added headings examined).""" - sha = baseline_sha(root) +def check(root: str, base_ref: str = DEFAULT_BASE) -> tuple[list[tuple[str, str]], int, str, str]: + """-> (violations, added headings examined, baseline sha, its provenance).""" + sha, whence = baseline_sha(root, base_ref) heads = added_headings(root, sha) text = pathlib.Path(root, EPI).read_text(errors="ignore") bad = [] @@ -126,15 +167,15 @@ def check(root: str) -> tuple[list[tuple[str, str]], int]: bad.append((h, "no entries/ reference")) elif not live: bad.append((h, f"references a file that does not exist: {', '.join(refs[:3])}")) - return bad, len(heads) + return bad, len(heads), sha, whence def main(argv: list[str]) -> int: root = run(["git", "rev-parse", "--show-toplevel"], ".").stdout.strip() or "." if "--self-test" in argv: return self_test() - bad, n = check(root) - print(f"epiphany-provenance: baseline {baseline_sha(root)[:12]}, " + bad, n, sha, whence = check(root) + print(f"epiphany-provenance: baseline {sha[:12]} ({whence}), " f"{n} level-2 heading(s) added since it, {len(bad)} without provenance") if not bad: return 0 @@ -162,19 +203,33 @@ def self_test() -> int: epi = pathlib.Path(d, EPI) epi.write_text("# Epiphanies\n\n## 2026-01-01 E-BASE-1 — pre-baseline\n\nbody\n") (ent / "2026-09-20-e-real-1.md").write_text("# entry\n") - for a in (["init", "-q"], ["add", "-A"], - ["-c", "user.email=t@t", "-c", "user.name=t", "commit", "-qm", "base"]): - run(["git", *a], d) - sha = run(["git", "rev-parse", "HEAD"], d).stdout.strip() + + def commit(label: str): + run(["git", "add", "-A"], d) + run(["git", "-c", "user.email=t@t", "-c", "user.name=t", + "commit", "-qm", label], d) + return run(["git", "rev-parse", "HEAD"], d).stdout.strip() + + run(["git", "init", "-q"], d) + sha = commit("base") + # The marker is COMMITTED, and a `main` branch is left pointing at it, so + # the merge-base reference the gate actually reads is exercised here rather + # than only the checkout fallback. pathlib.Path(d, MARKER).write_text(f"PROCESSED_THROUGH_SHA={sha}\n") + commit("marker") + run(["git", "branch", "-f", "main"], d) def commit_and_check(extra: str, label: str): epi.write_text(epi.read_text() + extra) - run(["git", "add", "-A"], d) - run(["git", "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-qm", label], d) - return check(d) + commit(label) + bad, n, _sha, _whence = check(d, "main") + return bad, n ok = True + _bad, _n, _sha, whence = check(d, "main") + if "merge-base" not in whence: + print(f" FAILED: the merge-base reference was not used ({whence})") + ok = False # (a) an addition WITH a resolvable reference -> silent bad, n = commit_and_check( @@ -203,11 +258,28 @@ def commit_and_check(extra: str, label: str): else: print(f" with a dangling reference : fires") - # (d) an unreachable baseline must REFUSE, never report a clean delta + # (d) ADVANCING the marker past an uncited heading must not erase the + # delta. Without the merge-base read this is the measured bypass: two + # ordinary commits and the gate goes silent (CodeRabbit on #1255). + pathlib.Path(d, MARKER).write_text( + f"PROCESSED_THROUGH_SHA={run(['git', 'rev-parse', 'HEAD'], d).stdout.strip()}\n") + commit("advance the marker past the uncited headings") + bad, n = check(d, "main")[:2] + if not bad: + print(" FAILED: advancing the marker erased the delta (the bypass)") + ok = False + else: + print(f" with the marker advanced : {len(bad)} violation(s) (fires)") + + # (e) an unreachable baseline must REFUSE, never report a clean delta. + # Written to BOTH the checkout and the merge-base reference, so neither + # path can quietly supply a good baseline and make this arm vacuous. pathlib.Path(d, MARKER).write_text( "PROCESSED_THROUGH_SHA=" + "0" * 40 + "\n") + commit("unreachable baseline") + run(["git", "branch", "-f", "main", "HEAD"], d) try: - check(d) + check(d, "main") print(" FAILED: an unreachable baseline did not refuse") ok = False except SystemExit as exc: From eae7f36ecf706d3df356635e35f409c0fdace870 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 16:13:57 +0000 Subject: [PATCH 18/19] board: the merge-base assertion was vacuous under its own disable `"merge-base" not in whence` passed with the merge-base read disabled, because the FALLBACK string also names the merge-base -- it says the marker was absent there. Found by running the disable rather than by reading the assertion. Anchored on the provenance token instead (`startswith("inherited at merge-base")`), which the fallback cannot satisfy. Re-verified: with the merge-base read disabled the self-test now fails on BOTH arms (the reference assertion and the marker-advance bypass); restored, 5/5 PASSED. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/tools/epiphany_provenance.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.claude/tools/epiphany_provenance.py b/.claude/tools/epiphany_provenance.py index db31beda4..d7e4ecba2 100644 --- a/.claude/tools/epiphany_provenance.py +++ b/.claude/tools/epiphany_provenance.py @@ -226,8 +226,11 @@ def commit_and_check(extra: str, label: str): return bad, n ok = True + # startswith, not `in`: the FALLBACK string also names the merge-base (it + # says the marker was absent there), so a substring test passed under the + # very disable it exists to catch -- vacuous, found by running that disable. _bad, _n, _sha, whence = check(d, "main") - if "merge-base" not in whence: + if not whence.startswith("inherited at merge-base"): print(f" FAILED: the merge-base reference was not used ({whence})") ok = False From afa5e9d2abaa47292c348d51d43801b3b5846c74 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 16:15:08 +0000 Subject: [PATCH 19/19] board: the two new comments cited the wrong PR number Both findings are on #1254, not #1255. Three comments named #1255 -- a citation a future session would follow to an unrelated (nonexistent) PR, which is the whole value of citing one. The two commit messages that landed with the same slip are left as-is; rewriting pushed history to fix a reference costs more than the reference is worth, and this commit is the correction of record. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- .claude/hooks/anti-pattern-matching.sh | 2 +- .claude/hooks/tests/anti-pattern-matching.test.sh | 2 +- .claude/tools/epiphany_provenance.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.claude/hooks/anti-pattern-matching.sh b/.claude/hooks/anti-pattern-matching.sh index f1e49c1a4..b6a5fafce 100755 --- a/.claude/hooks/anti-pattern-matching.sh +++ b/.claude/hooks/anti-pattern-matching.sh @@ -83,7 +83,7 @@ CAP_DENY='VERBOTEN (FIRST-HAND SOURCE LAW, Regel 9): eine SUCHE in head/tail/sed # The hook's stdout must be exactly ONE hook response; the MultiEdit branch # below loops over a batch, so without the exit a second violating edit wrote a # second JSON document and the pair parsed as neither denial (CodeRabbit on -# #1255, reproduced before fixing). Exiting inside the function is what stops +# #1254, reproduced before fixing). Exiting inside the function is what stops # the next branch that loops from re-introducing it. emit_deny() { jq -n --arg c "$1" \ diff --git a/.claude/hooks/tests/anti-pattern-matching.test.sh b/.claude/hooks/tests/anti-pattern-matching.test.sh index 209805b66..f2fffeeaa 100755 --- a/.claude/hooks/tests/anti-pattern-matching.test.sh +++ b/.claude/hooks/tests/anti-pattern-matching.test.sh @@ -135,7 +135,7 @@ multiedit SILENT x.md "b" "b tidied" "MultiEdit with no label" # A hook's stdout must be exactly ONE response document. Two violating edits in # one batch used to emit TWO, and a concatenated pair parses as neither denial -# (CodeRabbit on #1255). This asserts the COUNT, not merely that a denial +# (CodeRabbit on #1254). This asserts the COUNT, not merely that a denial # appeared -- the pre-existing rows above could not see the defect, because they # carry one violating edit each. Disable-verified: removing `exit 0` from # emit_deny makes this row report docs=2. diff --git a/.claude/tools/epiphany_provenance.py b/.claude/tools/epiphany_provenance.py index d7e4ecba2..daeaa6146 100644 --- a/.claude/tools/epiphany_provenance.py +++ b/.claude/tools/epiphany_provenance.py @@ -263,7 +263,7 @@ def commit_and_check(extra: str, label: str): # (d) ADVANCING the marker past an uncited heading must not erase the # delta. Without the merge-base read this is the measured bypass: two - # ordinary commits and the gate goes silent (CodeRabbit on #1255). + # ordinary commits and the gate goes silent (CodeRabbit on #1254). pathlib.Path(d, MARKER).write_text( f"PROCESSED_THROUGH_SHA={run(['git', 'rev-parse', 'HEAD'], d).stdout.strip()}\n") commit("advance the marker past the uncited headings")