Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .claude/board/EPIPHANIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,33 @@ A valid sign assignment exists — so the fixture is **consistent**, and the "co
**The CI corollary (#862, arguably the most consequential single item in the three).** `cargo test` **never executes an example's `main()`** — so every `assert!` in these probe examples had only ever run on a developer's local invocation. Until `rust-test.yml` was changed to run the probes explicitly, an entire class of falsifier was **decorative in CI**. A falsifier that never runs is the limit case of a falsifier that cannot fail.

**Scope fence.** This says the *review-found* defects clustered in falsifiers; it does **not** claim the measurements were correct — only that no review round found a defect in one. That is an absence of evidence over three PRs, not proof, and the honest reading is that falsifier code got less scrutiny while being written than the numbers it guarded.
## 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

**Status:** FINDING (review round on PR #902; both reviewers converged on it independently). **Confidence:** High — the failure is reproduced by a test in the same commit, and the fix's own guard was mutation-tested. Shipped with `lance_graph_contract::identity_quad`.

**The finding, and it is a genuine one that the original design missed.** `IdentityCodebook::try_new` sorts the key list and derives each ordinal from the sorted position. So **an ordinal is a property of the whole key set, not of the key alone**: grow a book by one key that sorts early and every ordinal at or after it shifts by one. Because the quad is a **persisted payload** rather than a transient value, the ordinal outlives the process that computed it — a facet baked against the old book resolves, through the new book, to a *neighbouring* key.

**Why the existing witness could not catch it — the load-bearing part.** `verify_bijective()` sweeps the whole book and proves `ordinal → key → ordinal` is the identity. It passes on **both** revisions, because each book is internally consistent. A within-book property cannot detect a between-book disagreement, however exhaustively it is checked. That is the general shape worth keeping: **an invariant proved inside one artifact says nothing about two artifacts that must agree with each other**, and a persisted encoding always has the second problem whether or not anyone wrote it down.

**What shipped, and what deliberately did not.** `IdentityCodebook::digest()` — a deterministic FNV-1a over the *ordered* key list, each key fed length-first so `["ab","c"]` and `["a","bc"]` cannot collide through concatenation. A bake records the digest beside the rows it wrote; a later read compares and refuses a shifted book instead of resolving a wrong key. It is a **witness, not an enforcement** — nothing in the type can stop a caller that declines to compare, and that limit is stated in the doc rather than papered over. An **append-preserving constructor was considered and NOT added**: a book that preserved assignments would no longer be sorted, and `ordinal()`'s `binary_search` would be unsound. Growing a book is therefore a **rebake**, stated as a constraint. Binding facets to a versioned codebook at the contract level stays open: `ISSUES.md` `ISS-IDENTITY-CODEBOOK-ORDINAL-STABILITY`.

**Two tests, both falsifiable, and the guard was broken on purpose to confirm it bites.** `growing_a_codebook_with_an_early_key_renumbers_the_existing_ones` makes the hazard *observable* — it asserts the mis-explanation happens and that both books pass `verify_bijective` — so the documented constraint is a demonstrated behaviour rather than a claim. `the_digest_fires_on_a_shift_and_stays_silent_on_an_equivalent_book` is the fire/silence pair on one value: different digest for a renumbering book, **same** digest for the same key set supplied in a different input order, and different digests for the concatenation-colliding pair. Mutation check: deleting the length prefix fails the third assertion — so the delimiter is load-bearing and not decoration.

**Review-triage note (method, not content).** Of the four review comments on #902, two were the finding above (the same defect reached from opposite directions), one was a real wording imprecision (capacity: `2^24 - 2` is `MAX_ORDINAL`, a *slot bound*; `MAX_ENTRIES = 2^24 - 1` is the *entry count* `check_capacity` gates — both now named separately in the doc), and one asked for the carving's sanction before publishing, which is not an oversight but the already-recorded `ISS-IDENTITY-QUAD-WIDE-CARVING-HOME` awaiting an operator ruling. Comment count is not defect count; each was priced separately.

## 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

**Status:** FINDING (shipped with `lance_graph_contract::identity_quad`, branch `claude/vocab-tenant-bake`). **Confidence:** High for the distinction and the encoding; the *home* of the carving is an OPEN operator question, tracked as `ISS-IDENTITY-QUAD-WIDE-CARVING-HOME` rather than settled in code.

**The finding.** `le-contract.md` §3's byte-axis catalogue (L1-L8) and §3a's discouragement of the wide carvings (G1-G3) are, read carefully, rules about **references**: a rail byte is a one-byte ref addressing 256 targets local to a basin, and the cap exists precisely so a ref can never become an unbounded global pointer. Widening a rail pair to `u16`/`u24` reopens that — which is the bug `lane16b` and `facet_lane` were both written to close, and it stays a bug.

**An exact external identity is a different kind of value, and the rule does not transfer to it.** It is not adjacency, it does not reach anywhere, and it has exactly one correctness property: **invertibility**. A `u24` split into three independently-meaningful bytes is three values, and three values are not one invertible identity. So the same arithmetic (12 bytes, 96 bits) is right one way and wrong the other, decided entirely by what the value IS — which is the slot-purity doctrine (§2) pointing at its own consequence: the ClassView selects the reading, and a reading that destroys invertibility is not available to a class whose slots are identities.

**The corollary that made the encoding work.** Because the value is an identity, "absent" cannot be spelled `0` — the zeroth entry of a codebook is a real identity. Slots therefore store `ordinal + 1`, and raw `0` is the CANON zero-fallback ladder's "not consulted". Without that offset a partially-joined row reads as fully joined, silently, which is the failure mode this tenant exists to remove rather than relocate. The largest ordinal a slot can hold is `MAX_ORDINAL = 2^24 - 2`; a book may hold one more *entry* than that number (`MAX_ENTRIES = 2^24 - 1`, the count `check_capacity` gates) because ordinals start at zero — the two are separate constants on purpose. The codebook **refuses** past capacity instead of truncating.

**The second corollary: bijectivity is a CONSTRUCTOR obligation, not a test obligation.** `IdentityCodebook::try_new` rejects a non-injective key list, so the many-to-one mapping cannot be built and therefore cannot be found later at a call site. The whole-book `verify_bijective()` sweep exists anyway, because "the constructor guarantees it" is an argument and a bake wants a measurement. Both halves shipped; the negative case (a duplicate is refused, a non-duplicate is not) is its own test.

**Method note worth keeping.** Two guards were **mutation-tested in-session** rather than trusted: replacing the duplicate check with `dedup()` failed the injectivity test; dropping the absent sentinel failed four tests. This is the cheap form of the falsifiability rule — write the guard, then break it on purpose and watch the suite notice. One test in the first draft (`over_capacity_codebook_is_refused`) was caught **vacuous by this discipline** — it asserted a value equalled itself — and was rewritten as a boundary assertion against an extracted `check_capacity`, because a guard whose failure path cannot be reached by any input is the defect one level up (`E-VACUOUS-ASSERTION-IS-THE-HOUSE-STYLE-1`).

## 2026-08-02 — E-D-MBX-SPINE-IS-STRAIGHT-TRACK-VERSION-IS-NOT-A-FLEET-STEP-SIGNAL-1 — the D-MBX production ownership map is ratified, and P4's fleet-wide fan-step is corrected to sparse sealed-transition application

Expand Down
Loading
Loading