Skip to content

Commit a422063

Browse files
authored
Merge pull request #384 from AdaWorldAPI/ccr-45a41fb4-0j3i0l
Synergy map after #378–#383; guard symlink fix; stale mul_add doc
2 parents 2cbe131 + de61987 commit a422063

4 files changed

Lines changed: 270 additions & 4 deletions

File tree

‎.claude/hooks/facet-stride-guard.sh‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ print(ti.get("file_path") or ti.get("notebook_path") or "")' 2>/dev/null)"
217217
for f in "$@"; do f="${f#"$ROOT"/}"; [ -f "$f" ] && whole_file "$f" | check_lines "$f"; done
218218
;;
219219
--all)
220-
while IFS= read -r f; do whole_file "$f" | check_lines "$f"; done \
220+
# A tracked path can be a dangling symlink (crates/burn/src/*.rs point
221+
# into an absent ../upstream checkout); skip anything that is not a file.
222+
while IFS= read -r f; do [ -f "$f" ] && whole_file "$f" | check_lines "$f"; done \
221223
< <(git ls-files '*.rs' | while IFS= read -r f; do in_scope "$f" && echo "$f"; done)
222224
;;
223225
*) echo "usage: $0 --hook | --diff <rev> | --all | --file <path>..." >&2; exit 64 ;;
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
# Synergy map 2026-10-29 — since lance-graph #1591 and ndarray #378
2+
3+
**Status:** OPEN — exploration map. It decides nothing; the operator chooses.
4+
5+
**Base:** lance-graph `.claude/board/entries/2026-10-16-synergy-map-since-1579.md`
6+
(the last detailed mapping). That entry revised the 2026-10-11 fleet listing
7+
(`coresearch-2026-10-11-simd-fleet.md`: A–F, X1–X19). This map revises every
8+
point of it and adds what the merges since then closed or opened.
9+
10+
**Delta read:**
11+
- ndarray: #378–#383, all merged (`cadb572` … `2cbe131`), plus this PR.
12+
- lance-graph `main` `b272a1c`: 114 merges since 2026-10-16 18:00. Only the
13+
rows this listing tracks were re-read.
14+
- Fleet default branches, fetched 2026-10-29: lichess-rs `79af1ab`,
15+
tesseract-rs `7cbc969`, lance-graph-java `d8cdcc1`, OGAR `2a080a9`,
16+
MedCare-rs `fb829b6`, q2 `66281e7`, ladybug-rs `7f2cc38`, surrealdb
17+
`ef75a05`.
18+
19+
**Method:** Haiku cards did the harvests (§7). Every row marked CLOSED or
20+
LOOSE below rests on a line that was re-read on the main thread; rows marked
21+
"not re-read" are carried over unchanged.
22+
23+
## 0. What the six ndarray PRs did
24+
25+
| PR | closed | opened or left |
26+
|---|---|---|
27+
| #378 | wasm `F32x16`/`F64x8::mul_add` round once: certified fast domain, local repair, exact fallback. `+relaxed-simd` tested and identical. Proof obligations in `wasm-fma-proof-obligations.md` | `reduce_sum` order still differs per realization; no mechanised proof |
28+
| #379 | NaN-exclusion mindmap and premise audit (document) | S2 masked float fold, S3 `n_excluded` |
29+
| #380 | Palette512 / SM9 scalar probe; note corrected (tests run, VPDPBUUD exists) | its separate SIMD gate |
30+
| #381 | float lanes: presence IS NaN, held as a bijection (`not_nan_*_to_mask`, `nan_where_clear_*`, `presence_nan_mismatches_*`); SQL TRUE planes `{lt,…,ne}_{f64,f32}_to_mask`; `mask_not_under`; SM9 probe with the 3σ gate | the two-plane SM9 layout (superseded by #383) |
31+
| #382 | FACET STRIDE rule, guard and exclusions; `simd_stride::{lut_u8, lut9}` | burn-down list: 166 ndarray hits, 10 lance-graph hits |
32+
| #383 | DR512 P×M law: ONE presence/polarity bit (P=0,M=0 is the only NaN); `hpc::codec9` (`EpiLane9`, `Codec9::encode_touched`); `lut9` moved onto one plane; CI job `dr512/epistemic-presence` runs the 512-codeword, distance, WHERE-64K and ceiling oracles plus our probes | CausalEdge64 512-palette sidecar DEFERRED; LUT distance speed unmeasured |
33+
| this PR | guard `--all` skipped nothing on dangling symlinks (34 `crates/burn/src/*.rs` → absent `../upstream`), now skips them (count unchanged at 166); `wasm-simd-consumer-guide.md:206` said wasm `mul_add` rounds twice; mindmap records #383 | — |
34+
35+
## 1. The base listing, point by point
36+
37+
### A. `fearless_simd` vs `ndarray::simd`
38+
39+
| point | 10-16 | now | evidence |
40+
|---|---|---|---|
41+
| compile-time dispatch, no per-kernel runtime dispatch, v4-on-AVX2 SIGILL, 512-shaped names, SSE tiers, AVX2 integer polyfills | CLOSED | CLOSED | no change |
42+
| aarch64 guard | LOOSE | LOOSE | `cpu_guard.rs:318` still says it needs `getauxval(AT_HWCAP)`; the only `getauxval` call reads `AT_PHDR` (`:461-465`) |
43+
| generated backends | PARTIAL | PARTIAL | — |
44+
| per-level parity, 18 types | LOOSE | LOOSE, refined | of the 18, 16 never occur in `crates/simd-masking-parity/src/lib.rs`; `I16x32` occurs 7 times, `I8x64` once (counted, not judged as coverage) |
45+
| MSRV prose | LOOSE | LOOSE | lance-graph `ISSUES.md:472` `ISS-NDARRAY-CANONICAL-COORDINATE-COUPLES-FLEET-MSRV`: **Status: OPEN** |
46+
| one binary everywhere | EXCLUDED | EXCLUDED | — |
47+
48+
### B. "Three places the CPU leaks back"
49+
50+
| point | now | evidence |
51+
|---|---|---|
52+
| the build cares; runtime dispatch | CLOSED | — |
53+
| consumers inherit no config | CLOSED for lance-graph; LOOSE for lance-graph-java | lgj `native/lgj-abi/.cargo/config.toml:35` still says "one known host"; `check_build_cpu` has 0 hits on lgj `main`. The v4 hard-code was not re-read |
54+
55+
### C. Accelerate split — PARK, unchanged. ### E/F (SSE slow paths) — unchanged.
56+
57+
### D. Unsafe inventory
58+
59+
Unchanged: missing `// SAFETY:` comments, CONSOLIDATE / SAFE-API rows, the
60+
SAFE-CRATE (`bytemuck`/`zerocopy`) question. `is_x86_feature_detected!`:
61+
96 sites in 17 files (counted today), still unclassified into
62+
startup / once / per-call.
63+
64+
### Findings X1–X19 and TD rows
65+
66+
| id | 10-16 | now | evidence |
67+
|---|---|---|---|
68+
| X1, X7, X18 | CLOSED | CLOSED | X18 re-read: OGAR takes `encryption` from ndarray `branch = "master"` (`ogar-encryption/Cargo.toml:15`), the named-branch form the substrate law allows |
69+
| X2–X4 ladybug | LOOSE | **UNKNOWN** | a search on ladybug-rs `main` for `grep avx512f`, `x86-64-v2`, `config-v2` found nothing. Search is not evidence of a fix; read the image selector before closing |
70+
| X6 v4 Railway images | DECIDED | DECIDED | q2 `Dockerfile:227` still `-C target-cpu=x86-64-v4`; MedCare-rs: no `x86-64-v4` string found in Dockerfiles/toml/yml (not read; may have moved) |
71+
| X11 `mul_add` | LOOSE (doc pair contradicted) | **CLOSED** | `simd.rs:1319` "fused on every arm" now matches `simd_wasm.rs:37-40` (emulated, rounds once). The last stale doc, `wasm-simd-consumer-guide.md:206`, is fixed in this PR. lance-graph CP-3 (harvest 10-27) asked for a "parity statement": parity group `check_mul_add_single_rounding` plus the proof document is that statement |
72+
| X16 consumer raw intrinsics | LOOSE | LOOSE, **merged with the FACET STRIDE lance-graph hits** | lance-graph CP-2 (10-27) ADOPTED: `ndarray_bridge.rs` raw blocks sit under `cfg(not(feature = "ndarray-hpc"))` (13 occurrences), a non-default fallback. `TD-SIMD-SWEEP-W2` HALF DONE: `types.rs` migrated, `ndarray_bridge.rs` 66 raw lines left. The guard's 10 lance-graph R1 hits are exactly those blocks (8) plus holograph `hamming.rs:593-594` (2, live) — one burn-down, not two |
73+
| X17 forbidden remedies in records | PARTLY CLOSED | PARTLY CLOSED | still open: lichess-rs `CLAUDE.md:32,60`, `README.md:93-97`, `engine-adapter-stockfish/Cargo.toml:14,16` say `+1.95`; tesseract-rs `rust.yml:60` "ndarray's rust-version = 1.95 floor"; the MSRV issue |
74+
| X19 lgj | LOOSE | LOOSE | see B |
75+
| TD-NDARRAY-SIMD-POPCNT-NATIVE | (b) CLOSED | (b) CLOSED | (a) objdump and (c) the `Cargo.toml` comment not re-read |
76+
77+
## 2. The 10-16 dots D1–D8
78+
79+
| dot | 10-16 | now | evidence |
80+
|---|---|---|---|
81+
| D1 one set algebra, four spellings | LOOSE, hinge D-RA-2 | **CLOSED by decision and code** | D-RA-2 DECISION 2026-10-20 option A; D-CMR-1 shipped (#1644, relalg `normalize` delegates to `contract::set_algebra`); D-CMR-6 shipped (#1654, relalg `symbolic` delegates to `contract::set_rules`). crepe's join-body rewrites stay, by the decision |
82+
| D2 one preimage op | CLOSED AS VIOLATION | CLOSED | — |
83+
| D3 read masks × clustering × prefilter | LOOSE | not re-read | — |
84+
| D4 per-row truth lane terminal | LOOSE | LOOSE | D-NALP-4 "Partial, shipped (#1548)": scalar law exact on 2³² rows; whether a lane terminal is needed is open |
85+
| D5 one `Binder::code` | LOOSE | LOOSE | D-ASM-1b Queued, not authorized |
86+
| D6 SAG-5 | LOOSE | LOOSE | D-SAG-5-0 … -10 Queued / docs |
87+
| D7 two ndarray ids | CLOSED | CLOSED | — |
88+
| D8 doc drift | PARTLY CLOSED | PARTLY CLOSED | closed: X11 pair, consumer guide (this PR). Open: X19 lgj comment, MSRV issue option, lichess/tesseract comments |
89+
90+
## 3. The 10-16 synergies S1–S8
91+
92+
| | 10-16 | now | evidence |
93+
|---|---|---|---|
94+
| S1 one register, five reasoners | LOOSE | LOOSE, **unblocked** | its prerequisite D-CGW-1 shipped (#1594); D-CGW-13 Queued |
95+
| S2 wire gate = admission-as-mask | LOOSE | LOOSE, **new ndarray hook (N8)** | D-RPF-4 "Blocked (4 decisions; T1 LUT-weighted strided sum gap)" |
96+
| S3 three devices, one PCS | LOOSE | LOOSE | `ISS-QUALIA-A2B-CLUT-UNMEASURED` open; D-CGW-14 Queued (modulators only) |
97+
| S4 orientation, two readers | LOOSE | **CLOSED** | #1594: `causal_edge::Orientation` on 43..45; Moore `lift_ce64` refuses an oriented edge, so there is one table |
98+
| S5 Binder is the one bind surface | LOOSE | LOOSE | D-ASM-1b Queued |
99+
| S6 one address minting path | LOOSE | not re-read | — |
100+
| S7 `syllogize` writes 50..52 as `0b111` | LOOSE | LOOSE | the D-CGW-1 row says "46..49 (D-CGW-9) and 50..52 still open"; `syllogize` now lives in `edge_v3.rs` / `isa.rs`; whether 50..52 is still written as `0b111` was not read |
101+
| S8 triad readers to migrate | LOOSE | **CLOSED** | #1594 removed the S/P/O triad ("no production writer") |
102+
103+
## 4. New synergies since then (the dots between arcs)
104+
105+
**N1 — `lut9` and Codec9 have their first consumer, and it adds no kernel.**
106+
lance-graph `planner/src/nars/scent_learn.rs:49-50` imports
107+
`ndarray::hpc::codec9::EpiLane9` and `ndarray::simd::lut9` (D-EPI-COT C3c,
108+
TEST-PINNED). Its learning rate is the `lut9` table; its delta is built in
109+
code space with the same zero rule `lut9` applies to its output. The
110+
dependency direction is the right one: the consumer names ndarray words and
111+
grows none.
112+
113+
**N2 — one P×M rule, three homes, two with a pairing test.** The rule
114+
"absent = P=0 AND M=0; 9-bit P is also the sign; touched zero is +0" lives in
115+
ndarray `codec9.rs`, in lance-graph-contract `lane_codec.rs` (`EpiLaneSpec`,
116+
presence plane mandatory, a 9-bit lane must be Sym), and in the
117+
thought-layers probe (`write_epi`: a NaN lane is not written, merge on read
118+
keeps the prior). The contract tests that it "agrees with `codec9` on all 512
119+
codes" (`lane_codec.rs:993`). The third copy, `lance-graph-nsl/src/eval.rs:3-7`,
120+
mirrors Codec9 with a runtime scale and has no such test (the crate is
121+
dependency-free by design).
122+
123+
**N3 — the float bridge is one mask expression.** A DR512 lane's float
124+
presence is `P | ne_u8_to_mask(M, 0)`; its complement is "never touched".
125+
That is exactly the plane #381's `nan_where_clear_f32` consumes, so decoding a
126+
DR512 lane to f32 keeps #381's bijection with no new primitive. The probe test
127+
`decode_satisfies_the_float_bijection` already pins this end to end.
128+
129+
**N4 — NSL wants a runtime-scale, batch Codec9.** D-NSL-W0W1 kept "SM9 as a
130+
storage format for neighbor input features" as a PROBE (9-bit 2–4× better
131+
than int8) that "needs Codec9 runtime scale, batch encode, and a Cora-scale
132+
run first". ndarray's Codec9 is scalar and fixes the scale at compile time on
133+
purpose (`codec9.rs:18-21`: "Storage, polarity, Sym and NaN policy are
134+
intentionally NOT configurable … the only compile-time knobs are … rounding
135+
mode and scale calibration"). A runtime scale is therefore a ruling, not a
136+
patch. NSL also REJECTED SM9 edge weights as sort keys (top-1 changes for
137+
7–21% of seeds); that verdict stays.
138+
139+
**N5 — the "touched presence" word.** `scent_learn.rs:345-356` builds
140+
`P = present & (positive | (M == 0))` with a scalar loop over its features;
141+
`lut9` applies the same rule internally. With a batch encoder (N4) this would
142+
be the second writer of the same word; the facade could then name it
143+
(`present & (positive | eq_u8_to_mask(M, 0))`, two mask ops). One consumer
144+
today, so not yet.
145+
146+
**N6 — D-RPF-4's "T1 LUT-weighted strided sum gap" may already compose.**
147+
ndarray now has `lut_u8` (facet stride) and `masked_strided_group_sum`. A
148+
LUT-weighted strided sum is `lut_u8` into a weight lane, then the strided
149+
group sum. Whether that meets D-RPF-4's need is unread; a probe answers it
150+
before anyone builds a fused primitive.
151+
152+
**N7 — X16 and the FACET STRIDE burn-down are one job.** The 8 lance-graph
153+
R1 hits are the dead fallback blocks of `TD-SIMD-SWEEP-W2`; deleting or
154+
migrating them (to `U64x8::popcnt` / `ndarray::hpc::bitwise`) closes both
155+
lists at once. holograph `hamming.rs:593-594` is the only live one.
156+
157+
**N8 — the popcount question the rule raises.** All 7 ndarray R1 hits and all
158+
10 lance-graph R1 hits are the nibble-table popcount (`pshufb` over two 4-bit
159+
halves). On AVX-512 VPOPCNTDQ replaces it; on AVX2 there is no vector
160+
popcount, and the nibble table is the published fast method (Muła et al.).
161+
The FACET STRIDE rule forbids a lookup built from shuffles. The options are a
162+
per-u64 scalar `popcnt` (four per 256-bit register), or an exclusion with a
163+
reason. This needs a measurement on an AVX2 host before either is chosen.
164+
165+
**N9 — the NaN erasers stay the open hazard.** `quantize_f32_to_u8`
166+
(`hpc/quantized.rs:517`) and `quantize_f32_to_i8` (`:545`) still map NaN
167+
through a saturating cast; 14 call sites in ndarray, 4 in lance-graph. Under
168+
both rulings (float presence IS NaN, DR512 never-touched) they silently turn
169+
NULL into a value.
170+
171+
## 5. Closed ends, loose ends, fruit
172+
173+
### Closed since 10-16
174+
175+
1. X11 and its doc pair (#374, #378, this PR).
176+
2. D1 (D-RA-2 option A; #1644; #1654).
177+
3. S4 and S8 (#1594, D-CGW-1).
178+
4. H2 superseded: D-CGW-9 replaced by D-HL-1 O1 (46..49 = activation i4).
179+
5. NaN exclusion on float lanes (#381) and integer lanes (#383, one plane).
180+
6. FACET STRIDE rule, guard, audit (#382); guard symlink crash (this PR).
181+
7. `lut9` / Codec9 adopted downstream without a new kernel (N1).
182+
8. Palette512 probe corrected and kept as a CI tripwire (#380, #383).
183+
184+
### Excluded or rejected (do not reopen without new evidence)
185+
186+
- One binary everywhere (operator).
187+
- Runtime dispatch of core types.
188+
- Gather / preimage designs (D2, D-ASM-11/11A/11B, D-QMB-0…5: VIOLATION banners).
189+
- SM9 edge weights as sort keys (D-NSL-W0W1).
190+
- A second DR512 bit interpretation (Asym, Floor, NoNaN) for Codec9 (#383).
191+
192+
### Low-hanging (≤ 1 hour each)
193+
194+
| # | item | repo | check |
195+
|---|---|---|---|
196+
| L1 | lichess-rs `+1.95` (5 places) and tesseract-rs `rust.yml:60` comment → 1.99 | lichess-rs, tesseract-rs | doc only; needs push in those repos |
197+
| L2 | lgj: name the artifact tier, drop "one known host", call `check_build_cpu()` in the handshake | lance-graph-java | needs push approval |
198+
| L3 | NSL: a pairing test between its SM9 mirror and Codec9 semantics (512 codes, the -0.4/-0.5 ceiling cases), kept in NSL's own test data since the crate is dependency-free | lance-graph | the contract's `lane_codec.rs:993` test is the template |
199+
| L4 | restore the facet-stride paragraph in `lut9`'s doc (lost in #383's rewrite) | ndarray | doc only |
200+
| L5 | classify the 96 `is_x86_feature_detected!` sites (startup / once / per-call) as an inventory column | ndarray | grindwork for a Haiku census + Sonnet classification |
201+
202+
### High-hanging (a session each)
203+
204+
| # | item | why | gate |
205+
|---|---|---|---|
206+
| H1 | parity groups for the 16 never-named facade types | A | one flipped scalar op per group goes red |
207+
| H2 | aarch64 guard via `AT_HWCAP` | A | dotprod build under `qemu-aarch64 -cpu cortex-a53` reports, no SIGILL |
208+
| H3 | AVX2 popcount: scalar `popcnt` vs nibble table, measured, then migrate the 7 ndarray R1 hits or exclude them with the number as the reason | N8 | the faster one on a named AVX2 host; parity unchanged |
209+
| H4 | lance-graph `ndarray_bridge.rs` dead blocks deleted, holograph `hamming.rs` onto `ndarray::simd` | X16, N7 | guard reports 0 for lance-graph; holograph Hamming tests unchanged |
210+
| H5 | `quantize_f32_to_{u8,i8}`: refuse NaN or document the mapping; parity test that a NULL=NaN lane survives `Codec8 NaNAtMin` with zero mismatches | N9 | `presence_nan_mismatches == 0` after the round trip |
211+
| H6 | probe: does `lut_u8` + `masked_strided_group_sum` cover D-RPF-4's T1 gap | N6 | equals D-RPF-4's reference fold on its fixture |
212+
| H7 | D-CGW-13 first fixture (ONA + Java OpenNARS on one NAL fixture) | S1, now unblocked | two disagreeing oracles never project to equal edges |
213+
| H8 | S7: read whether `syllogize` still writes 50..52 as `0b111`; if so, give 50..52 its one meaning | S7 | field isolation on 50..52 |
214+
215+
### Heavy-hanging (multi-session, owner or ruling needed)
216+
217+
| # | item | why |
218+
|---|---|---|
219+
| V1 | runtime-scale, batch Codec9 (SIMD encode into magnitudes + presence plane) | N4: a ruling on #383's "only compile-time knobs" |
220+
| V2 | masked float fold with a fixed order, carrier `n, mean, M2` (mindmap S2), plus `n_excluded` (S3) | determinism ladder steps 2–3 |
221+
| V3 | DR512 comparisons without decode (`cmp` on P×M as masks) | waits for a consumer; lance-graph lance13 map X14 parks u8 `Pred` until one asks |
222+
| V4 | CausalEdge64 512-palette sidecar | DEFERRED by #383; lance-graph CE64 owner |
223+
| V5 | per-classid label codebook behind `Binder::code` (D-ASM-1/1b) | D5, not authorized |
224+
| V6 | D-NALP-5…7 | D4 |
225+
| V7 | SAG-5 on D-CMR | D6 |
226+
| V8 | Accelerate split, Kani, `bytemuck`/`zerocopy` | PARK |
227+
228+
## 6. Not searched
229+
230+
ladybug-rs image selector (search empty, not read); MedCare-rs deploy CPU
231+
flags (search empty, not read); lgj `.cargo/config.toml` lines 1–34 and 36+;
232+
S6 minting path; S7 `syllogize` body; D3; the 114 lance-graph merges beyond
233+
the rows above; stockfish-rs, HubSPO-rs, spear, a2ui-rs, surrealdb (fetched,
234+
not searched for these items; surrealdb's `ndarray = "0.17.2"` from crates.io
235+
is unchanged).
236+
237+
## 7. Harvest ledger (Haiku cards)
238+
239+
| card | task | result | spot check on the main thread |
240+
|---|---|---|---|
241+
| substrate-mapper | map of #383's six files | 172 entries, DONE | `codec9.rs` read in full; `:56` `NEVER_TOUCHED`, `:148` `encode_touched` match |
242+
| substrate-mapper | lance-graph consumers of SM9/Codec9 | 151 entries, PARTIAL (STATUS_BOARD too large to read whole; searched) | `scent_learn.rs:49-50` imports and `:345-356` zero rule re-read |
243+
| harvest-scout | NaN / presence / shuffle candidates in lance-graph | DONE, but ran on a stale local checkout (128 commits behind `main`) | its 10 `shuffle_epi8` hits match the guard's 10 lance-graph hits |
244+
| census-counter | guard counts, lance-graph grep counts | DONE; exposed the guard's symlink crash | crash reproduced; fixed in this PR |
245+
| census-counter | X-item status across 9 repos (18 commands) | DONE | `simd.rs:1319`, consumer guide `:206`, `cpu_guard.rs:318` re-read |
246+
| quote-harvester | six lance-graph board entries | DONE, 6/6 | NSL `:20-23` decisions re-read |
247+
| census-counter | board status rows for 20 IDs | DONE | `STATUS_BOARD.md:364,372,494,594`, `ISSUES.md:472`, `TECH_DEBT.md:1947,2274` re-read |
248+
249+
Misses: one (the stale-checkout scout; my brief named the local checkout
250+
before I had fetched `main`). No card miscounted or concluded.

0 commit comments

Comments
 (0)