|
| 1 | +# ADR-0039 — Admit the Waveshare single-page largest-block transient |
| 2 | + |
| 3 | +- Status: **Accepted** |
| 4 | +- Date: 2026-08-21 |
| 5 | +- Supersedes: ADR-0037 decision item 8 for the Waveshare |
| 6 | + `idf_internal_largest_block_min_bytes` floor only, and ADR-0038's |
| 7 | + fresh-observation requirement only under the exact byte-identity |
| 8 | + conditions of decision item 6 |
| 9 | +- Preserves: every other ADR-0037/ADR-0038 rule, the immutable `a8be631…` |
| 10 | + baseline, and all historical derivation revisions |
| 11 | + |
| 12 | +## Context |
| 13 | + |
| 14 | +Three consecutive replacement-era Waveshare OI-1 verify runs on candidate |
| 15 | +source `7d853289815751c7381c9fd0b9a9a4409bdb6879` failed at exactly one gate: |
| 16 | +one heap snapshot per run recorded `idf_internal_largest_block_bytes` of |
| 17 | +`98304` against the frozen floor of `102400`. Every other value passed in the |
| 18 | +same runs — reset samples 749–1,531 ms, all ten PUT/GET samples well above |
| 19 | +6,600 bytes/s, 20/20 reliability with zero integrity failures, settled 2M |
| 20 | +PHY/DLE 251 transport, and the physical power seam. |
| 21 | + |
| 22 | +The dip is characterized, not anomalous: |
| 23 | + |
| 24 | +- It is exactly one 4,096-byte page: `98304 = 102400 - 4096`. |
| 25 | +- `idf_internal_free_bytes` and `idf_internal_minimum_free_bytes` are |
| 26 | + unchanged at the dip instant — transient fragmentation of the largest |
| 27 | + block, not memory consumption. |
| 28 | +- It appears once per run at a timing-dependent post-HELLO snapshot |
| 29 | + (reset samples 4, 6, and 1 across the three runs). |
| 30 | +- The generic `esp32-s3-n16r8` profile — identical chip, identical floor — |
| 31 | + recorded 41 snapshots across three runs the same day with zero dips. |
| 32 | + The behavior is specific to the Waveshare image. |
| 33 | +- The retained `a8be631…` baseline capture recorded no dip, so |
| 34 | + `floor-min-1024-v1` froze the floor at the un-fragmented value. |
| 35 | + |
| 36 | +`floor-min-1024-v1` cannot express a floor below its baseline minimum, so |
| 37 | +admitting the transient requires a new heap-floor derivation identifier and a |
| 38 | +new source era, exactly as ADR-0037 introduced fixed reset/goodput |
| 39 | +identifiers for the V4 era. |
| 40 | + |
| 41 | +This decision does not fit a gate to a failure. The floor remains a |
| 42 | +fragmentation regression guard, not a performance promise; the admitted value |
| 43 | +is the baseline-derived floor minus exactly one page — the minimal relaxation |
| 44 | +that admits a single-page transient — and the three failed runs confirm, |
| 45 | +rather than define, that arithmetic. The sanctioned ADR-0037 item 9 path is |
| 46 | +followed in full: spec-first ADR, then fresh qualification of a new candidate. |
| 47 | + |
| 48 | +## Decision |
| 49 | + |
| 50 | +For the second-replacement v0.6.0 source era: |
| 51 | + |
| 52 | +1. The era boundary is `7d853289815751c7381c9fd0b9a9a4409bdb6879` — the |
| 53 | + superseded first-replacement candidate source. Strict descendants use |
| 54 | + `QUALIFICATION_DERIVATION_V5`; the boundary and its ancestors keep their |
| 55 | + historical derivations (V4 era per ADR-0038, version-routed before it). |
| 56 | + Unknown or unrelated ancestry still fails closed. |
| 57 | +2. `QUALIFICATION_DERIVATION_V5` changes exactly one identifier relative to |
| 58 | + V4: `heap_floor` becomes `floor-min-1024-waveshare-block-98304-v2`. |
| 59 | + `application_image`, `application_headroom`, `boot_ceiling`, and |
| 60 | + `goodput_floor` keep their exact V4 identifiers and arithmetic. |
| 61 | +3. Under `floor-min-1024-waveshare-block-98304-v2`, every heap floor for |
| 62 | + every profile keeps `floor-min-1024-v1` arithmetic from the immutable |
| 63 | + `a8be631…` baseline, with exactly one exception: |
| 64 | + `idf_internal_largest_block_min_bytes` for |
| 65 | + `waveshare-esp32-s3-lcd-147b` is the fixed value `98304`. |
| 66 | +4. The active policy for the V5 era is therefore the exact V4 policy with |
| 67 | + the `heap_floor` derivation identifier replaced and exactly one numeric |
| 68 | + field changed: the Waveshare `idf_internal_largest_block_min_bytes` |
| 69 | + `102400 -> 98304`. All other 10 largest-block/heap values, every static |
| 70 | + image/headroom bound, every reset ceiling, and every goodput floor are |
| 71 | + byte-for-byte unchanged. |
| 72 | +5. The floor value `98304` is a fixed product decision. A verify run that |
| 73 | + records any heap sample below it fails, and per ADR-0037 item 9 its |
| 74 | + values MUST NOT be used to relax the policy again; a further change |
| 75 | + requires another spec-first ADR and fresh qualification. |
| 76 | +6. Evidence captured under the superseded first-replacement candidate MAY |
| 77 | + bind into the successor candidate's completion, per profile, only if |
| 78 | + every one of these mechanical conditions holds: |
| 79 | + a. the successor candidate's install artifacts for that profile are |
| 80 | + byte-identical (equal SHA-256 and size) to the artifacts the evidence |
| 81 | + was captured against; |
| 82 | + b. every policy threshold applicable to that profile is value-identical |
| 83 | + between the superseded and successor policies; |
| 84 | + c. the evidence passed its frozen evaluator when captured, unmodified. |
| 85 | + The eligible evidence classes are OI-1 verify observations, the C3 |
| 86 | + post-OI NVS capture (its receipt re-bound to the successor |
| 87 | + candidate digest from re-derived bytes), and provisioning |
| 88 | + install/readback evidence. If any condition fails for a profile, the |
| 89 | + clause is void for that profile and ADR-0038's fresh-observation rule |
| 90 | + applies unchanged. `waveshare-esp32-s3-lcd-147b` is excluded by |
| 91 | + construction (condition b fails) and always requires a fresh |
| 92 | + observation. App HIL matrix rows are NOT eligible and are re-run |
| 93 | + against the successor candidate. |
| 94 | +7. The byte-identity and threshold-identity proofs for every carried |
| 95 | + profile must be recorded alongside the completion evidence (exact |
| 96 | + SHA-256 pairs and the compared threshold rows). |
| 97 | +8. The tag/candidate replacement procedure of ADR-0038 applies unchanged: |
| 98 | + retain the superseded tag object and candidate metadata as superseded |
| 99 | + evidence, never publish them, and require fresh candidate creation, |
| 100 | + validation, and completion under the successor policy. |
| 101 | + |
| 102 | +## Consequences |
| 103 | + |
| 104 | +- The Waveshare profile is qualifiable on truthful evidence: its |
| 105 | + characterized single-page transient no longer fails an otherwise fully |
| 106 | + passing run, while a genuine fragmentation regression below `98304` |
| 107 | + still fails closed. |
| 108 | +- One more derivation era exists. Historical eras remain byte-reproducible; |
| 109 | + the V4 era's policy and arithmetic are untouched for ancestry at or |
| 110 | + below the `7d85328…` boundary. |
| 111 | +- If the successor build proves byte-identical per profile, already-passed |
| 112 | + physical observations remain valid evidence instead of being discarded |
| 113 | + for a policy-only source change — bounded strictly by the mechanical |
| 114 | + conditions of decision item 6. If it does not, every profile requalifies |
| 115 | + fresh, so the clause can only reduce redundant bench work, never admit |
| 116 | + unproven hardware behavior. |
| 117 | +- The firmware bytes are not changed by this decision. If a later change |
| 118 | + eliminates the transient allocation, the floor may be restored to the |
| 119 | + baseline-derived value by a further spec-first ADR. |
0 commit comments