From db10f0327603674fdfe8a86e1fceb2ae13f8e944 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 19:35:14 +0000 Subject: [PATCH 1/3] board: PR #79 arc entry (post-merge sha 9cb63e9) Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01DCfrD5y19cvFc4AoyydXYv --- .claude/board/PR_ARC_INVENTORY.md | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index e300d3e..4b5ce18 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -8,6 +8,46 @@ > anti-pattern the imported board rules name. Backfilled below in one > pass rather than left stale; PR #4 onward gets its entry at merge time. +## PR #79 — `hop_cached_vs_gather`: the M1b tile pays off on hop two; the scatter walk is the access-shape question (opened 2026-09-16, merged `9cb63e9`, head `c10029b`) + +**Added.** `native/lgj-abi/examples/hop_cached_vs_gather.rs` — `lgj_hop`'s +selection three ways at 65 536 rows × 32 facets, every arm asserted +bit-identical on every frontier before timing: `recompute` (the shipped +body: per facet two contiguous `eq_u32` passes + `ternlog` + scatter), +`cached` (`sel_f = class_f ∧ struct_f` built once per store generation — +32 × 8 KiB = 256 KiB, the §9 M1b tile keyed `(generation, edge_classid)` — +then one `mask_and` per facet + scatter), `gather` (the scalar row walk on +AosRows, the access-shape baseline, not a candidate). `LATEST_STATE.md` +entry with the full table. No ABI symbol, no Java change. + +**Measured** (Xeon 2.10 GHz, `avx512f=true`, release, median of 7, two +runs, every output `black_box`ed inside its timed closure): cache build +843–930 µs; cached **14.4–15.0 / 31.8–33.0 / 96–100 / 159–196 / +903–1 056 µs** across rand7 / rand655 / classid / hop2 / all, against +recompute 728–1 779 µs — break-even **0.9–1.3 hops** at every frontier. + +**Locked.** *A store generation's predicates do not change between hops; +re-deriving them per hop is 64 contiguous 256 KiB passes for nothing.* The +scatter is `O(N/64 + selected bits)` per facet (it walks every word of +`selected` before it can know which are empty), not O(frontier) — +CodeRabbit's correction, carried into the doc and the board. + +**Deferred.** Invalidation cost (a write to any classid/hi32 lane drops all +32 masks — the registry already does this wholesale for `cached_carving`); +the per-`edge_classid` multiplication of the 256 KiB; and the operator's +actual question — inside the random-access scatter walk, decide a visited +row's 32 facets with one zmm `mask_cmpeq_epi32` per 4 facets (8 loads) or +one xmm compare per facet, instead of the scalar 64-load / 64-branch loop +(`gather_xmm` / `gather_zmm_row`, named, not built). + +**Review.** Codex P1 (timed closures returned `()`, outputs unread — LLVM +could drop the scatter stores): fixed, re-measured, every number held. +CodeRabbit: the O(frontier) claim, fixed; docstring-coverage warning +(40 %) on private helpers, not addressed. Bugbot: usage limit, no run. + +**Confidence.** HIGH on the numbers (two runs, ranges banked). The +access-granularity arms are unmeasured; the door is named, not opened. + ## PR #77 — first CI lint gate: fmt + clippy + rust-test, Rust pinned to 1.98.1 (opened 2026-09-05, head `6d4b1a2`) **Added.** `.github/workflows/lint.yml` (three jobs: `format`, `clippy`, From 1899e45097e76a38c9f15ba4f496f1c73b1ab75f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 19:36:09 +0000 Subject: [PATCH 2/3] =?UTF-8?q?hop=5Fcached=5Fvs=5Fgather:=20break-even=20?= =?UTF-8?q?prose=201.0=E2=80=931.4=20=E2=86=92=200.9=E2=80=931.3,=20matchi?= =?UTF-8?q?ng=20the=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit on #79 (posted as it merged): the re-measured rows span 0.9–1.3 hops; the sentence above the table still carried the first run's 1.0–1.4. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01DCfrD5y19cvFc4AoyydXYv --- native/lgj-abi/examples/hop_cached_vs_gather.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/lgj-abi/examples/hop_cached_vs_gather.rs b/native/lgj-abi/examples/hop_cached_vs_gather.rs index eb6f4ea..6b6077e 100644 --- a/native/lgj-abi/examples/hop_cached_vs_gather.rs +++ b/native/lgj-abi/examples/hop_cached_vs_gather.rs @@ -32,7 +32,7 @@ //! | hop2 | 6 943 | 12 125 | 1 019–1 102 | **159–196** | 705–758 | 0.9–1.1 hops | //! | all | 65 536 | 56 841 | 1 630–1 779 | **903–1 056** | 3 583–3 863 | 1.2–1.3 hops | //! -//! **The cached tile pays for itself on the second hop** (break-even 1.0–1.4 +//! **The cached tile pays for itself on the second hop** (break-even 0.9–1.3 //! hops at every frontier): a store generation's predicates do not change //! between hops, and the shipped body re-derives them with 64 contiguous //! 256 KiB passes per hop. What remains per hop is one 8 KiB `mask_and` per From ac0a2a5ab873295866673cd3d7e3481b4954aa5f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 19:38:23 +0000 Subject: [PATCH 3/3] board: mark the #79 arc entry as a post-merge backfill (Codex P2 on #80) The entry was reconstructed after the merge, not written at open; the inventory's own header promises entries at merge time from #4 onward, so presenting it as contemporaneous would conceal the lapse. Storno-style note added above the entry; the entry itself is unchanged. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01DCfrD5y19cvFc4AoyydXYv --- .claude/board/PR_ARC_INVENTORY.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index 4b5ce18..7158ff0 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -10,6 +10,13 @@ ## PR #79 — `hop_cached_vs_gather`: the M1b tile pays off on hop two; the scatter walk is the access-shape question (opened 2026-09-16, merged `9cb63e9`, head `c10029b`) +> **Post-merge backfill, owned (2026-09-16):** this entry was NOT written at +> open. #79 was opened and merged without its arc entry — the same lapse the +> header above records for PRs #1–#3 — and the entry below was reconstructed +> after the merge in PR #80 (Codex P2 on #80 named the omission). Read it as a +> reconstruction, not as a record made with the change; the numbers are the +> ones banked in the probe's module doc and `LATEST_STATE.md` at merge time. + **Added.** `native/lgj-abi/examples/hop_cached_vs_gather.rs` — `lgj_hop`'s selection three ways at 65 536 rows × 32 facets, every arm asserted bit-identical on every frontier before timing: `recompute` (the shipped