From 7dd4f4c870915b3ea6fecae2fbb030f4ee793e6f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:16:44 +0000 Subject: [PATCH 1/4] ogar-r2il: borrow CallMask's active words (PR2a, mask-ABI half) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `CallMask` carried a Boolean algebra (and/or/xor/and_not/not/count) over inline words with no way to read them, so a consumer could only reach the population through `contains`/`set_indices` — per-slot, and the wrong shape for a plane-shaped evaluator. `words()` borrows them, sliced to `len.div_ceil(64)` rather than the full `MASK_WORDS` array. Only `Pairs` (180 calls) fills three words; `Triples` (120) and `Quads` (90) fill two, and their third inline word is a phantom the body never had. Handing it out would give a consumer a word count that disagrees with `len()` — and a consumer clearing its own complement tail against that different count would disagree on the phantom's bits while agreeing on every real one. Wrong-answer shape, not wasted-word shape. Population identity stays outside the words: the bits alone do not say what they index. These are CALL SLOTS WITHIN ONE BODY, at most 180, never row ordinals of a table — a row-population consumer that shares this carrier's algebra shares the algebra, not the index space. Three tests, each two-sided: the slice width is derived from `len` and at least one shape is provably narrower than the carrier (anti-vacuity — with no narrow shape the two readings agree by accident); `words()` matches `contains` bit for bit across a seeded scatter plus every word edge the shape can express; and no bit at or past `len` is ever exposed. No behaviour change to any existing caller. 16/16 lib tests, clippy clean. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- crates/ogar-r2il/src/lib.rs | 142 ++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/crates/ogar-r2il/src/lib.rs b/crates/ogar-r2il/src/lib.rs index 48780de..5aa449a 100644 --- a/crates/ogar-r2il/src/lib.rs +++ b/crates/ogar-r2il/src/lib.rs @@ -468,6 +468,31 @@ impl CallMask { self.words.iter().map(|w| w.count_ones()).sum() } + /// The mask's **active** words, borrowed — the zero-copy way out of this + /// carrier and into a plane-shaped consumer. + /// + /// Sliced to `len.div_ceil(64)`, NOT the full [`MASK_WORDS`] inline + /// array: only `Pairs` (180 calls) fills three words; `Triples` (120) and + /// `Quads` (90) fill two, and their third word is a phantom the + /// population does not have. Handing it out would give a consumer a word + /// count that disagrees with [`len`](Self::len) — and a consumer whose + /// own complement clears the tail against a DIFFERENT word count than + /// this mask's [`not`](Self::not) does would then disagree on the + /// phantom's bits while agreeing on every real one. That is a + /// wrong-answer shape, not a wasted-word shape. + /// + /// **Population identity travels with the words, never inside them.** + /// The bits alone do not say what they index: a consumer needs + /// [`len`](Self::len) (the bit count) and [`shape`](Self::shape) (the + /// index space) to read them at all. In particular these indices are + /// CALL SLOTS WITHIN ONE BODY — at most 180 — and are not row ordinals + /// of any table; a row-population consumer sharing this carrier's + /// Boolean algebra shares the algebra, not the index space. + #[must_use] + pub fn words(&self) -> &[u64] { + &self.words[..(self.len.div_ceil(64) as usize)] + } + fn zip(&self, other: &Self, f: impl Fn(u64, u64) -> u64) -> Self { debug_assert_eq!(self.shape, other.shape, "masks of different shapes"); Self { @@ -1007,4 +1032,121 @@ mod tests { ); } } + + /// **The accessor is sliced to the POPULATION, not to the carrier.** + /// + /// `MASK_WORDS` is 3 because `Pairs` (180 calls) needs three words. The + /// other two shapes do not: `Triples` is 120 calls and `Quads` is 90, + /// both two words, and their third inline word is a phantom the body + /// never had. Two-sided on purpose — the assertion that a narrow shape + /// yields FEWER words than the carrier holds is what fails if + /// `words()` is ever changed to hand out `&self.words` whole. + #[test] + fn words_is_sliced_to_the_population_not_the_carrier() { + assert_eq!(MASK_WORDS, 3, "carrier width changed; re-derive the table"); + + for (shape, want_words, want_len) in [ + (LaneShape::Pairs, 3usize, 180u32), + (LaneShape::Triples, 2, 120), + (LaneShape::Quads, 2, 90), + ] { + let m = CallMask::all(shape); + assert_eq!(m.len(), want_len, "{shape:?}: population"); + assert_eq!( + m.words().len(), + want_words, + "{shape:?}: words() must span len.div_ceil(64), not MASK_WORDS" + ); + assert_eq!( + m.words().len(), + (m.len().div_ceil(64)) as usize, + "{shape:?}: slice width must be derived from len, never hardcoded" + ); + } + + // Anti-vacuity: at least one shape must be NARROWER than the carrier, + // or the two readings agree by accident and this test proves nothing. + assert!( + CallMask::all(LaneShape::Quads).words().len() < MASK_WORDS, + "no shape is narrower than the carrier: the slice cannot be falsified" + ); + } + + /// `words()` is the same mask `contains` reads — bit for bit, including + /// the straddling word and the bits just under `len`. + #[test] + fn words_agrees_with_contains_bit_for_bit() { + for shape in [LaneShape::Pairs, LaneShape::Triples, LaneShape::Quads] { + let mut m = CallMask::empty(shape); + // Seeded scatter plus every boundary this shape can express: the + // word edges (63/64, 127/128) and its own last two slots. + let mut seeded = 0u32; + for i in 0..m.len() { + if i % 7 == 0 || i % 13 == 3 { + m.set(i); + seeded += 1; + } + } + for edge in [ + 0, + 1, + 62, + 63, + 64, + 65, + 126, + 127, + 128, + m.len() - 2, + m.len() - 1, + ] { + if edge < m.len() { + m.set(edge); + } + } + assert!(seeded > 0, "{shape:?}: fixture set no bits"); + + let w = m.words(); + for i in 0..m.len() { + let from_words = (w[(i / 64) as usize] >> (i % 64)) & 1 == 1; + assert_eq!( + m.contains(i), + from_words, + "{shape:?}: bit {i} disagrees between contains() and words()" + ); + } + assert_eq!( + w.iter().map(|x| x.count_ones()).sum::(), + m.count(), + "{shape:?}: popcount over the slice must equal count()" + ); + } + } + + /// A complement's tail is clear **within the slice** — the property a + /// plane-shaped consumer relies on when it clears its own tail against + /// the same `len`. `not()` already clears per-word; this pins that the + /// slice never exposes a set bit at or past `len`. + #[test] + fn words_exposes_no_bit_at_or_past_len() { + for shape in [LaneShape::Pairs, LaneShape::Triples, LaneShape::Quads] { + let complement = CallMask::empty(shape).not(); + assert_eq!( + complement.count(), + complement.len(), + "{shape:?}: !empty must be full" + ); + let w = complement.words(); + let tail_bits = (w.len() as u32) * 64 - complement.len(); + if tail_bits > 0 { + let last = w[w.len() - 1]; + let in_range = complement.len() - ((w.len() as u32 - 1) * 64); + assert_eq!( + last >> in_range, + 0, + "{shape:?}: {tail_bits} tail bit(s) set in the last slice word" + ); + } + } + } } From 385cf94c5ff05f54e7b6eda133659afa5b310ea8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:17:56 +0000 Subject: [PATCH 2/4] ogar-r2il: each accessor test names the claim its disable run falsifies The tail test derived the straddling word width arithmetically (`len - (words-1)*64`), which underflows the moment the slice is wider than `len` implies -- i.e. exactly the case under test. It went red under the slice disable by PANIC, not by its assertion: detection for the wrong reason, and a false positive for the claim it appeared to prove. Rewritten to read every physically-spanned bit past the population directly. It then stays GREEN under the slice disable -- correctly, since `not` already clears the phantom words per-word, so a wider slice exposes zeros. So it guards `not`, never `words`, and now says so. The agreement test is labelled the same way: it reads only indices below `len`, which sit in the same words under either width, so it falsifies a wrong word index or bit order and nothing about the slice. One claim per test, each with the disable that reddens it named in its own doc comment. Slicing is falsified by the first test alone. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- crates/ogar-r2il/src/lib.rs | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/crates/ogar-r2il/src/lib.rs b/crates/ogar-r2il/src/lib.rs index 5aa449a..d3b7f20 100644 --- a/crates/ogar-r2il/src/lib.rs +++ b/crates/ogar-r2il/src/lib.rs @@ -1074,6 +1074,11 @@ mod tests { /// `words()` is the same mask `contains` reads — bit for bit, including /// the straddling word and the bits just under `len`. + /// + /// An AGREEMENT test, not a slicing one: it reads only indices below + /// `len`, which live in the same words under either slice width, so it + /// is green whether or not the carrier is over-exposed. It falsifies a + /// wrong word index or a wrong bit order — nothing about the width. #[test] fn words_agrees_with_contains_bit_for_bit() { for shape in [LaneShape::Pairs, LaneShape::Triples, LaneShape::Quads] { @@ -1123,10 +1128,18 @@ mod tests { } } - /// A complement's tail is clear **within the slice** — the property a + /// A complement sets no bit at or past `len` — the property a /// plane-shaped consumer relies on when it clears its own tail against - /// the same `len`. `not()` already clears per-word; this pins that the - /// slice never exposes a set bit at or past `len`. + /// the same `len`. + /// + /// **This guards [`not`](CallMask::not), not [`words`](CallMask::words).** + /// Measured: it stays green when `words()` is widened to the full + /// carrier, because `not` already clears the phantom words per-word, so + /// a wider slice exposes zeros rather than ones. It goes red when `not` + /// is reduced to a plain `!w` over every word. The slice itself is + /// falsified by `words_is_sliced_to_the_population_not_the_carrier`; + /// keeping the two claims in separate tests is what makes each one's + /// disable run mean something. #[test] fn words_exposes_no_bit_at_or_past_len() { for shape in [LaneShape::Pairs, LaneShape::Triples, LaneShape::Quads] { @@ -1136,15 +1149,20 @@ mod tests { complement.len(), "{shape:?}: !empty must be full" ); + // Every bit the slice PHYSICALLY spans, past the population, + // read directly. Deriving the straddling word's in-range width + // arithmetically underflows as soon as the slice is wider than + // `len` implies, and the test then fails by panic instead of by + // assertion — detection for the wrong reason. let w = complement.words(); - let tail_bits = (w.len() as u32) * 64 - complement.len(); - if tail_bits > 0 { - let last = w[w.len() - 1]; - let in_range = complement.len() - ((w.len() as u32 - 1) * 64); + let spanned = (w.len() as u32) * 64; + for i in complement.len()..spanned { + let bit = (w[(i / 64) as usize] >> (i % 64)) & 1; assert_eq!( - last >> in_range, + bit, 0, - "{shape:?}: {tail_bits} tail bit(s) set in the last slice word" + "{shape:?}: bit {i} is set but the population is only {} wide", + complement.len() ); } } From 8517b8c34be993b014504cb5a54b3e3d16288fdb Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:18:48 +0000 Subject: [PATCH 3/4] ogar-r2il: drop the tail test -- its assertion is unreachable `words_exposes_no_bit_at_or_past_len` looped over every bit the slice physically spans past `len` and asserted each was clear. That assertion can never be the one that fires. `count()` reads `self.words` WHOLE (no slice, lib.rs:468), so it already counts phantom bits. Any bit set in 180..192 therefore moves `count`, and the test's own precondition -- `!empty` must have `count == len` -- fails first. Measured against a `not()` disable (tail clearing removed): the test goes red at the precondition, never at the loop. That makes the loop decoration, and the precondition a restatement of the pre-existing `a_complement_never_invents_call_slots`, which catches the same disable. Deleted rather than reworded. What survives carries one disable-verified claim each: `words_is_sliced_to_the_population_not_the_carrier` falsifies the slice width (red when `words()` hands out the full carrier), and `words_agrees_with_contains_bit_for_bit` falsifies word index and bit order. `not()`'s tail discipline stays where it already was. Left standing as a NOTE, not fixed here: `count()` spanning the full carrier means it is not derivable from `words()`. The two agree only because the phantoms are always zero -- which the agreement test pins, and which no caller should assume beyond that. 15/15 lib tests, clippy clean. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- crates/ogar-r2il/src/lib.rs | 40 ------------------------------------- 1 file changed, 40 deletions(-) diff --git a/crates/ogar-r2il/src/lib.rs b/crates/ogar-r2il/src/lib.rs index d3b7f20..64acac4 100644 --- a/crates/ogar-r2il/src/lib.rs +++ b/crates/ogar-r2il/src/lib.rs @@ -1127,44 +1127,4 @@ mod tests { ); } } - - /// A complement sets no bit at or past `len` — the property a - /// plane-shaped consumer relies on when it clears its own tail against - /// the same `len`. - /// - /// **This guards [`not`](CallMask::not), not [`words`](CallMask::words).** - /// Measured: it stays green when `words()` is widened to the full - /// carrier, because `not` already clears the phantom words per-word, so - /// a wider slice exposes zeros rather than ones. It goes red when `not` - /// is reduced to a plain `!w` over every word. The slice itself is - /// falsified by `words_is_sliced_to_the_population_not_the_carrier`; - /// keeping the two claims in separate tests is what makes each one's - /// disable run mean something. - #[test] - fn words_exposes_no_bit_at_or_past_len() { - for shape in [LaneShape::Pairs, LaneShape::Triples, LaneShape::Quads] { - let complement = CallMask::empty(shape).not(); - assert_eq!( - complement.count(), - complement.len(), - "{shape:?}: !empty must be full" - ); - // Every bit the slice PHYSICALLY spans, past the population, - // read directly. Deriving the straddling word's in-range width - // arithmetically underflows as soon as the slice is wider than - // `len` implies, and the test then fails by panic instead of by - // assertion — detection for the wrong reason. - let w = complement.words(); - let spanned = (w.len() as u32) * 64; - for i in complement.len()..spanned { - let bit = (w[(i / 64) as usize] >> (i % 64)) & 1; - assert_eq!( - bit, - 0, - "{shape:?}: bit {i} is set but the population is only {} wide", - complement.len() - ); - } - } - } } From 239fc609a683e3fe3751ca69c71b4b94641b269b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 20 Sep 2026 12:40:47 +0000 Subject: [PATCH 4/4] CLAUDE.md: the shell rule is superseded by an evidence rule The non-negotiable read "grep/sed/tail/head/awk via Bash are prohibited -- use the Grep/Read/Glob tools." It policed which Unix command is typed, not the failure it was written for, and the failure kept happening through the sanctioned tools: SEARCH HIT -> snippet -> meaning assumed -> architecture asserted SEARCH = 0 -> "it does not exist" Replaced in place (append-only canon: the old text is quoted under a supersession marker, not deleted) by the epistemic rule. Search may establish only "candidates are X, Y, Z" -- never what a type means, what a function guarantees, that a consumer does not exist, who owns something, or which way a dependency runs. 0 hits proves nothing; a global negative needs a CLOSED, explicitly named search space; a partial Read is not evidence for a whole-file claim; and a search must never be the last tool result before an architectural conclusion. sed/head/tail/awk stay prohibited for SOURCE INSPECTION specifically -- a numeric slice has no semantic boundary -- while limiting a non-search command's output stays fine, which the old blanket wording forbade and which the fleet's own guarded-executor contract requires. Full law + auto-deepen triggers + paging rule + delegation/escalation levels: lance-graph .claude/knowledge/FIRST-HAND-SOURCE-LAW.md, enforced there by a PreToolUse guard with a committed two-sided test. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GXUahz73MZxtxWcfpHp9dG --- CLAUDE.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4480642..735c20d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -296,7 +296,21 @@ alignment costs. Until measured: 3×4 stands. - **PII:** never emit German PII labels (medcare-rs leaf-rename at the adapter is the guarantee). Word-boundary abort-guard before commit. - **No model identifier** in any committed artifact (chat only). -- **Shell discipline:** `grep`/`sed`/`tail`/`head`/`awk` via Bash are - prohibited — use the Grep/Read/Glob tools. +- **Evidence discipline (SUPERSEDES the shell rule):** ⊘ the rule here was + *"`grep`/`sed`/`tail`/`head`/`awk` via Bash are prohibited — use the + Grep/Read/Glob tools."* That policed which Unix command is typed, not the + failure it was written for. The governing rule is now epistemic: + **SEARCH IS NAVIGATION, NEVER EVIDENCE.** A search may establish only + *"candidates are X, Y, Z"* — never what a type means, what a function + guarantees, that a consumer does not exist, who owns something, or which way + a dependency runs. `0 hits` proves nothing; a global negative needs a CLOSED, + explicitly named search space; a partial Read is not evidence for a + whole-file claim; and **a search must never be the last tool result before + an architectural conclusion.** `sed`/`head`/`tail`/`awk` stay prohibited for + SOURCE INSPECTION specifically (a numeric slice has no semantic boundary), + while limiting a non-search command's output stays fine. Full law, the + auto-deepen triggers, the paging rule and the delegation/escalation levels: + lance-graph `.claude/knowledge/FIRST-HAND-SOURCE-LAW.md`, enforced by that + repo's `PreToolUse` guard. - **Append-only canon:** never delete a ledger entry; regrade in place; corrections cite their pass (savant / G-pass / canon-pass).