|
| 1 | +## 2026-08-13 — E-A-TOTAL-FUNCTION-THAT-CANNOT-REFUSE-IS-A-CORRUPTION-PATH-1 |
| 2 | + |
| 3 | +**Status:** FINDING `[G]` — two measured instances, one crate, one hour. |
| 4 | +Found by codex review on PR #948; the second by following the first to its |
| 5 | +class. **Confidence:** High. Mechanism measured, not inferred. |
| 6 | + |
| 7 | +**The shape.** `CalibratedFloor::quantize(f64) -> u8` is **total**: every input |
| 8 | +returns a valid-looking bucket. It has no way to say *"that was not a |
| 9 | +measurement."* Measured behaviour on non-finite input: |
| 10 | + |
| 11 | +| input | bucket | why | |
| 12 | +|---|---|---| |
| 13 | +| `NaN` | **0** | `f64::clamp` **propagates** `NaN` rather than clamping it, then Rust's float→int cast saturates and sends `NaN` to zero | |
| 14 | +| `-inf` | **0** | clamps to the low rim | |
| 15 | +| `+inf` | **255** | clamps to the high rim | |
| 16 | + |
| 17 | +Every one of those is a **legitimate** bucket. `0` and `255` are the ordinary |
| 18 | +saturation values; `bucket_center(0)` is a real number near `lo`. Nothing |
| 19 | +downstream can distinguish the result from a genuine reading. |
| 20 | + |
| 21 | +**Why this was live and not theoretical.** ARCO-ERA5 is sparse *by design*: |
| 22 | +`probes/weather-p1/README.md` §1 records `fill_value: NaN`, that several |
| 23 | +variables 404 at the arc's **own fixture timestep**, and that in Zarr v2 a |
| 24 | +missing chunk means all-`fill_value` — so **a 404 is valid store semantics, not |
| 25 | +a fetch failure**, and *"any ingest must treat 404 as data."* The 404-ing list |
| 26 | +at that timestep includes five variables the W1 field set actually packs. |
| 27 | + |
| 28 | +**Instance 1 — the store path** (`lane.rs::pack_facet`, codex P1). An absent |
| 29 | +field would have been written as plausible low-bucket measurements and read |
| 30 | +back through `bucket_center` as ordinary numbers. This is the reserved-slot |
| 31 | +rule — *"a reserved slot must not read back as a plausible number"* — defeated |
| 32 | +one level deeper, where the existing guard could not see it. |
| 33 | + |
| 34 | +**Instance 2 — the INSTRUMENT path, and it is worse** |
| 35 | +(`floor.rs::saturation_of`). That function scores *"an ARBITRARY external |
| 36 | +population"* by counting rim buckets — and non-finite input lands **on the |
| 37 | +rim**. An all-`NaN` population would have scored `1.0`: **"completely |
| 38 | +saturated" when the truth is "no data at all."** Those are opposite findings |
| 39 | +and the bare fraction could not tell them apart. It is bar B2's instrument, so |
| 40 | +the corruption would have propagated into a *measurement* rather than a stored |
| 41 | +value. |
| 42 | + |
| 43 | +> **The sharpening worth keeping: a corrupted stored value is bad; a corrupted |
| 44 | +> INSTRUMENT is worse.** A bad value is one wrong row. A bad instrument is |
| 45 | +> every conclusion drawn with it, each of which looks sound and carries no |
| 46 | +> trace of the defect. When a finding lands on a total function, check its |
| 47 | +> *measurement* call sites before its storage call sites. |
| 48 | + |
| 49 | +**The other half of the same mistake — do not silently drop.** Skipping |
| 50 | +non-finite values without reporting them is equally wrong: the caller never |
| 51 | +learns the population was partly or wholly absent. The fix therefore |
| 52 | +**reports**: `saturation_of` returns `SaturationScore { fraction, finite, |
| 53 | +non_finite }`, matching this crate's standing shape (`calibrate` and `decode` |
| 54 | +return `None` on a degenerate case rather than inventing a number) and the |
| 55 | +`D-WXS-12` rule that *the degenerate case must be reported, never folded as |
| 56 | +`0.0`*. |
| 57 | + |
| 58 | +**Where the guard belongs.** At the boundary where an external value enters |
| 59 | +the register — not inside the hot primitive. `quantize` keeps its signature |
| 60 | +(changing it ripples through every call site); `pack_facet` refuses, and |
| 61 | +`saturation_of` excludes-and-counts. `calibrate` was checked and is **clean** |
| 62 | +— it already filters `is_finite`, so the hole never reached calibration. Every |
| 63 | +`quantize` call site in the crate is now either guarded or provably finite. |
| 64 | + |
| 65 | +**Generalizable check, cheap to run:** for every total function that maps a |
| 66 | +wider domain onto a narrower one — quantisers, clamps, `as` casts, |
| 67 | +`unwrap_or`, saturating arithmetic — ask *what does an invalid input return, |
| 68 | +and is that return distinguishable from a valid one?* If the answer is "a |
| 69 | +valid-looking value", the function cannot refuse, and every call site is a |
| 70 | +corruption path until one of them does. |
| 71 | + |
| 72 | +**Cross-ref:** `E-VACUOUS-ASSERTION-IS-THE-HOUSE-STYLE-1`; |
| 73 | +`E-A-DISABLE-PROBE-CAN-ITSELF-BE-VACUOUS-1` (same session, the verification |
| 74 | +layer); `.claude/plans/weather-soa-bake-v1.md` §4 bar B2 (the instrument); |
| 75 | +`probes/weather-p1/README.md` §1 (the store semantics); PR #948. |
| 76 | + |
| 77 | +--- |
| 78 | + |
| 79 | +## 2026-08-13 — E-A-DISABLE-PROBE-CAN-ITSELF-BE-VACUOUS-1 |
| 80 | + |
| 81 | +**Status:** FINDING `[G]` — three measured instances in one session, all mine. |
| 82 | +**Confidence:** High. Method-level; no code claim. |
| 83 | + |
| 84 | +**The known rule it extends.** This workspace already holds *"an assertion |
| 85 | +implied by the code it tests is not a test"* (`CLAUDE.md` § falsifiability rule) |
| 86 | +and, in the sibling repo's words, *"turning a knob that does not bind is not a |
| 87 | +disable."* Both are stated about **tests**. This entry records that the same |
| 88 | +failure applies one level up — to the **verification probe** that is supposed to |
| 89 | +prove a test can fail — and that it is harder to spot there, because a broken |
| 90 | +probe and a passing suite look identical. |
| 91 | + |
| 92 | +**The three instances, same session, gating `crates/weather-poc`.** |
| 93 | + |
| 94 | +1. **Wrong symbol name.** A probe searched for `ManifestError::DuplicateSlot`; |
| 95 | + the real variant is `SlotCollision`. The substitution script aborted, the |
| 96 | + test run afterwards executed **unmodified code**, and reported `25 passed`. |
| 97 | + Read casually, that is a passing disable-verification of a guard that was |
| 98 | + never touched. |
| 99 | +2. **Dead code.** A probe inserted an `if` block computing `lo`/`hi` and |
| 100 | + discarding both (`let _ = (lo, hi);`). It applied cleanly and changed |
| 101 | + nothing. `25 passed` again. |
| 102 | +3. **Wrong target.** A probe changed `raw` to `raw.max(1)` intending to make |
| 103 | + reserved slots decode — but the unpack loop only visits **manifest-resolved** |
| 104 | + slots, so the edit could never reach a reserved one. `33 passed`. |
| 105 | + |
| 106 | +Instance 1 is the dangerous one: 2 and 3 at least ran, while 1 silently did not. |
| 107 | + |
| 108 | +**The signature that separates the two causes.** A disable run that stays green |
| 109 | +has two possible explanations — *the guard is absent* or *the probe never |
| 110 | +touched it* — and greenness alone does not distinguish them. What does: a |
| 111 | +correct disable kills **at least one** test, and usually a small, nameable set. |
| 112 | + |
| 113 | +> **A disable that kills ZERO tests is more likely a broken probe than a missing |
| 114 | +> guard.** Treat zero as "re-check the probe", never as "verified". |
| 115 | + |
| 116 | +Corollary, the mechanical fix now in use: **the probe must assert that it |
| 117 | +applied.** Every substitution asserts its pattern was found and the file |
| 118 | +actually changed, and fails loudly otherwise — so instance 1 becomes an error |
| 119 | +instead of a green run. |
| 120 | + |
| 121 | +**Why this is worth a board entry rather than a shrug.** The whole |
| 122 | +disable-the-fix discipline exists because a passing test proves nothing about |
| 123 | +whether it *could* fail. If the probe that establishes that is itself unchecked, |
| 124 | +the discipline has an unverified root and inherits exactly the confidence it was |
| 125 | +built to withdraw. Three instances in one session, by an operator applying the |
| 126 | +rule deliberately, is the measured argument that the root needs checking too. |
| 127 | + |
| 128 | +**Cross-ref:** `E-VACUOUS-ASSERTION-IS-THE-HOUSE-STYLE-1`, |
| 129 | +`E-A-CONTROL-THAT-CANNOT-LOSE-IS-NO-CONTROL-1`, |
| 130 | +`E-ANTI-EIGENVALUE-MACHINERY-CAN-ITSELF-BECOME-THE-EIGENVALUE-1` (the same |
| 131 | +one-level-up move, applied there to guards rather than probes); |
| 132 | +`CLAUDE.md` § The falsifiability rule. |
| 133 | + |
| 134 | +--- |
| 135 | + |
1 | 136 | ## 2026-08-12 — E-THE-REGIME-LADDER-MEASURED-RANGE-NOT-TURBULENCE-1 |
2 | 137 |
|
3 | 138 | **Status:** FINDING `[G]` — measured, same run, found by an operator |
|
0 commit comments