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).
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 | n (exponent) | R² | 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 | — | — | — | BLOCKED — malla.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.
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.
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:
https://malla.mtnme.sh/api/packets — HTTP 521 (Cloudflare origin unreachable) at
first check and again on the plan's mandated single retry, 2 minutes apart. Same failure mode
the day-of recon had already flagged.https://malla.gamesh.net/api/packets) is up (HTTP 200) — not
the blocker — but the position-join dependency (https://meshview.gamesh.net/api/nodes, needed
to compute distance_km for any row) returned HTTP 502 across four courtesy-spaced probes over
~4.5 minutes and never recovered in that window. No cached or alternate position source exists
for gamesh in this environment (unlike mtnme, which has a static cached nodes.json that is
moot anyway since mtnme's packets endpoint itself is down).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.
.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.
rssi = A + B·log10(d)) yields both a slope (exponent n = -B/10) and an intercept
(PL(1 m) = TX_POWER_DBM - A). Per-node TX power and antenna gain differences across a
heterogeneous, third-party-operated fleet bias the intercept and shadowing term, but not the
log-distance slope. The pipeline (sim/experiments/propagation_calibration.py) has always
applied only the data-derived exponent to the sim's PathLossModel, keeping PL(1 m) and
shadowing σ at literature values — unchanged this wave.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/).
sim/data/propagation_fit.json gate block
is June-era output (b39d77a) while the sim has ~15 commits of deterministic drift since
(incl. #494 env_excess_db), so a diff there on re-run signals sim-code drift to
investigate, not seed noise to ignore):
cd sim && source ../.venv/bin/activate && python3 -m experiments.propagation_calibration
(no --dataset flag → defaults to the June CSV, unchanged since Task 1.)cd sim && source ../.venv/bin/activate && python3 -m experiments.propagation_calibration --dataset 2026-08
Requires sim/data/malla_ng_calibration_2026-08.csv to exist first. Note:
tools/fetch_malla.py's output path is currently hardcoded to the June CSV
(sim/data/malla_ng_calibration.csv); producing a 2026-08 CSV without overwriting June needs
either a small output-path parameter added to tools/fetch_malla.py, or the same
uncommitted-wrapper approach Task 1 used (see
sim/data/malla_ng_calibration_2026-08.PROVENANCE.md) once malla.mtnme.sh or
meshview.gamesh.net recovers.cd sim && source ../.venv/bin/activate && python3 -m pytest -q tests/test_propagation_calibration.py
(5 passed, 1 skipped — the skip is test_dataset_selector_switches_to_2026_08_csv, correctly
gated on the still-missing 2026-08 CSV.)cd sim && source ../.venv/bin/activate && python3 -m pytest -q
→ 249 passed, 1 skipped, 0 failed, 245.02 s. The one skip is the same 2026-08 dataset-selector
test above; no regressions elsewhere.sim/data/malla_ng_calibration_2026-08.PROVENANCE.md against whichever host has recovered,
respecting the plan's courtesy rules (paged, ≥1 s between pages, unauthenticated, ≤100 MB
total, malla.mtnme.sh gets one retry before falling back to gamesh-only).sim/experiments/fleet_snr_distance.py was never created — see Task 2 report). Regenerating
the discovery evidence that produced the 0/25 result: re-run the position search documented in
.superpowers/sdd/2026-08-25-158-calibration-refresh/task-2-report.md against the current
loomwave and loomwave-docs trees; the corpus itself self-destructs by retention
(LW_HISTORY_DAYS=30) around 2026-09-04 per its README, so the underlying event rows will not
be re-derivable from the source DB after that date regardless.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.
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.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.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.