← RFC

Calibration Refresh — #158 Wave A (Memo)

Status: Wave A result (data + fit + memo). Date: 2026-08-25. Reproduce: see "Regen commands" below. Full suite: sim/ pytest — 249 passed, 1 skipped, 0 failed, 245.02 s (run this session, 2026-08-25).

Bottom line

This wave set out to refresh the 2026-06-09 propagation calibration (propagation-calibration-result.md, sim-result-v8) with ~2.5 months of new public Malla data and add an own-fleet SNR-vs-distance population as a distinct link class. Neither refresh produced new numbers. The 2026-08 Malla pull is outage-blocked on both independent networks; the own-fleet population is blocked by the project's own position-privacy design, not by missing data collection. The June exponent (n = 2.50, combined, 1,125 points) remains the operative, unchanged number driving the sim's propagation model. This is a structural finding, not a bug, and is reported as such below — no numbers are fabricated to fill either gap.

Epoch × source table

Epoch Source n (exponent) n_points Status
2026-06 (June) mtnme 2.52 0.37 413 committed (sim/data/malla_ng_calibration.csv); reproduced byte-for-byte this session
2026-06 (June) gamesh 3.36 0.11 712 committed; reproduced
2026-06 (June) combined 2.50 0.26 1,125 committed; reproduced
2026-08 mtnme BLOCKEDmalla.mtnme.sh HTTP 521
2026-08 gamesh BLOCKED — packets API up (200) but position-join dependency meshview.gamesh.net HTTP 502
2026-08 combined BLOCKED (no new CSV produced)
2026-08 fleet (own) 0 resolvable distances (0/25 coordinator↔node pairs) BLOCKED by design — position-privacy model, not a data gap

June figures verified this session by re-running python3 -m experiments.propagation_calibration against the committed CSV: mtnme n=2.5208 (R²=0.3745, 413 pts), gamesh n=3.3554 (R²=0.1070, 712 pts), combined n=2.4999933 (R²=0.2616, 1,125 pts) — matches propagation-calibration-result.md (2.52 / 3.36 / 2.50 at 2 d.p.) and the sim/tests/test_propagation_calibration.py bracket asserts (2.48 ≤ n ≤ 2.52 for combined, per-network brackets [2.4, 2.6] and [3.2, 3.5]), all of which pass in this session's full suite run.

MEETS / drift commentary

The refreshed exponent did not move, because there is no refreshed exponent this wave — both 2026-08 arms (Malla and fleet) are blocked before producing a fit. The sim's validation-gate agreement against the June exponent is therefore unchanged from the June doc's own re-run (SIM mean 7.4% vs REAL mean 7.0% channel utilization; median 7.8% vs 5.7%; the upper tail, p90/max, remains unreproduced and attributed to structural causes outside a single-cluster steady-state sim). No NG-gate re-run was performed in this wave, per the plan's explicit scope decision (2026-08-25-158-calibration-refresh.md, Self-Review Notes).

Follow-up trigger, using the June doc's own demonstrated sensitivity as the reference magnitude: the June doc's own before/after shows that a Δn = 0.20 exponent move (prior literature assumption 2.70 → data-derived 2.50) roughly doubled the sim's mean channel-utilization figure (3.5% → 7.4%) and closed most of the gap to the real network's 7.0% mean. That is the only empirical sensitivity data point available — there is no other stated numeric threshold in the June doc. Using it as the reference: a future refreshed combined exponent that differs from 2.50 by roughly that same order of magnitude (≳0.15–0.20) would plausibly move the gate's central-tendency agreement enough to justify re-running it. A refresh that lands within ~0.05–0.10 of 2.50 (consistent with the June per-network spread of 2.52–3.36 on independent gateways, which itself reflects normal siting variance) would not, on this evidence, be expected to change the gate's verdict. This wave produced no new exponent to test against that trigger.

What's blocked, and why

2026-08 Malla refresh — outage-blocked (evidence: sim/data/malla_ng_calibration_2026-08.PROVENANCE.md)

Both independent networks were unusable for a new pull during the 2026-08-25 06:04–06:12 UTC attempt window:

