Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
546b17a
Core vertical slice: docs/abi.md contract, native/lgj-abi, Java facade
AdaWorldAPI Aug 17, 2026
a1e65cc
Merge main (bootstrap commit) into dev branch to establish shared his…
AdaWorldAPI Aug 17, 2026
bdd40b2
Valhalla lab: three-truths method, causal isolation, 3 real reproducers
AdaWorldAPI Aug 17, 2026
317ee83
Merge main (squash of PR #1) to fix history divergence for PR #2
AdaWorldAPI Aug 17, 2026
ea4753c
Merge main (squash of PR #2) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
4ab0da8
Vector API bench: real JMH, cross-checked; the crossing does not alwa…
AdaWorldAPI Aug 17, 2026
96eccff
Merge main (squash of PR #3) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
cd7782b
Phase I synthesis docs + fusion-sweep 256-row re-run + board hygiene
AdaWorldAPI Aug 17, 2026
ddeaecb
Merge main (squash of PR #4) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
e4463cb
Board: PR #4 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
e8b6dc2
SoA row store: 512B rows, 32 facet lanes, ABI minor 2 (W1+W2)
AdaWorldAPI Aug 17, 2026
aff72f3
Merge main (squash of PR #5) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
8fceaca
Board: PR #5 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
91e22f3
Knowledge: assess the archived layout-bridge discussion; name W6
AdaWorldAPI Aug 17, 2026
6927961
Plans: OGAR Machine (exploratory) + lance-graph-hydrate dependency note
AdaWorldAPI Aug 17, 2026
7e218ed
Merge main (squash of PR #6) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
9cc85ad
Board: PR #6 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
f3bbab7
Waves calcified: dispatch maps for every plan; Ghidra plan from real …
AdaWorldAPI Aug 17, 2026
dac0f0b
Merge main (squash of PR #7) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
57a7e48
Board: PR #7 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
83b8994
Plan: lance-graph #958 merged (was open at last check)
AdaWorldAPI Aug 17, 2026
572f865
Java RowStore facade: W3 shipped (185/185, one bug found+fixed)
AdaWorldAPI Aug 17, 2026
b138382
Merge main (squash of PR #8) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
bc6f91a
Board: PR #8 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
619b3de
Plan: r2sleigh recorded as third lift path + decompiler candidate
AdaWorldAPI Aug 17, 2026
84e73ca
Bench Component F: the boundary re-asked on the real row-store layout…
AdaWorldAPI Aug 17, 2026
897fd92
Merge main (squash of PR #9) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
201a626
Board: PR #9 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
ed4fb7c
Parity: the third independent read path (ROW_LAYOUT segment reads)
AdaWorldAPI Aug 17, 2026
6c4afe4
Merge main (squash of PR #10) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
9717cda
Board: PR #10 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
8eecb3b
Consumer example: World/Trades — the zero-object fluent domain API (W5a)
AdaWorldAPI Aug 17, 2026
74e5b6b
Merge main (squash of PR #11) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
9088dc9
Board: PR #11 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
f7974da
Consumer example: Bricks — mask-first authorization, fail-closed, agg…
AdaWorldAPI Aug 17, 2026
ce6fba4
Merge main (squash of PR #12) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
239edf0
Board: PR #12 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
9ee044f
Board: record the C-band ruling — the classid domain byte carries ALT…
AdaWorldAPI Aug 18, 2026
e736d6a
Board: reconcile Ghidra G1/G2 -- superseded by ruff_r2il, not built
AdaWorldAPI Aug 18, 2026
f68335b
Board: ruff #96 is a different arm; read the real staging guide + ran S1
AdaWorldAPI Aug 18, 2026
df35426
Board: R2IL handshake outcomes + the Valhalla-premise storno (operato…
AdaWorldAPI Aug 18, 2026
8806899
rowstore: generate_with_edges -- the graph-consumer wave's real, meas…
AdaWorldAPI Aug 18, 2026
f03a9ce
Merge main (squash of PR #13) to keep dev branch history aligned
AdaWorldAPI Aug 18, 2026
ae02be5
lgj-abi: edge-bearing row store ABI addition (lgj_rowstore_open_with_…
AdaWorldAPI Aug 18, 2026
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
91 changes: 91 additions & 0 deletions .claude/board/EPIPHANIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,97 @@
> `**Status:**`/`**Confidence:**` line. A correction gets its own new,
> dated entry that references the one it corrects — the storno rule.

## 2026-08-18 (later still) — "the generator exists" ≠ "Java can reach it": the membrane gap the prior entry's own resolution note missed

**Status:** FINDING + a correction of the entry directly below this one.
**Confidence:** High — measured (`nm -D` before/after, full Rust + Java test
suites, two disable-runs).

### What the prior entry's "RESOLVED" undersold

The STOP-condition entry below this one — and `wave-consumer-graph.md`'s own
header — declared the graph wave DISPATCHABLE once
`RowStore::generate_with_edges` existed and its numbers were pinned. True at
the Rust level, but incomplete: `Engine.openRowStore` /
`registry::open_rowstore` (the only path Java has to a `RowStore`) call
plain `RowStore::generate` unconditionally. **No `extern "C"` symbol for the
edge-bearing generator existed.** A worker briefed to build `Graph.java`
against `RowStore.open` would have had no way to reach non-vacuous data at
all — the exact STOP condition this wave was declared clear of, just moved
one layer up the stack, and it would have surfaced as a live "the file I
need is outside my scope" STOP report from a Sonnet worker mid-dispatch
rather than being caught here, before any worker spawned.

Same shape as the finding this whole sub-arc started from: checking the
*mechanism* (does a hop composition exist) without checking the *path*
(can a caller actually reach the data the mechanism needs). Twice now in
one wave.

### The fix — the wave's own D1b rule, applied to itself

`wave-consumer-graph.md`'s Decision D1 already states the rule for exactly
this shape of gap: *"a new ABI symbol... must go through the substrate wave
process FIRST as its own W-tier PR (the consumer-never-grows-the-membrane
rule)."* Applied it to the row-store CONSTRUCTOR, not just the hop op D1
was originally about — same rule, same reasoning: growing the membrane is
orchestrator/W-tier work, never a consumer worker's ad hoc addition.

`lgj_rowstore_open_with_edges` (ABI minor 2→3, `docs/abi.md` §12):
`registry::open_rowstore_with_edges` + the `extern "C"` export mirror
`open_rowstore`/`lgj_rowstore_open` symbol-for-symbol — same
`LGJ_RESOURCE_ROWSTORE` kind, same lane shape, no new mask op, purely an
alternative constructor. Java: `Downcalls.rowstoreOpenWithEdges` +
`Engine.openRowStoreWithEdges` (`Abi.requireMinor(3)`, matching the row
store's own minor-2 gate pattern) + the public `RowStore.openWithEdges`
factory.

### The strongest new result: Java independently reproduces the D1a hop, not just the classid stream

Added to `RowStoreParityTest` rather than deferred to G1/G2: a **Java-side
transcription of the exact D1a mechanism** (`lgj_row_facet_match` crossing +
raw lane-0 payload decode, zero new ABI op — the mechanism the wave's own
Decision D1 chose to start with) at the SAME parameters as the Rust-pinned
regression (`n=2000, seed=0xF00D_CAFE, edge_classid=0, gate_mask=0x0,
radius=25`). Result: **19 rows at 1 hop, 29 at 2 hops — identical to the
Rust side, to the row.** This is a stronger falsifier than the Rust
regression alone: it proves the membrane doesn't just carry the same
classid stream, it carries the same *edge structure*, read through the
exact mechanism a real `Graph.hop()` will use.

Two disable-runs, both red-then-green:
1. **Registry level:** hardcoded `open_rowstore_with_edges`'s inner call to
pass `edge_classid = 0` regardless of the argument → the new
`out_of_range_edge_classid_matches_plain_open_through_the_registry` test
(which passes `edge_classid = 16`, expecting parity with plain `open`)
went red, because classid 0 with `gate_mask = 0x0` genuinely writes
structured edges the plain generator never would. Restored, 93/93.
2. **Java level:** forced the hop transcription's classid-match check to
always skip (`if (true) { continue; }`) → 1-hop and 2-hop both collapsed
to 0 and the anti-vacuity assertion failed exactly as expected. Restored,
194/194.

### Gates

`cargo test` 93/93 (+3 over the prior entry's 90), clippy `-D warnings` +
`fmt --check` clean, release build exports `lgj_rowstore_open_with_edges`
(`nm -D`, confirmed present). Java `AllTests` 194/194 (+6, all in
`RowStoreParityTest`) — full suite re-run, not just the new section, since
the stale top-level `target/release/liblgj_abi.so` (pre-dating this pass,
minor 2) initially made EVERY suite fail at class-init (`Downcalls`
eagerly resolves all method handles including the new one) until rebuilt
with `CARGO_TARGET_DIR=$ROOT/target cargo build --release` per the
documented build convention — a real, if brief, self-inflicted false
alarm, not a substrate defect; recorded so a future session doesn't
re-diagnose the same eager-resolution behavior as a bug.

### Consequence

The graph-consumer wave is now genuinely dispatchable — the substrate is
proven at BOTH the Rust generator level (prior entry) and the Java
membrane level (this entry), through the exact D1a mechanism the wave
already chose. G1 (traversal facade) and G2 (falsifier tests) are next,
not yet spawned.

## 2026-08-18 (measured) — the graph-consumer STOP condition was real, and is now cleared

**Status:** FINDING + a correction of MY OWN earlier claim. **Confidence:**
Expand Down
40 changes: 40 additions & 0 deletions .claude/board/LATEST_STATE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
## 2026-08-18 (later still) — the graph wave's ABI gap, found and closed before dispatch: `lgj_rowstore_open_with_edges` (minor 3)

Picked up the graph-consumer wave on "everything on track?" — it was marked
DISPATCHABLE by the entry below, and idle capacity while ruff_r2il works its
own PR2/3 track was worth using. Before spawning G1/G2, checked what Java
would actually call to reach `RowStore::generate_with_edges` — and it was
nothing: `Engine.openRowStore`/`registry::open_rowstore` only ever call plain
`RowStore::generate`; no `extern "C"` symbol for the edge-bearing generator
existed anywhere. The prior pass's STOP-condition-RESOLVED note proved the
*generator*, not the *membrane path to it* — a real gap that would have
surfaced mid-dispatch as "G1's scope requires touching a file outside your
scope" the moment a worker tried to open an edge-bearing store from Java.

Closed it as the wave's own D1b rule requires: "a new ABI symbol... must go
through the substrate wave process FIRST as its own W-tier PR" — done here as
orchestrator work (genuinely new ABI surface, not consumer scope), not
delegated. `lgj_rowstore_open_with_edges` (ABI minor 2→3, docs/abi.md §12):
byte-identical resource kind and lane shape to `lgj_rowstore_open`, purely an
alternative constructor, following the row store's own minor-2
`requireMinor` gating pattern exactly. `cargo test` 93/93 (+3), Java `AllTests`
194/194 (+6). Full record (including the two disable-runs and the strongest
result — Java independently reproducing the D1a hop mechanism's exact pinned
numbers through raw-segment reads, not just the classid stream): see
`STATUS_BOARD.md` D-LGJ-W6, `EPIPHANIES.md`.

Not yet dispatched: G1 (traversal facade) and G2 (falsifier tests) are next,
now against a genuinely complete substrate rather than one proven only at the
Rust generator level.

Meanwhile on ruff: PR #100 (upstream 1500-commit catch-up, explicitly marked
"baseline, not for merge" in its own body) merged anyway by the operator —
its own CI never completed (cancelled on every commit), but incidentally
fixed a 13-day-old `main`-CI lint failure (`prek`/shellcheck on
`.github/workflows/ci.yaml:443`) that predated this whole arc and was
unrelated to it. PR #101 (`ruff_r2il` PR2 first slice — §12 corpus profile
resolving O1, `RefinedTruthSink`) merged cleanly on top, ~1.5h turnaround,
CI green through `prek` on the resulting `main` run — the standing lint issue
stayed fixed. Neither event required action here; recorded for continuity
since both landed mid-session.

## 2026-08-18 (measured) — W5c's real blocker found + cleared: RowStore::generate_with_edges

Asked what was buildable while ruff_r2il PR2/PR3 are blocked. Was about to
Expand Down
3 changes: 2 additions & 1 deletion .claude/board/STATUS_BOARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ layout wired end to end. Doctrine: `E-LGJ-THE-MIDDLE-TIER-IS-DELETED-NOT-WRAPPED
| D-LGJ-W2 | lgj-abi row store: `rowstore.rs`, `LGJ_RESOURCE_ROWSTORE`, `lgj_rowstore_open`, strided facet lanes through the unchanged `LgjLaneDesc`, `lgj_op_eq_classid`, `lgj_row_facet_match`, ABI minor 1→2, `docs/abi.md` §11 | **DONE 2026-08-17** — `cargo test` **84/84**, clippy/fmt clean, release build exports **18/18** symbols (`nm -D`). Parity: both kernels vs independent scalar references over 10 row counts × 2 seeds × 4 facets × 4 needles, cross-checked a THIRD way against `RowStore::classid_at`. Two-sided payload-vs-classid falsifier. End-to-end membrane test covers describe → predicate → mask algebra → count → facet-match → lifecycle |
| D-LGJ-W3 | Java `RowStore` facade: structured `MemoryLayout`, minor-≥2 gate, `FacetMatchView`, parity test transcribing the generator | **DONE 2026-08-17** — dispatched per `.claude/waves/wave-substrate-w3-w4.md` (3 Sonnet workers, disjoint scopes: FFM membrane extension / public facade / tests), orchestrator-integrated. `javac -Xlint:all` clean (same 7 pre-existing `[restricted]` warnings, zero new). `AllTests` **185/185** (was 132; +53 new checks: 29 parity + 24 lifetime). **One real bug caught by the suite and fixed**: `FacetMatchView.rowCount()` was missing the closed-store guard `matchesOf`/`cardinality` both had — a stale row count was readable after the owning store closed. Fixed, re-verified. Both mandated disable-runs ran red-then-green: (1) `Abi.requireMinor` inflated by 1 → exactly `RowStoreParityTest`+`RowStoreLifetimeTest` failed, all 8 other suites stayed green; (2) the pure-Java generator's a/b draw order swapped in `RowStoreParityTest` → exactly that suite broke (17/29), `RowStoreLifetimeTest` (generator-independent) stayed green — confirming the parity test is a real falsifier, not decorative. `Mask.source()` retyped `NativePattern → NativeResource` (new interface) so a `Mask` can parent onto either a `NativePattern` or a `RowStore` — zero call-site breakage (verified: no existing caller bound the narrower type) |
| D-LGJ-W4 | Bench Component F: Vector API facet scan vs the crossing, on the REAL layout | **DONE 2026-08-17** — 1 Sonnet worker (F_RowStoreFacetScan + RowStoreData + Kernels facet-match arms, cross-check-in-@Setup discipline), orchestrator-run JMH: 9/9 combos, cross-checks green at every row count. **Finding: Component C's direction survives, its margin collapses** — Vector API wins the 32-facet strided scan at every row count but by 2.51×/1.92×/1.14× (4K/65K/1M rows) vs C's 56×; at 512 MiB traversed all three arms converge on memory bandwidth. Native arm's per-call allocation asymmetry disclosed in §F with a named follow-up (`facetMatchesInto`), not hidden. summarise.sh extended with the F table (and the old 'E/F' section retitled 'E' — a real naming collision); tables regenerated from the merged CSV |
| D-LGJ-W5 | Three consumer examples (trades / bricks / graph) — one plan file each | **trades DONE 2026-08-17** — `consumers/trades/` (own compile unit, core consumed as a third-party would): `Trade` (schema-not-entity: zero public ctors, zero instance fields, reflection-forced construction still throws), `World.open` → the existing lazy `View` under domain names, zero new membrane surface. TradesParityTest 12/12 (chain vs transcribed-generator recomputation at 1K+64K rows; 0 crossings composing / 1 at terminal THROUGH the domain vocabulary; reflection guard). TradesAllocationTest 3/3 — **the poster's number, measured: 240 bytes/query, IDENTICAL at 64K and 1M rows** (row-count independence is the thesis assertion; 64 KiB absolute backstop). Disable-run: VENUE pointed at the wrong lane → the membrane's own LANE_KIND_MISMATCH rejected it (the binding is checked, not trusted); restored green. **bricks DONE 2026-08-17** — `consumers/bricks/` (2 Sonnet workers K1/K2 per `.claude/waves/wave-consumer-bricks.md`): mask-first RBAC where `authorize(Role)` is a real natively-evaluated predicate in the SAME lazy chain as `where(...)` (`Role.EU_ONLY` = `REGION.eq(EU)`, `DENY_ALL` = `REGION.eq(0xFFFF)` — a genuine impossible predicate, not a Java branch), fail-closed (`UnauthorizedQueryException` BEFORE any crossing; no default-allow path exists), aggregate-only egress (every public method returns `BricksQuery`/`long`/`Map` — structurally no row-shaped type). BricksAuthTest **62/62**: parity vs transcribed generator at 1K+64K; RBAC-as-predicate equivalence (EU_ONLY result == GLOBAL+explicit-where); DENY_ALL counts 0 while paying a real crossing; crossing arithmetic — count()=1, sumBy()=**32 crossings (16 groups × 2: plan_eval + lgj_reduce_sum_i32), IDENTICAL at both row counts** (the thesis: crossings ∝ groups, never rows — the measured 32 corrected K1's "1 per group" Javadoc claim, a real finding about sum-terminal cost); reflection guards. Disable-run: `requireAuthorized` short-circuited → **exactly the 3 can-fire fail-closed checks red, 59 green**; restored, 62/62. Core suite unaffected (188/188). graph still shelved on the D1 ruling + edge-generator substrate change |
| D-LGJ-W5 | Three consumer examples (trades / bricks / graph) — one plan file each | **trades DONE 2026-08-17** — `consumers/trades/` (own compile unit, core consumed as a third-party would): `Trade` (schema-not-entity: zero public ctors, zero instance fields, reflection-forced construction still throws), `World.open` → the existing lazy `View` under domain names, zero new membrane surface. TradesParityTest 12/12 (chain vs transcribed-generator recomputation at 1K+64K rows; 0 crossings composing / 1 at terminal THROUGH the domain vocabulary; reflection guard). TradesAllocationTest 3/3 — **the poster's number, measured: 240 bytes/query, IDENTICAL at 64K and 1M rows** (row-count independence is the thesis assertion; 64 KiB absolute backstop). Disable-run: VENUE pointed at the wrong lane → the membrane's own LANE_KIND_MISMATCH rejected it (the binding is checked, not trusted); restored green. **bricks DONE 2026-08-17** — `consumers/bricks/` (2 Sonnet workers K1/K2 per `.claude/waves/wave-consumer-bricks.md`): mask-first RBAC where `authorize(Role)` is a real natively-evaluated predicate in the SAME lazy chain as `where(...)` (`Role.EU_ONLY` = `REGION.eq(EU)`, `DENY_ALL` = `REGION.eq(0xFFFF)` — a genuine impossible predicate, not a Java branch), fail-closed (`UnauthorizedQueryException` BEFORE any crossing; no default-allow path exists), aggregate-only egress (every public method returns `BricksQuery`/`long`/`Map` — structurally no row-shaped type). BricksAuthTest **62/62**: parity vs transcribed generator at 1K+64K; RBAC-as-predicate equivalence (EU_ONLY result == GLOBAL+explicit-where); DENY_ALL counts 0 while paying a real crossing; crossing arithmetic — count()=1, sumBy()=**32 crossings (16 groups × 2: plan_eval + lgj_reduce_sum_i32), IDENTICAL at both row counts** (the thesis: crossings ∝ groups, never rows — the measured 32 corrected K1's "1 per group" Javadoc claim, a real finding about sum-terminal cost); reflection guards. Disable-run: `requireAuthorized` short-circuited → **exactly the 3 can-fire fail-closed checks red, 59 green**; restored, 62/62. Core suite unaffected (188/188). **graph: substrate now fully unblocked (D-LGJ-W6, this pass) — dispatch is the next action, not yet executed** |
| D-LGJ-W6 | Edge-bearing row store ABI addition (`lgj_rowstore_open_with_edges`, minor 2→3, docs/abi.md §12) — the D1b-shaped "must land as its own W-tier PR before the consumer wave" the graph wave itself named | **DONE 2026-08-18** — orchestrator-authored (genuinely new ABI surface, not consumer-scope work): `registry::open_rowstore_with_edges` + `lgj_rowstore_open_with_edges` (mirrors `lgj_rowstore_open` exactly: same resource kind, same lane shape, no new mask op — purely an alternative constructor), `Engine.openRowStoreWithEdges`/`Abi.requireMinor(3)`, `RowStore.openWithEdges`. `cargo test` **93/93** (+3: registry-level open/describe, out-of-range-classid-matches-plain, radius-overflow-rejected), clippy/fmt clean, release build exports the new symbol (`nm -D`). Java: `AllTests` **194/194** (+6, all in `RowStoreParityTest`) — the strongest new result is a cross-language reproduction of the D1a hop mechanism itself: Java facet-matches + raw-lane-0 payload decode (zero new ABI op) reaches the EXACT same measured hop counts already pinned as a Rust regression (10-row seed → 19 at 1 hop → 29 at 2 hops, `n=2000, seed=0xF00D_CAFE, edge_classid=0, gate_mask=0x0, radius=25`) — proving the two sides of the membrane see identical edge structure, not merely identical classids. Two disable-runs, both red-then-green: (1) registry-level, a classid-not-threaded bug (`open_rowstore_with_edges` hardcoded classid `0`) caught by the out-of-range-parity test; (2) Java-level, the hop's classid-match condition forced to always skip → 1-hop/2-hop both went to 0 and the anti-vacuity assertion failed, exactly as expected. Caught mid-dispatch: the ABI-facing symbol did not exist before this pass (only the bare `RowStore::generate_with_edges` Rust function did, from the prior session) — the graph wave's own STOP-condition-RESOLVED note undersold what was still missing; closed here rather than discovered by G1/G2 mid-flight |
Loading