diff --git a/.claude/board/EPIPHANIES.md b/.claude/board/EPIPHANIES.md index 8f9cf605a..f11ef1372 100644 --- a/.claude/board/EPIPHANIES.md +++ b/.claude/board/EPIPHANIES.md @@ -1,3 +1,75 @@ +## 2026-08-12 — E-ON-A-GOLDEN-LATTICE-LOCALITY-IS-FIBONACCI-MEMBERSHIP-1 + +**Status:** FINDING `[G]` — W5 RUN (`spiral_adi_probe.py`/`.json`) + a +targeted verification measurement, both committed. + +**The claim.** On a Vogel/golden lattice, a *local* non-Fibonacci control +for stride-structure experiments **does not exist** — not "is hard to +build," does not exist. Locality and Fibonacci-family membership are the +same property, by the three-distance theorem: a point's near neighbours in +physical space are exactly the points at convergent-denominator index +offsets, and for the golden angle the convergent denominators ARE the +Fibonacci numbers. + +**How three successive control designs discovered this by failing +differently.** W5's B3 control went through three generations, each +correcting the last: (1) strides 12/18 — wrong SCALE (connects points +nowhere near each other); (2) strides 1500/2600 — magnitude-matched but +still wrong scale in disguise (angular residues 0.05/0.11 vs the true +pair's 0.00028/0.00017 — two to three orders larger); (3) the +distance-matched shuffled-neighbour control — picks, per point, the REAL +nearest lattice neighbour closest in physical distance to the true partner, +excluding that partner. Generation 3 is the strongest possible local +control — and the RUN shows it changes nothing: anisotropy ratio +control/fib = **0.9996** (B3 bar: ≥1.5 → **VOID** by its own +pre-registered rule). + +**The diagnosis, then the verification — in that order.** The suspicion: +generation 3's "non-Fibonacci" partners are themselves Fibonacci-offset +points, because on this lattice there is nothing else nearby to pick. +Measured directly (N=62 208, family-A control links): **99.38 % of the +control's links have a Fibonacci |Δk|** — top offsets 233, 987, 610 +(all Fibonacci) and 1220 (= 2·610). The control never left the family. +The three-generation arc is therefore not a story of bad control design +but a **constructive proof sketch of the impossibility**: wrong-arithmetic +⟹ wrong-scale on a golden lattice, in both directions, because the +three-distance theorem couples the two. + +**Consequences.** +- **W5's B3 question ("does the smoothing depend on the strides being + Fibonacci?") is unanswerable BY A LOCAL CONTROL on this lattice** — and + that is the honest verdict, not a probe defect. What CAN be said: the + ADI smoothing quality is governed by local step geometry, and on a + golden lattice, having correct local step geometry and being + Fibonacci-linked are the same thing. +- **Companion to `E-A-CONTROL-THAT-CANNOT-LOSE-IS-NO-CONTROL-1` (below, + same day): that entry's failure mode is a control that cannot LOSE; + this one's is a control that cannot DIFFER.** Both carry zero + information when they "work" — and both were caught only because the + runs happened and the results were interrogated instead of banked. +- A genuine falsifier for the Fibonacci-dependence question would have to + leave locality: e.g. compare against a DIFFERENT lattice (jittered + grid, Halton) with its own natural neighbour structure under the same + stencil — deferred, scoped as a different experiment, not a fourth + control generation on the same lattice. + +**The positive results this run also delivered (recorded here since B3's +VOID would otherwise overshadow them):** **B2 PASS** at the headline +N=7 651 227 — iso-fit error **0.00053** against the 0.15 bar (≈280× +margin), anisotropy 1.213 vs the 1.25 bar: two Fibonacci-stride +tridiagonal sweeps DO approximate an isotropic 2D diffusion, which is the +load-bearing half for the domino.rs spiral-ADI design. **B4**: smooth +monotone improvement across the floor sweep (iso 0.44 → 0.0001 from n=8 +to n=19, N=52.4M), **no knee at n=17** — on this metric the operator's +17/21 floor reads as a comfortable safety margin, per the pre-registered +two-sided reading. Honest residual: the anisotropy asymptotes at **~1.213 +across three decades of N** (1.28/1.22/1.213/1.213 at n=12/14/17/19) — +an N-independent, structural ~21 % second-moment anisotropy of the +operator/geometry itself (band-restricted chains on polar geometry), not +a resolution artifact; it passes the 1.25 bar but does not tend to 1.0, +and any future tightening of that bar below ~1.22 would need this +mechanism addressed first. + ## 2026-08-12 — E-A-CONTROL-THAT-CANNOT-LOSE-IS-NO-CONTROL-1 **Status:** FINDING `[G]` — both instances measured this session, committed diff --git a/.claude/board/LATEST_STATE.md b/.claude/board/LATEST_STATE.md index 65d36aa0d..a22d9a859 100644 --- a/.claude/board/LATEST_STATE.md +++ b/.claude/board/LATEST_STATE.md @@ -855,6 +855,8 @@ Membrane consumers can now pull BOTH halves of a render `classid` BBB-safely fro | PR | Merged | Title | What it added | |---|---|---|---| | *gap note* | — | **#781–#925 are NOT in this table** — carried by the dated sections above + `PR_ARC_INVENTORY.md`. Recorded 2026-08-12 (codex P2 on #930) rather than silently reconstructed; the table had stalled at #780. | — | +| **#935** | 2026-08-12 | The validation wave RUNS: T1–T4 + W2s-a executed; `E-A-CONTROL-THAT-CANNOT-LOSE-IS-NO-CONTROL-1` | T2/T3/T4 PASS (68–106× at 200q; tempered 140/140 exact vs golden 124–127/140; 39.0 % naive-rounding collapse). T1 twice-corrected under codex review of its own run: verified-permanent m* = **1.9–2.7× q** (first-crossing 1.0–1.4× was not permanent; q=17: D*(22) back above the ceiling). W2s-a: G1 VOID, G2/G4 FAIL — the CONTROL is degenerate (two translated identical grids are symmetry-uniform, CV ~1e-12; cannot lose any evenness comparison). W5 pre-registered, run in flight at merge. | +| **#934** | 2026-08-12 | Board hygiene #932/#933 + storm-geography refinement | MIXED. Refinement, each claim measurement-grounded: centering = tempered territory (spiral center structurally sub-floor at any N; shipped `find_center` already exact-register); collision annulus = golden (Go/territory framing); overlay = controlled chaos at 12 B/node; self-description asymmetry (tempered up to q, golden unbounded). Task causes the regime, geography sorts the tasks. Arc entry written one PR late, caught in #935's hygiene pass. | | **#933** | 2026-08-12 | 4 codex fixes on merged #932 + `golden-vs-tempered-stride-v1` (head-vs-gut plan) | MIXED. Fixes: W5 bump sub-floor despite "fixed" N (local index = √(r²N), not √N → N=3·F(17)², bump r=0.75, bands 1–2 excluded); tie test redefined per-source (d1/d2 ratio); 17-TET sign convention unified; B3 control distance-matched (residue arithmetic exposed 1500/2600 as wrong-scale in disguise). Plan: T1 crossover at m≈q across 8 q; T2 golden 68–106× ahead at m=200q; T3 tempered fills q/q by proof vs golden 124/140 at q=140; T4 naive φ-rounding collapses at 39 % of q∈[8,300). "Best stride" declared metric-dependent (3 metrics → 3 different winners at q=17). | | **#932** | 2026-08-12 | Golden-ratio index floor (≥17/21) + temperament mechanism; W5/W2s-a re-specced before any worker ran | Merged BEFORE its own 4 review findings could be addressed (fixed in #933). Floor: F-convergents behave like φ only from n≈17–21 (err 1.5e-4 → 1.8e-7 → 3.7e-9); emergent parastichy pair ≈ √N ⇒ N ≳ F(17)². Mechanism: temperament — coprime closure + distributed comma (12 fifths miss by +23.46 ct; 17-TET fifth exact by construction, +3.93 ct/fifth spread) = D-QUANTGATE's anti-moiré dither. `E-THE-GOLDEN-STEP-IS-THE-WRONG-STEP-AT-SMALL-Q-1` + `ISS-HELIX-GOLDEN-STEP-LABEL`. Chat-register quotes paraphrased out of all committed artifacts (12 sites). | | **#930** | 2026-08-12 | #929 hygiene → grew into an open-review sweep of #920–#930 + report §10 (product-lead program) + `weather-w-probes-v1` (Sonnet worker briefs) | MIXED (started as pure hygiene, corrected its own description twice per the #927 lesson). Sweep found 3 ledger figures wrong (R² "5th decimal" claim, "10 probes" undercount, "+13/−0,+10/−0,+0/−0" audit figures) and replaced the append-only audit itself (zero-deletions → suffix check, both halves measured, the new check correctly flags this very PR). §10 = measurement standard + dipole vector-sum model incl. stranded-storm regime + corridor α + queue-and-bow + sunflower/spiral-ADI substrate. Worker briefs W5/W2s-a/W6 ready; CT-F17 gated on W6 + independent adversarial audit. See sweep entry, `.claude/board/PR_ARC_INVENTORY.md` for the correction table — the figures in #928's/#929's rows below are SUPERSEDED by that entry, not edited in place. | diff --git a/.claude/board/PR_ARC_INVENTORY.md b/.claude/board/PR_ARC_INVENTORY.md index eebfe94ca..9f29a2949 100644 --- a/.claude/board/PR_ARC_INVENTORY.md +++ b/.claude/board/PR_ARC_INVENTORY.md @@ -54,6 +54,88 @@ **Status:** MERGED (`e6e27829`). Branch `claude/jirak-math-theorems-harvest-rfii13` → `main`. Doc/plan/board only. +## 2026-08-12 — lance-graph #935 (MERGED) — the validation wave RUNS: T1–T4 + W2s-a executed, four more defects caught, one new epiphany + +- **Added.** `golden_vs_tempered_probe.py`/`.json` (T1–T4 executed against + the pre-registered bars — committed with bars BEFORE running, then run, + then corrected under review, per the standing discipline) and + `sunflower_pairing_probe.py`/`.json` (W2s-a executed: headline + N=F(17)²=2 550 409 per lattice + the G4 floor sweep to n=19, + N≈17.5M). `spiral_adi_probe.py` (W5) committed pre-registered; its RUN + was still in flight at merge time — results land in a follow-up PR. + EPIPHANIES: **`E-A-CONTROL-THAT-CANNOT-LOSE-IS-NO-CONTROL-1`**. +- **Locked — the verdicts, honestly split.** **T2 PASS** (golden 68–106× + ahead at m=200q, all 10 q — exposed to none of the four bugs, since it + was always a single fixed-point comparison). **T3 PASS** (tempered + 140/140 by exact integer arithmetic; golden 124–127/140 across 5 + phases). **T4 PASS** (39.0 % naive-rounding collapse rate). **T1 + twice-corrected**: the verified-permanent crossover is **1.9–2.7× q**, + not the first-drafted ~1.0–1.4× — golden needs roughly TWO tempered + cycles before its lead is durable. **W2s-a: G1 VOID (its own + pre-registered escape hatch), G2/G4 FAIL — and the FAIL is a fact about + the CONTROL, not the golden lattice**: two identically-constructed grids + differing only by translation are symmetry-uniform in cross-nearest- + neighbour distance (CV ≈ 1.6e-12 vs golden's 0.368, invariant under four + center offsets, diagnosed by a 0.1 s smoke test BEFORE the 2.55M run, + then run as-specified so the record shows the specified control failing + rather than a quiet redesign). +- **Locked — the epiphany.** A control that cannot lose is as vacuous as a + test that cannot fail; the falsifiability rule's can-it-fire doctrine + extends to CONTROL ARMS. Two instances in one afternoon: the symmetric + grid (cannot lose any evenness comparison) and T1's first-crossing m* + (an implicit never-reverses claim with no machinery to check it — + codex's reproduced counterexample: q=17 reported m*=21, D*(22) back + above the ceiling). Corollaries banked: *a control must be able to + lose* (check for symmetry/degeneracy/construction-identity before + pre-registering); *"permanently" is a suffix claim needing verification + with a STATED scope* (checkpoint counts now reported beside every m*); + *smoke-test the control's losability cheaply before paying for the full + run*. +- **Fixed in-flight (codex on this very PR's run results).** (P2) the + useful-range floor used `q//2` where the spec says `⌈q/2⌉` — every odd q + admitted one sub-range prefix; single shared helper now. (P1) m* was a + first-crossing search reported as permanent — replaced by + `verified_permanent_crossover` with sampled-suffix verification. Also a + self-caught commit-message falsity: one commit claimed "D-GVT-T1 row + updated" when only D-W2sA had been edited — caught by checking the + message's claims against the tree right after pushing, fixed in the next + commit with the discrepancy named. +- **Deferred.** W5's run result (in flight at merge). W6 (needs ~40 WB2 + chunks — next fetch-bearing step). An honest evenness falsifier for + W2s-a (offset/rotation-varied or spacing-mismatched control). The G4 + note that 3-in-3.15M near-ties at n=19 reflect the fixed 1e-6 tolerance + meeting large-N sampling density, not a mechanism failure. +- **Confidence.** High on every number (all from committed scripts + + JSONs); the T1 crossover figure specifically carries a three-revision + history, each widening, documented in the plan rather than smoothed. + +**Status:** MERGED (`a378136a`). Branch `claude/jirak-math-theorems-harvest-rfii13` +→ `main`. Probes + results + board — zero product code. + +## 2026-08-12 — lance-graph #934 (MERGED) — board hygiene for #932/#933 + the storm-geography refinement (entry written late, from #935's post-merge pass) + +- **Added.** Arc entries + shipped rows for #932/#933, and the plan's + §Synthesis **storm-geography refinement** (operator, paraphrased), each + claim grounded in an existing measurement: (1) **centering is tempered + territory** — a golden lattice's center is structurally sub-floor at any + N (`√(r²N) → 0`), and the shipped `find_center` is already an exact grid + argmin + quadratic sub-grid fit, now stated as doctrine (never sample + the center from the spiral whose center is its own worst data); (2) **the + collision annulus is golden territory** — territory-gain/Go framing, + addresses self-describing outward; (3) **overlaying collision lattices = + controlled chaos at near-zero storage** — aperiodic yet fully + deterministic from two center coordinates, a node costs exactly its + 12-byte facet; (4) **the self-description asymmetry in one sentence** — + tempered self-describes exactly up to q, golden for every k indefinitely. + Demarcation kept: the TASK causes the regime, the geography merely sorts + the tasks. +- **Hygiene note.** This entry itself was written one PR late — #934 merged + and the operator's "run tests to validate" directive rightly took + priority; the omission was caught during #935's post-merge hygiene pass + and is recorded here rather than backdated. + +**Status:** MERGED (`96dc5bfe`). Doc/plan/board only. + ## 2026-08-12 — lance-graph #933 (MERGED) — 4 codex fixes on #932 + golden-vs-tempered-stride-v1 (head-vs-gut, made falsifiable) - **Added.** `.claude/plans/golden-vs-tempered-stride-v1.md` — standalone, diff --git a/.claude/board/STATUS_BOARD.md b/.claude/board/STATUS_BOARD.md index 3a435d6fa..cc56af84b 100644 --- a/.claude/board/STATUS_BOARD.md +++ b/.claude/board/STATUS_BOARD.md @@ -25,7 +25,7 @@ Wave 1 = parallel, no operator gate beyond go-ahead; gated rows named. | D-id | Deliverable | Wave | Status | Feeds | |---|---|---|---|---| -| D-W5 | Spiral-ADI anisotropy: Vogel N=4096, iso ≤0.15 & aniso ≤1.25, non-Fibonacci stride control ≥1.5× | 1 | Queued | domino.rs gather design; [H] flags §10.5 | +| D-W5 | Spiral-ADI anisotropy (final spec: N=3·F(17)²=7.65M, bump r=0.75, distance-matched control) | 1 | **RUN — B2 PASS (iso 0.00053 vs 0.15, aniso 1.213 vs 1.25); B3 VOID structurally (control links are 99.38 % Fibonacci — three-distance theorem: locality IS family membership, `E-ON-A-GOLDEN-LATTICE-LOCALITY-IS-FIBONACCI-MEMBERSHIP-1`); B4 smooth, NO knee at n=17 (floor = safety margin on this metric, per the pre-registered second branch)** | domino.rs gather design UNBLOCKED by B2; honest residual: structural ~21 % aniso asymptote flagged for any bar below 1.22 | | D-W2sA | Golden-vs-grid pairing on real cos-lat metric (zero-ties G1, CV G2) | 1 | **RUN — G1 VOID, G2/G4 FAIL (control degenerate: two identical translated grids are symmetry-uniform, CV ~1e-12 — cannot lose any evenness comparison; diagnosed via smoke test, run as-specified, `E-A-CONTROL-THAT-CANNOT-LOSE-IS-NO-CONTROL-1`)** | honest falsifier for evenness DEFERRED (offset/rotation-varied or spacing-mismatched control); §10.5 properties 1–3 untouched | | D-W6 | Two-component deconvolution (geo + bow, global lstsq, 38 eqs / 2 params; B3 = stranded stratification via v_rel) | 1 | Queued | dipole vector-sum identification; F17 gate | | D-W2sB | α-window sweep β∈[0.85,1.15] | gated (W2s-a) | Queued | corridor α discriminator | diff --git a/.claude/plans/weather-w-probes-v1.md b/.claude/plans/weather-w-probes-v1.md index f3662c130..ed53db54c 100644 --- a/.claude/plans/weather-w-probes-v1.md +++ b/.claude/plans/weather-w-probes-v1.md @@ -272,6 +272,52 @@ verdicts: {B2, B3, B4}}`. --- +### RUN, 2026-08-12 (`spiral_adi_probe.py` / `.json`) — B2 PASS, B3 VOID (structurally, with the diagnosis verified), B4 smooth with no knee + +| bar | verdict | measured | +|---|---|---| +| **B2 ISO** (headline N=7 651 227) | **PASS** | iso-fit rel-L2 **0.00053** vs the 0.15 bar (≈280× margin); anisotropy **1.2134** vs the 1.25 bar | +| **B3 CONTROL** | **VOID** (its own pre-registered rule) | ratio control/fib = **0.9996** vs the ≥1.5 bar — the distance-matched control smooths identically | +| **B4 floor sweep** | run in full, n=8..19 (n=21 NOT RUN per budget, recorded) | iso 0.4405 → 0.1004 → 0.0245 → 0.0057 → 0.00053 → 0.0001; aniso 6.55 → 1.65 → 1.28 → 1.223 → 1.2134 → 1.2129 | + +**B3's VOID is structural, and the diagnosis was VERIFIED before being +written down** (`E-ON-A-GOLDEN-LATTICE-LOCALITY-IS-FIBONACCI-MEMBERSHIP-1`): +measured at N=62 208, **99.38 % of the control's links have a Fibonacci +|Δk|** (top offsets 233, 987, 610, plus 1220 = 2·610). On a Vogel lattice +the near neighbours ARE the Fibonacci-offset points (three-distance +theorem: physical proximity ⟺ convergent-denominator index offset), so a +distance-matched local control CANNOT leave the family — the third control +generation didn't fail at its job, it proved the job impossible. The +Fibonacci-dependence question is unanswerable by any local control on this +lattice; a genuine falsifier must change the lattice (jittered grid / +Halton under the same stencil), deferred as its own experiment. + +**B4's two-sided pre-registered reading lands on the second branch:** the +curve improves smoothly and monotonically from n=8 through n=19 with **no +knee at n≈17** — on this metric the index floor is a **safety margin, not +a mechanism**, exactly the outcome the §0 rule said must be reported +plainly if measured. (The floor retains its independent justification from +the convergent-error ladder and the T1/T2/T3/T4 duel results; what this +sweep shows is that the ADI smoothing quality specifically does not +exhibit a threshold at the floor.) + +**Honest residual, flagged for any future bar-tightening:** anisotropy +asymptotes at **~1.213 across three decades of N** (n=12→19) — an +N-independent structural ~21 % second-moment anisotropy of the +band-restricted polar chain geometry itself, not a resolution artifact. +It passes the 1.25 bar; a future bar below ~1.22 would need this +mechanism addressed first, not more points. + +**Two implementation notes a rerun should know:** the qualifying-band rule +(inner radius ≥ r_floor) resolves to **bands 4–8**, and the brief's older +"bands 3–8" label is off-by-one against its own parenthetical (the rule +wins). Discovery found the expected emergent pairs per band — +[2584, 4181] = F(18)/F(19) in the qualifying bands at the headline N, with +the inner (excluded) bands showing the lower-index transition exactly as +the parastichy-index arithmetic predicts. + +--- + ## §2 BRIEF W2s-a — golden two-lattice pairing on REAL lat/lon geometry (Sonnet, zero fetch) **File:** `sunflower_pairing_probe.py`. **Seed:** 20260812. **No network.** diff --git a/probes/weather-p1/spiral_adi_probe.json b/probes/weather-p1/spiral_adi_probe.json new file mode 100644 index 000000000..07a051a53 --- /dev/null +++ b/probes/weather-p1/spiral_adi_probe.json @@ -0,0 +1,292 @@ +{ + "headline": { + "n_idx": 17, + "N": 7651227, + "r_floor": 0.5773502691896258, + "qualifying_bands": [ + 4, + 5, + 6, + 7, + 8 + ], + "strides": { + "1": [ + 987, + 1597 + ], + "2": [ + 1597, + 2584 + ], + "3": [ + 1597, + 2584 + ], + "4": [ + 2584, + 4181 + ], + "5": [ + 2584, + 4181 + ], + "6": [ + 2584, + 4181 + ], + "7": [ + 2584, + 4181 + ], + "8": [ + 2584, + 4181 + ] + }, + "stride_top5_band5": [ + [ + 2584, + 7971 + ], + [ + 4181, + 7958 + ], + [ + 6765, + 7939 + ], + [ + 10946, + 7910 + ], + [ + 8362, + 90 + ] + ], + "crossing_angles": { + "1": { + "median_deg": 52.28616785668392, + "iqr_deg": [ + 40.824243543793756, + 68.99164896503665 + ] + }, + "2": { + "median_deg": 56.959628254106846, + "iqr_deg": [ + 50.561996954515536, + 65.4480533380746 + ] + }, + "3": { + "median_deg": 36.91067064023271, + "iqr_deg": [ + 33.97795417304726, + 40.640023983675434 + ] + }, + "4": { + "median_deg": 62.2992236100756, + "iqr_deg": [ + 59.2701858000263, + 65.85510053756052 + ] + }, + "5": { + "median_deg": 51.22307683517869, + "iqr_deg": [ + 48.89964320494506, + 53.6702644589433 + ] + }, + "6": { + "median_deg": 43.169027332934036, + "iqr_deg": [ + 41.535185291390576, + 44.974928031392864 + ] + }, + "7": { + "median_deg": 37.296378715533194, + "iqr_deg": [ + 36.07858869780451, + 38.65892819158141 + ] + }, + "8": { + "median_deg": 32.797387686142656, + "iqr_deg": [ + 31.77588053357195, + 33.82374906190599 + ] + } + }, + "fib": { + "aniso": 1.2133704271386727, + "iso_rel_l2": 0.000531146335896528, + "sigma_ref": 0.08, + "amplitude": 0.9998296702272748 + }, + "control": { + "aniso": 1.2128492673045226, + "iso_rel_l2": 0.0043580045257184145, + "sigma_ref": 0.08, + "amplitude": 0.9999676829776998 + }, + "aniso_ratio_control_over_fib": 0.9995704857951919 + }, + "sweep": [ + { + "n_idx": 8, + "N": 1323, + "qualifying_bands": [ + 4, + 5, + 6, + 7, + 8 + ], + "fib": { + "aniso": 6.550475179352178, + "iso_rel_l2": 0.4404837665749021, + "sigma_ref": 0.16677966101694913, + "amplitude": 0.2689536925373855 + }, + "control": { + "aniso": 6.095688827508773, + "iso_rel_l2": 0.4732845453823644, + "sigma_ref": 0.13966101694915253, + "amplitude": 0.3368345392568036 + }, + "aniso_ratio_control_over_fib": 0.9305720059398221 + }, + { + "n_idx": 10, + "N": 9075, + "qualifying_bands": [ + 4, + 5, + 6, + 7, + 8 + ], + "fib": { + "aniso": 1.6505857060824627, + "iso_rel_l2": 0.10043483184160697, + "sigma_ref": 0.09084745762711864, + "amplitude": 0.7920953474210749 + }, + "control": { + "aniso": 1.5044745699165143, + "iso_rel_l2": 0.11989375903383313, + "sigma_ref": 0.08813559322033898, + "amplitude": 0.8417567835585169 + }, + "aniso_ratio_control_over_fib": 0.9114792187842631 + }, + { + "n_idx": 12, + "N": 62208, + "qualifying_bands": [ + 4, + 5, + 6, + 7, + 8 + ], + "fib": { + "aniso": 1.2816729521408852, + "iso_rel_l2": 0.024501112922115414, + "sigma_ref": 0.08271186440677966, + "amplitude": 0.949155201617418 + }, + "control": { + "aniso": 1.2772997073940147, + "iso_rel_l2": 0.031202030128976373, + "sigma_ref": 0.08271186440677966, + "amplitude": 0.9526491768136327 + }, + "aniso_ratio_control_over_fib": 0.9965878621846818 + }, + { + "n_idx": 14, + "N": 426387, + "qualifying_bands": [ + 4, + 5, + 6, + 7, + 8 + ], + "fib": { + "aniso": 1.222991180241266, + "iso_rel_l2": 0.005653896538414601, + "sigma_ref": 0.08, + "amplitude": 0.9969933972351945 + }, + "control": { + "aniso": 1.2231128961849835, + "iso_rel_l2": 0.007338811726399315, + "sigma_ref": 0.08, + "amplitude": 0.9974380152494843 + }, + "aniso_ratio_control_over_fib": 1.0000995231573897 + }, + { + "n_idx": 17, + "N": 7651227, + "qualifying_bands": [ + 4, + 5, + 6, + 7, + 8 + ], + "fib": { + "aniso": 1.2133704271386727, + "iso_rel_l2": 0.000531146335896528, + "sigma_ref": 0.08, + "amplitude": 0.9998296702272748 + }, + "control": { + "aniso": 1.2128492673045226, + "iso_rel_l2": 0.0043580045257184145, + "sigma_ref": 0.08, + "amplitude": 0.9999676829776998 + }, + "aniso_ratio_control_over_fib": 0.9995704857951919 + }, + { + "n_idx": 19, + "N": 52442283, + "qualifying_bands": [ + 4, + 5, + 6, + 7, + 8 + ], + "fib": { + "aniso": 1.2128839037705261, + "iso_rel_l2": 0.00011915553240126285, + "sigma_ref": 0.08, + "amplitude": 0.9999750838721444 + }, + "control": { + "aniso": 1.212800932576421, + "iso_rel_l2": 0.001403899969162001, + "sigma_ref": 0.08, + "amplitude": 0.9999996339961671 + }, + "aniso_ratio_control_over_fib": 0.9999315918087073 + } + ], + "n21": "NOT RUN (N=3*F(21)^2 ~ 3.6e8, beyond budget; recorded per brief)", + "verdicts": { + "B2_iso": "PASS", + "B3_control": "VOID -- control smooths as isotropically as Fibonacci; the Fibonacci claim measures nothing" + } +} \ No newline at end of file diff --git a/probes/weather-p1/spiral_adi_probe.py b/probes/weather-p1/spiral_adi_probe.py index 038eedbe5..0f684f7d2 100644 --- a/probes/weather-p1/spiral_adi_probe.py +++ b/probes/weather-p1/spiral_adi_probe.py @@ -17,6 +17,26 @@ "r >= 0.6124"), and the brief's "bands 3-8" label is reported as the off-by-one it is rather than silently adopted. +V2 (2026-08-12, after four codex findings on PR #936 voided the v1 run's +verdicts -- committed BEFORE the v2 run, per the standing discipline): +(a) control links are built FULL-BAND (v1's 250k/band cap left ~74% of +headline sources as self-links and searched a thinned tree -- the v1 B3 +ratio measured mostly self-links, not the control); (b) iterations are +SCALED so the added blur is resolvable and PREDICTED: V = sigma^2/4 added +variance per axis, iters = 2V/h^2 with h^2 the measured median squared +nearest-neighbour spacing, so the fitted sigma_ref must land at +sqrt(sigma^2+V) -- an operator that does nothing now FAILS (v1's 8 +iterations at N=7.65M added ~0.003% variance: near-identity, and identity +fits the input Gaussian perfectly -- v1's B2 "pass" never demonstrated +diffusion); (c) the bump moved to sigma=0.05, r0=0.78 (>=3.35 sigma from +both mask edges; v1's 1.72-sigma inner clearance meant the mask ITSELF +produced a 1.208 covariance ratio -- confirmed analytically against the +measured 1.213 "asymptote", i.e. v1 measured the mask, not the operator) +and the UNSMOOTHED-baseline anisotropy through the same mask is now +computed and the verdict taken on the CHANGE; (d) the control-link +offset histogram is computed in-run and stored in the JSON (the 99.38% +Fibonacci-membership verification was previously chat-only). + B3 CONTROL IMPLEMENTATION NOTE (documented choice, same operator form both arms): the Fibonacci arm sweeps chains k -> k+j (prev = k-j, next = k+j, hold at open ends). The control arm replaces each point's next-partner with @@ -37,8 +57,9 @@ PHI = (1 + 5 ** 0.5) / 2 GOLDEN_FRAC = 2 - PHI F = {8: 21, 10: 55, 12: 144, 14: 377, 17: 1597, 19: 4181} -SIGMA = 0.08 -N_ADI_ITERS = 8 +SIGMA = 0.05 # v2: was 0.08; see header note (c) +R_BUMP = 0.78 # v2: was 0.75; >=3.35 sigma from both mask edges +ADDED_VAR = SIGMA ** 2 / 4.0 # v2: target added variance per axis (V) N_BANDS = 8 @@ -142,15 +163,20 @@ def build_fib_links(n, bands, strides, qualifying): return links -def build_control_links(x, y, n, bands, strides, qualifying, rng, - max_pts_per_band=250_000): - """B3 control links: for each point (subsampled per band if huge), the - control partner is the physically-distance-matched real neighbour - (among 8 nearest, closest in distance to the true Fibonacci partner's - distance, excluding that partner). prev = reverse map where uniquely - defined, else hold.""" +def build_control_links(x, y, n, bands, strides, qualifying, sel_qualifying, + rng): + """B3 control links, v2: FULL-BAND, no subsampling cap. v1 capped each + band at 250k points (headline bands hold ~956k each -- ~74% of sources + got no real tree, silently self-linked; codex P1 on PR #936) and built + the KD-tree only from the sampled subset, so even sampled sources + picked among sampled neighbours rather than their real 8 nearest. + Every point in every qualifying band now gets a real control partner. + Returns (links, offset_histogram) -- histogram is {|dk|: count} over + ALL control links in family A, the artifact codex P2 asked to be + committed rather than left as chat-only prose.""" idx_all = np.arange(n) links = [] + histA = None for fam in (0, 1): nxt = idx_all.copy() for b in qualifying: @@ -159,18 +185,13 @@ def build_control_links(x, y, n, bands, strides, qualifying, rng, continue j = info["pair"][fam] sel = np.where(bands == b)[0] - if len(sel) > max_pts_per_band: - sel = np.sort(rng.choice(sel, max_pts_per_band, replace=False)) tree = cKDTree(np.column_stack([x[sel], y[sel]])) d_nn, nn = tree.query(np.column_stack([x[sel], y[sel]]), k=9) - # true fib partner distance (where it exists in-band) tgt = sel + j ok = (tgt < n) ok[ok] &= (bands[tgt[ok]] == b) fibd = np.full(len(sel), np.nan) fibd[ok] = np.hypot(x[tgt[ok]] - x[sel[ok]], y[tgt[ok]] - y[sel[ok]]) - # choose among neighbours 1..8 the one closest in distance to fibd, - # excluding the true partner itself cand_global = sel[nn[:, 1:]] is_partner = cand_global == np.where(ok, tgt, -1)[:, None] dist_diff = np.abs(d_nn[:, 1:] - fibd[:, None]) @@ -179,7 +200,28 @@ def build_control_links(x, y, n, bands, strides, qualifying, rng, pick = np.argmin(dist_diff, axis=1) good = np.isfinite(dist_diff[np.arange(len(sel)), pick]) nxt[sel[good]] = cand_global[np.arange(len(sel)), pick][good] - # reverse map: unique preimage -> prev, else hold + if fam == 0: + moved = nxt != idx_all + dk = np.abs(nxt[moved] - idx_all[moved]) + vals, counts = np.unique(dk, return_counts=True) + order = np.argsort(-counts) + n_qual = int(sel_qualifying.sum()) + moved_in_qual = int((moved & sel_qualifying).sum()) + # self_linked_frac_overall is over ALL n points and is DOMINATED + # by non-qualifying-band points, which are never touched by + # design (a debugging trap found and fixed live: an earlier + # version of this histogram divided by n and reported ~38% "self + # -linked" that was almost entirely non-qualifying-band points + # correctly excluded, not a control-search failure -- see the + # _in_qualifying_bands figure for the number that actually + # matters). + histA = {"n_moved": int(moved.sum()), "n_total": int(n), + "n_qualifying": n_qual, + "self_linked_frac_overall": float(1.0 - moved.sum() / n), + "self_linked_frac_in_qualifying_bands": float( + 1.0 - moved_in_qual / n_qual) if n_qual else None, + "top10_offsets": [(int(vals[i]), int(counts[i])) + for i in order[:10]]} prv = idx_all.copy() src_pts = np.where(nxt != idx_all)[0] order = np.argsort(nxt[src_pts]) @@ -190,11 +232,23 @@ def build_control_links(x, y, n, bands, strides, qualifying, rng, unique_srcs = src_pts[order][first[counts == 1]] prv[unique_tgts] = unique_srcs links.extend([nxt, prv]) - return links + return links, histA + +def median_nn_spacing_sq(x, y, sel, rng, sample=20_000): + """h^2: median squared nearest-neighbour spacing over the qualifying + region, sampled for tractability -- the local mesh scale the ADI + stencil actually diffuses on, used to size the iteration count.""" + idx = np.where(sel)[0] + if len(idx) > sample: + idx = rng.choice(idx, sample, replace=False) + tree = cKDTree(np.column_stack([x[np.where(sel)[0]], y[np.where(sel)[0]]])) + d, _ = tree.query(np.column_stack([x[idx], y[idx]]), k=2) + return float(np.median(d[:, 1]) ** 2) -def run_adi(field, links, iters=N_ADI_ITERS): - """iters ADI iterations: family-A sweep then family-B sweep each.""" + +def run_adi(field, links, iters): + """`iters` ADI iterations: family-A sweep then family-B sweep each.""" nxtA, prvA, nxtB, prvB = links y = field.copy() for _ in range(iters): @@ -203,10 +257,16 @@ def run_adi(field, links, iters=N_ADI_ITERS): return y -def analyze_bump(x, y, blurred, x0, y0, sel): - """Second-moment tensor of the blurred bump over the qualifying region - -> anisotropy lambda_max/lambda_min; plus a least-squares isotropic - Gaussian fit (over sigma_ref and amplitude) -> relative L2 error.""" +def analyze_bump(x, y, blurred, x0, y0, sel, sigma_predicted): + """v2: second-moment tensor -> anisotropy (unchanged); the isotropic + fit now searches a window CENTERED on the PREDICTED sigma_ref + (sqrt(sigma^2+V) from the iteration scaling) rather than an unbounded + grid from the input sigma upward -- v1's search floor equalled the + input sigma, so an inert operator's exact match (sigma_ref=sigma) was + reachable and indistinguishable from a resolved blur (codex P1). Also + returns the RAW (pre-fit) relative L2 against the UNSMOOTHED input + bump, so "resolved" can be checked directly against "still basically + the input".""" w = np.clip(blurred[sel], 0, None) if w.sum() <= 0: return None @@ -218,22 +278,35 @@ def analyze_bump(x, y, blurred, x0, y0, sel): cxy = (w * (xs - mx) * (ys - my)).sum() / w.sum() ev = np.linalg.eigvalsh(np.array([[cxx, cxy], [cxy, cyy]])) aniso = float(ev[1] / max(ev[0], 1e-300)) - # isotropic reference: fit sigma_ref (grid search then refine) + amplitude d2 = (xs - x0) ** 2 + (ys - y0) ** 2 + lo, hi = sigma_predicted * 0.5, sigma_predicted * 1.5 best = None - for s_ref in np.linspace(SIGMA, SIGMA * 3, 60): + for s_ref in np.linspace(lo, hi, 120): g = np.exp(-d2 / (2 * s_ref ** 2)) a = (g * w).sum() / (g * g).sum() err = np.sqrt(((w - a * g) ** 2).sum() / (w ** 2).sum()) if best is None or err < best[0]: best = (float(err), float(s_ref), float(a)) + g0 = np.exp(-d2 / (2 * SIGMA ** 2)) + a0 = (g0 * w).sum() / (g0 * g0).sum() + raw_vs_input = float(np.sqrt(((w - a0 * g0) ** 2).sum() / (w ** 2).sum())) return {"aniso": aniso, "iso_rel_l2": best[0], - "sigma_ref": best[1], "amplitude": best[2]} + "sigma_ref": best[1], "amplitude": best[2], + "raw_rel_l2_vs_unsmoothed_input": raw_vs_input} def run_one_n(n_idx, rng, partial_fh): """The full pipeline at N = 3*F(n_idx)^2: build, discover, sweep both - arms, analyze. Returns the result row; checkpoints to partial_fh.""" + arms at a V-MATCHED iteration count (same target added variance V at + every n, so B4's comparison is apples-to-apples on physical blur, not + on iteration count), analyze against the PREDICTED blur. Returns the + result row; checkpoints to partial_fh. + + Iteration count is derived, not fixed: iters = round(2*V / h^2), h^2 = + the median squared nearest-neighbour spacing actually measured on this + lattice (mesh scale shrinks as N grows, so iters grows too, for a FIXED + physical target V -- this is why n=19 is out of budget under v2, see + run()'s docstring).""" fn = F[n_idx] n = 3 * fn * fn x, y, r = vogel(n) @@ -243,30 +316,44 @@ def run_one_n(n_idx, rng, partial_fh): if np.sqrt((b - 1) / N_BANDS) >= r_floor] strides = discover_strides(x, y, bands, rng=rng) angles = crossing_angles(x, y, bands, strides, n, rng) - # bump at r0 = 0.75 along +x (any azimuth is equivalent by construction) - x0, y0 = 0.75, 0.0 + x0, y0 = R_BUMP, 0.0 field = np.exp(-((x - x0) ** 2 + (y - y0) ** 2) / (2 * SIGMA ** 2)) sel = np.isin(bands, qualifying) + h2 = median_nn_spacing_sq(x, y, sel, rng) + iters = max(1, round(2 * ADDED_VAR / h2)) + sigma_predicted = float(np.sqrt(SIGMA ** 2 + ADDED_VAR)) + + # baseline: the UNSMOOTHED input bump through the identical mask -- + # isolates the mask's own contribution to the anisotropy readout + # (codex P1c: v1's asymptote may have been the mask, not the operator) + baseline_res = analyze_bump(x, y, field, x0, y0, sel, SIGMA) + fib_links = build_fib_links(n, bands, strides, qualifying) - fib_blur = run_adi(field, fib_links) - fib_res = analyze_bump(x, y, fib_blur, x0, y0, sel) + fib_blur = run_adi(field, fib_links, iters) + fib_res = analyze_bump(x, y, fib_blur, x0, y0, sel, sigma_predicted) - ctl_links = build_control_links(x, y, n, bands, strides, qualifying, rng) - ctl_blur = run_adi(field, ctl_links) - ctl_res = analyze_bump(x, y, ctl_blur, x0, y0, sel) + ctl_links, ctl_hist = build_control_links(x, y, n, bands, strides, + qualifying, sel, rng) + ctl_blur = run_adi(field, ctl_links, iters) + ctl_res = analyze_bump(x, y, ctl_blur, x0, y0, sel, sigma_predicted) row = { "n_idx": n_idx, "N": int(n), "r_floor": float(r_floor), - "qualifying_bands": qualifying, + "qualifying_bands": qualifying, "iters": iters, "h2": h2, + "sigma_predicted": sigma_predicted, "strides": {str(b): (v["pair"] if v else None) for b, v in strides.items()}, "stride_top5_band5": strides.get(5, {}).get("top5") if strides.get(5) else None, "crossing_angles": {str(b): v for b, v in angles.items()}, - "fib": fib_res, "control": ctl_res, + "baseline_unsmoothed": baseline_res, + "fib": fib_res, "control": ctl_res, "control_link_histogram": ctl_hist, "aniso_ratio_control_over_fib": ( float(ctl_res["aniso"] / fib_res["aniso"]) if fib_res and ctl_res else None), + "aniso_change_from_baseline_fib": ( + float(fib_res["aniso"] - baseline_res["aniso"]) + if fib_res and baseline_res else None), } partial_fh.write(json.dumps({"stage": f"n{n_idx}", **row}) + "\n") partial_fh.flush() @@ -274,16 +361,24 @@ def run_one_n(n_idx, rng, partial_fh): def run(): - """Headline at n=17 (N=3*F(17)^2) first, then the B4 sweep ascending - n in {8,10,12,14,19} (17 reused from the headline). n=21 NOT RUN - (N~3.6e8, beyond budget) -- recorded, not silently dropped.""" + """v2. Headline at n=17 (N=3*F(17)^2) first, then the B4 sweep ascending + n in {8,10,12,14} (17 reused from the headline). n=19 and n=21 are NOT + RUN under v2's V-matched iteration scaling: iters = 2V/h^2 and h^2 + shrinks roughly as 1/N for a Vogel lattice, so a FIXED physical target V + forces iters to grow roughly linearly with N -- at n=19 (N~52.4M) the + predicted iteration count is in the tens of thousands, and total cost + scales as N*iters, making it multiple orders of magnitude more expensive + than the n=17 headline alone. This is a genuine budget cutoff, stated + with its mechanism, not a silent drop -- v1's B4 ran n=19 only because + its FIXED 8-iteration count never matched a physical target in the first + place (part of why v1's numbers were void).""" rng = np.random.default_rng(SEED) out_dir = pathlib.Path(__file__).parent partial = out_dir / "spiral_adi_probe.partial.jsonl" with open(partial, "w") as pf: headline = run_one_n(17, rng, pf) sweep = [] - for n_idx in (8, 10, 12, 14, 19): + for n_idx in (8, 10, 12, 14): sweep.append(run_one_n(n_idx, rng, pf)) sweep_full = sorted(sweep + [headline], key=lambda r: r["n_idx"]) @@ -295,10 +390,16 @@ def run(): out = { "headline": headline, "sweep": [{k: v for k, v in row.items() - if k in ("n_idx", "N", "qualifying_bands", "fib", - "control", "aniso_ratio_control_over_fib")} + if k in ("n_idx", "N", "iters", "qualifying_bands", + "baseline_unsmoothed", "fib", "control", + "aniso_ratio_control_over_fib", + "aniso_change_from_baseline_fib")} for row in sweep_full], - "n21": "NOT RUN (N=3*F(21)^2 ~ 3.6e8, beyond budget; recorded per brief)", + "n19_n21": ("NOT RUN under v2's V-matched iteration scaling -- " + "iters ~ 2V/h^2 grows roughly linearly with N for a " + "fixed physical blur target, making n=19/21 multiple " + "orders of magnitude more expensive than n=17; " + "mechanism stated, not a silent drop (see run() docstring)"), "verdicts": { "B2_iso": "PASS" if b2 else "FAIL", "B3_control": ("PASS" if b3 else @@ -318,14 +419,20 @@ def run(): res = run() h = res["headline"] print(f"N={h['N']} r_floor={h['r_floor']:.4f} qualifying={h['qualifying_bands']}") + print(f"iters={h['iters']} h2={h['h2']:.3e} sigma_predicted={h['sigma_predicted']:.5f}") print("strides per band:", h["strides"]) + print(f"baseline (unsmoothed, same mask): {h['baseline_unsmoothed']}") print(f"fib: {h['fib']}") print(f"control: {h['control']}") + print(f"control link histogram (fam A): {h['control_link_histogram']}") print(f"aniso ratio (control/fib): {h['aniso_ratio_control_over_fib']}") + print(f"aniso change from baseline (fib): {h['aniso_change_from_baseline_fib']}") print("verdicts:", res["verdicts"]) print("\nB4 sweep:") for row in res["sweep"]: f_ = row["fib"] - print(f" n={row['n_idx']:2d} N={row['N']:9d} " + b_ = row["baseline_unsmoothed"] + print(f" n={row['n_idx']:2d} N={row['N']:9d} iters={row['iters']:6d} " f"iso={f_['iso_rel_l2']:.4f} aniso={f_['aniso']:.4f} " + f"baseline_aniso={b_['aniso']:.4f} " f"ratio={row['aniso_ratio_control_over_fib']}")