No page of packet data was ever pulled (the position check runs first and blocked before the paged pull started), so total transfer for this attempt was a handful of status-only probes plus one earlier ~33 KB recon GET — well under the plan's 100 MB courtesy budget. The dataset selector (--dataset/dataset= on experiments.propagation_calibration, implemented in Task 1) is ready to consume sim/data/malla_ng_calibration_2026-08.csv the moment either host recovers; no code change is needed to pick it up, only a successful pull.

mtnme status as of this memo: still down per the pull window above (06:04–06:12 UTC, 2026-08-25); not independently re-probed after that window while writing this memo, so "still down" reflects the last check, not a live status.

Own-fleet SNR-vs-distance — blocked by design, not by data availability (evidence: .superpowers/sdd/2026-08-25-158-calibration-refresh/task-2-report.md)

The fleet corpus (/root/project/loomwave/infra/calibration/2026-08-fleet-corpus/, read-only, per its own README) has plenty of raw SNR data: 45,134 of 59,316 event rows carry snr, and 34,479 are non-self topology/advert rows (excluding a coordinator hearing its own broadcast) spanning 25 distinct (coordinator, heard-node) pairs across two non-overlapping coordinator windows — 29C076 (2026-07-25 → 07-27) and 7F55DB (2026-07-31 → 08-05), both already public in the corpus's own README and used here at that same disclosure level (no other ADDR24 from that corpus appears in this memo).

The blocker is positions, not SNR: 0 of the 25 pairs have both endpoints' positions resolvable anywhere in the committed loomwave or loomwave-docs trees. This is by design — docs/field-test-runbook.md states the address↔device/location map is kept out of the repo deliberately (position-privacy model B, decided 2026-07-03), and the one in-repo mechanism that could supply fixed-node coordinates, LW_NODE_LAT/LW_NODE_LON (docs/analysis/2026-07-03-node-positions-on-a-map.md), is a design proposal that has never been wired to an actual env value. Per the plan's own hard-stop rule ("if < 3 distinct distances resolve, STOP ... do not fabricate positions"), Task 2 stopped at discovery: 0 resolvable distances, no code or CSV written, no commit.

What would unblock it is a Matt-level privacy/design call, not more engineering effort: wiring the already-designed LW_NODE_LAT/LW_NODE_LON env for the two tower coordinators and recording at least 3 client/repeater positions (e.g. the bench Pi's fixed position, or surveyed points from the operator's out-of-repo host/device-inventory notes). That is deliberately deferred to Matt here, not attempted — it changes the project's position-disclosure posture, which is outside a calibration-refresh task's scope.

Assumptions (inherited + restated)

Regen commands

All commands run from the repo root (/root/project/loomwave-docs) unless noted, with the repo venv active (source .venv/bin/activate from root, or source ../.venv/bin/activate from sim/).

Wave B pointer

The webmap heat layer (rendering the calibrated propagation model / real reception data as a map overlay) is wave B of #158, a separate plan — not attempted, scoped, or designed in this wave. This memo's outputs (or lack thereof, for the two blocked arms) are the input wave B would consume once it starts.

Follow-ups

  1. Retry the 2026-08 Malla pull once malla.mtnme.sh (521) or meshview.gamesh.net (502) recovers; add the small output-path parameter to tools/fetch_malla.py first so the pull doesn't require an uncommitted wrapper.
  2. The own-fleet SNR-vs-distance population needs a Matt-level position-privacy decision before any further engineering: whether to wire LW_NODE_LAT/LW_NODE_LON for the two tower coordinators (and record at least 3 client/repeater positions) so a distance-only, non-invasive fleet fit becomes possible. Not attempted here; flagged for Matt.
  3. No NG-gate re-run this wave (by design, see Self-Review Notes in the plan). Re-run it only if a future Malla or fleet refresh produces a combined exponent that moves by roughly ≳0.15–0.20 from 2.50, per the sensitivity discussion above.
  4. The fleet corpus retention window closes 2026-09-04 (LW_HISTORY_DAYS=30); if the position blocker is lifted before then, re-exporting from the same corpus is still possible after that date only if a fresh export or a new collection period exists.