|
| 1 | +## 2026-09-14 (5) — STORNO on entries (3) and (2), from the #307 council (measurement-skeptic, kernel-membrane, overclaim): same numbers, tighter words |
| 2 | + |
| 3 | +The numbers stand; the wording ran past them. Corrections, each to the sentence it replaces: |
| 4 | + |
| 5 | +- (3) *"full-field −14 %"* → **−5 % to −14 % across two runs** (14 517 vs 16 944 and 16 507 vs 17 462): within this density's cross-run noise, i.e. no reliable full-field win over the per-bit loop. The table pinned the better run. |
| 6 | +- (3) *"node-span −66 % (n 17.0 → 5.7 µs)"* → **on this fixture (frontier confined to one 64-word level-1 tile, 1/16 of the field, 29 % of the tile span), restricting the shifts to the tile span cuts the x=0 STEP from 16.9 to 5.7 µs (−66 %, one run).** It is a step ratio, not an op ratio: every arm still carries the full-field housekeeping (scratch zeroing, `OR2_AND`, the reverse walk over 1024 words) AND the probe's own per-rep reset — the `rails_run` copy is **786 KiB** (65 536 × 12 B), not the "8 KiB" the probe comment said (fixed), ~1 µs per step amortized inside every `n`. A frontier straddling k nodes pays Σ spans. |
| 7 | +- (3) *"the ratio survives the degree-1 ablation"* → **a −33 % gain survives** (4 487 vs 6 704); the ratio halves. What the ablation shows is that the word op's advantage is not hex-specific; the other half of the degree-6 gain scales with the per-bit loop's direction count. |
| 8 | +- (3) *"remaining 5.7 µs is the field-wide housekeeping"* → housekeeping **plus** the reset amortization; neither is separated. |
| 9 | +- (3) *"delta-frontier on top of the node span buys nothing (5.7 → 6.0)"* → no gain; the +0.4 µs is inside single-window noise, not a finding. |
| 10 | +- (2)/(3) *"coal = 8.9 µs = 0.48 maintained steps"* → **8.8–13.7 µs across three runs = 0.47–0.76 steps at x=4** (single window each). *"ternlogq 281 ns/pass"* → 280–300 across runs, max residual ≤ 2.8 %; the "1.7 % at x=1" is fit-derived. *"228–462×"* range-reveal ratio → ~200–490× across three runs at N = 65 536; the range arm's floor is the 8 KiB output clear. |
| 11 | +- (3) *"68/68 gates"* → 68/68 probe ROWS pass the three spread gates on one fixture and one seed. *"1.8 % density"* → 1.8 % of the field, **29 % of the tile span** — the denominator that explains why the word op loses full-field and wins node-span. |
| 12 | +- Method: one 50 ms window per cell, no repeats, no variance reported; cross-run spread is visible only because three runs were banked (ladder x=0 spread 3 %, `shift` 14 %, coal 56 %). Single-fixture observations, all of them. |
| 13 | +- Kernel-membrane, on `mask_shift_morton`: the slice IS the field — a sub-span shift is NOT the restriction of the full-field shift (no carry crosses the span edge). The probe's node arm was correct only because a level-1 tile is Morton-aligned and the source is confined to it; that law is now on the op's doc and the probe asserts `lo % len == 0` at the call site. The op is a lattice axis shift (four Cartesian moves; hex diagonals are two-call compositions), renamed as such in its docs. |
| 14 | +- Codex P2 on the probe: the Hebbian reverse walk credited any predecessor in the accumulated `state`; under the delta-frontier arms only `delta` cells propagated, so an older active neighbour of a newly reached cell could be credited for a firing it did not carry. Fixed (attribution against the step's SOURCE frontier, `delta` published after the walk) and **measured inert on this fixture — all 68 rows' fired/step and survivors identical before and after** — because eligibility is static here: an older predecessor's target was already settled when that predecessor was itself in the delta. Real for dynamic eligibility, unobservable in this probe. |
| 15 | + |
| 16 | +## 2026-09-14 (4) — D-MRX-0: `*_to_mask_under` — the gated predicate mask-risc's `Pred { under }` promised and T1 lacked |
| 17 | + |
| 18 | +**Why now.** lance-graph #1225's kernel-membrane review (PR2 council) ruled the |
| 19 | +executor may not compose a gated predicate from `*_to_mask` + `mask_and` (the |
| 20 | +whole plane, twice) nor skip words itself (a compute path above the facade): |
| 21 | +*"PR3 lands `*_to_mask_under` first."* This is that word. |
| 22 | + |
| 23 | +**Shape.** ONE private engine, `pack_under::<T, L>(name, values, under, out, |
| 24 | +group_bits)`: `out[w] = under[w] & pred(values)[w]`, the predicate evaluated |
| 25 | +only where `under[w] != 0`. The skip is word-granular (64 rows) — the unit |
| 26 | +the caller holds; a per-group skip is reachable and deliberately not done. An |
| 27 | +executor may skip coarser (mask-risc speaks of 1024-row chunks) with a result |
| 28 | +identical by construction (a skipped chunk is an all-zero gate) — not |
| 29 | +exercised by any test. COMPARE cost ∝ live gate WORDS (a sparse frontier |
| 30 | +spread across every word pays every compare); the per-word gate test and |
| 31 | +zero store stay ∝ rows/64; no timing of the skip exists, only the call count |
| 32 | +below. The predicate's own tail law makes a phantom gate bit past `n` vanish — |
| 33 | +the AND conforms regardless, so a gate never needs cleaning before use |
| 34 | +(surplus `under` words are never read). Ten public |
| 35 | +members, one per `Pred` variant (`gt/lt/ge/le/eq/ne_i32`, `eq/ne_u32`, |
| 36 | +`ternary_match_u32/u64`), each one `pack_under` call over the SAME lane op its |
| 37 | +ungated sibling uses — no new backend semantics, so no backend file changed. |
| 38 | + |
| 39 | +**Falsifiers.** (1) family ≡ `ungated & gate` word-for-word at ten lengths with |
| 40 | +phantom gate bits present; (2) the skip is MEASURED: a counting closure sees |
| 41 | +20 of 40 groups under an alternating gate, 40 under all-ones — disable-run |
| 42 | +red (`left: 40, right: 20`) with the `gate == 0` early-out removed, green |
| 43 | +restored (verified once, not re-runnable); (3) phantom bits do not leak at |
| 44 | +n = 70; (4) short gate panics; (5) each public member is ONE `pack_under` |
| 45 | +delegation, counted from the source, so the skip test on the private engine |
| 46 | +covers all ten; |
| 47 | +doctests 10/10. Parity harness group 10 (`0xAxx`, `check_predicates_under`): |
| 48 | +alternating-zero gate with random phantom bits, reference reads the gate BIT |
| 49 | +per row. Native (AVX2), nightly (`core::simd`), wasm simd128 and wasm scalar: all |
| 50 | +10/10 bit-identical here; neon has no qemu in this sandbox, and the |
| 51 | +`neon-simd/parity-qemu` CI job on #307 is the witness for that arm (green). |
| 52 | + |
| 53 | +**Allocation.** Engine + first member by the orchestrator; nine members + |
| 54 | +tests by a worker agent against a written spec (its Bash died on a full disk |
| 55 | +mid-run — the tasks tmpfs and the checkout share one allowance — so it landed |
| 56 | +Tasks A–C unverified and reported exactly that; the orchestrator gated |
| 57 | +centrally after freeing 6.5 GB of stale scratch targets and landed the parity |
| 58 | +arm itself). W1a deviation record as for `mask_andnot` / `mask_ternlog`: |
| 59 | +free-fn family shape beside its siblings, not a struct method. |
| 60 | + |
| 61 | +**Loose ends.** The strided operand family (12-in-16-byte register compares |
| 62 | +for `LaneRef`) and `u8/u16/u64` compare-to-mask (DuckDB matrix G1/G2) remain |
| 63 | +T1 gaps; neither is needed for PR3's first executor. |
| 64 | + |
| 65 | +## 2026-09-14 (3) — D-GTM-1m MEASURED: `mask_shift_morton` lands; the win is in the NODE SPAN, not the op — n = 17.0 → 5.7 µs (−66 %) |
| 66 | + |
| 67 | +`mask_shift_morton` (255c36d) is bit-exact (F1–F4, parity 9/9 on native/ |
| 68 | +nightly/wasm/wasm-scalar; neon-qemu absent here) — and over the FULL field it |
| 69 | +barely moves `n`: 14.5–16.5 µs vs 17.0 µs for the per-bit loop. The worker |
| 70 | +implementer named the mechanism correctly: the op is FIELD-size-bound (1024 |
| 71 | +words × ~8 passes per direction) while the per-bit loop is ACTIVE-bound, so at |
| 72 | +1.8 % density they cost about the same and the op loses once gates thin the |
| 73 | +frontier. |
| 74 | + |
| 75 | +**The fix is the fixed-spatial-distribution dividend a second time.** A trie |
| 76 | +node is a contiguous word span AND a square Morton sub-field (the level-1 tile = |
| 77 | +64 words = a 64×64 field, `log2(64)` even), so the shifts run over the node's |
| 78 | +own span with no correctness change (the source ⊆ tile, so no carry enters the |
| 79 | +span; a carry leaving it is what `& tile` removes anyway). Measured, dirs = 6, |
| 80 | +x = 0, same gates green (68/68 rows, 0 heap B/step): |
| 81 | + |
| 82 | +| arm | ns/step | vs ladder | |
| 83 | +|---|---|---| |
| 84 | +| ladder (per-bit, full state) | 16,944 | — | |
| 85 | +| nnue (per-bit, delta frontier) | 9,296 | −45 % | |
| 86 | +| shift (word op, full field) | 14,517 | −14 % | |
| 87 | +| **node (word op, tile span)** | **5,677** | **−66 %** | |
| 88 | +| node+g / node+nn / node+nn+g | 5,722 / 6,044 / 5,774 | — | |
| 89 | + |
| 90 | +Delta-frontier on top of the node span buys nothing (5.7 → 6.0), as predicted: |
| 91 | +a span-bound op does not care how many bits are set. Degree-1 control: node |
| 92 | +4.5 µs vs ladder 6.7 µs — the ratio survives the E-Q8 ablation, so the gain is |
| 93 | +the word op, not the six. The ternlog fit is unchanged (281 ns/pass, n = 17.0 µs |
| 94 | +on the ladder arm by construction). Remaining 5.7 µs is the field-wide |
| 95 | +housekeeping (scratch zeroing, `OR2_AND`, the Hebbian reverse walk over 1024 |
| 96 | +words) — the next rung restricts THOSE to the node span too and re-measures; |
| 97 | +not claimed here. |
| 98 | + |
| 99 | +Rule extracted: **a word-level op pays for the span it is given; give it the |
| 100 | +node, never the field.** The same statement as "top-down is a range, not a |
| 101 | +compare" (2026-09-14 (2)), now on the grey side. |
| 102 | + |
| 103 | +## 2026-09-14 (2) — D-GTM-0m: the hex TENANT — top-down traversal AND spread on ONE Morton-keyed SoA; `step = x·ternlogq + n` measured, and the chain is 1.7 % of it |
| 104 | + |
| 105 | +Probe: `examples/hex_tenant_mq_probe.rs` (`--release`, committed; output banked |
| 106 | +in the session scratchpad). Operator statement it builds (2026-09-14): *"static |
| 107 | +traversal top down AND plasticity (spread) in the same substrate — SoA gets a |
| 108 | +hex tenant with 6×2×8 bit and the field is a trie (fixed spatial distribution)."* |
| 109 | +This is `gemm-ternlog-mask-consolidation-v1.md` §9 M1/M1b/M2/M3 and §11.10 |
| 110 | +(`substrate == mask geometry == projection surface`) executed on the merged #306 |
| 111 | +facade, not argued. Substrate: 65,536 rows = 256×256 axial hex cells, **row = |
| 112 | +Morton(q, r)**, payload = the V3 12-byte register read `6×(u8:u8)` with rail `d` |
| 113 | += hex direction `d`, `u8:u8 = (permeability, strength)`. §9 R1 ("not obviously |
| 114 | +the same six") is resolved by construction: adjacency and carving ARE the same |
| 115 | +six once the rail index is the direction. Three gates, all green (32/32 cells): |
| 116 | +range reveal == TCAM reveal at every level/prefix; Morton-arm spread == an |
| 117 | +independent row-major axial BFS at every step (plasticity bytes compared too); |
| 118 | +hot-path heap = **0 B/step** everywhere (counting allocator). |
| 119 | + |
| 120 | +**White — top-down is a RANGE, not a compare.** A trie node at nibble level L is |
| 121 | +`2^(16−4L)` CONTIGUOUS rows, so revealing it is a range write: **49–99 ns** vs |
| 122 | +**22.4–22.8 µs** for the general `ternary_match_u32_to_mask` sweep over the |
| 123 | +address column — **228–462×**. That is the fixed-spatial-distribution dividend |
| 124 | +stated as a number: the TCAM op stays for addresses that are NOT laid out (the |
| 125 | +D-GTM-0l linker case); a minted, Morton-keyed tenant never pays it. |
| 126 | + |
| 127 | +**Grey — the cost model, fitted (identity gates, survivors held at 1175):** |
| 128 | +`step = x·ternlogq + n` with **ternlogq = 291 ns/pass** (8 KiB masks, 0.285 |
| 129 | +ns/word) and **n = 17.3 µs**, max residual 2.8 % over x ∈ {0,1,2,4,8,16,32}. |
| 130 | +So at x = 1 the chain is **1.7 %** of the step; even x = 32 only doubles it. |
| 131 | +`n` is the ONE non-mask op on the path — the per-active-bit hex shift (dilated- |
| 132 | +integer add per direction). **That is the missing substrate word**: a mask-level |
| 133 | +neighbour shift on the Morton lattice (`mask_shift_hex(state, d, dst)` — within |
| 134 | +a nibble a 4×4 block shift, carries across blocks), which would fold `n` into a |
| 135 | +handful of word passes. Filed, not built. First rung without it: the **NNUE |
| 136 | +reading** — spread from the DELTA frontier (`scratch & !state`), never from the |
| 137 | +accumulated state — gives the identical closure (gate green) at **8.8 µs** |
| 138 | +(−48 %), 8.4 µs with the real gates. The E-Q8 control is in the table (degree-1 |
| 139 | +arm: 7.0 µs, 301 survivors — a different closure, so a cost floor, not a cost |
| 140 | +equivalence). |
| 141 | + |
| 142 | +**Coal.** One re-chain (regenerate a resident mask from its column, |
| 143 | +`gt_i32_to_mask` over 256 KiB) = **8.9 µs = 30.6 ternlogq passes = 0.48 |
| 144 | +maintained steps** at x = 4. M2 is linear: x → x±1 is one pass (291 ns), no |
| 145 | +cliff. M1b generation (6 eligibility masks) = 75 µs once per mask generation. |
| 146 | +Plasticity: 740 rows' strength bytes bumped IN the register (1,263 firings over |
| 147 | +24 steps), on survivors only — the first version fired on every re-reached cell |
| 148 | +the gates then removed, which is the "fire before you know it survived" bug the |
| 149 | +reverse walk fixes. |
| 150 | + |
| 151 | +**Stated limits.** The T1 compare is i32-wide, so the u8 permeability column is |
| 152 | +widened 4× for `gt_i32_to_mask` — `n_gen` and coal are UPPER bounds; a u8/u16 |
| 153 | +compare-to-mask is a T1 addition. One fixture density (62 % permeable), one |
| 154 | +tile size, timing floor 50 ms, no `perf`. No production caller; this is W0. |
| 155 | + |
1 | 156 | ## 2026-09-14 — AVX2 arm of the mask family MEASURED, not rewritten: 6 of 10 shapes were already packed, 4 earned intrinsic realizations |
2 | 157 |
|
3 | 158 | **The pre-compaction plan was wrong, and the instrument said so before code |
|
0 commit comments