|
| 1 | +# ADR-0037 — Use fixed profile reset and product-wide transfer SLOs |
| 2 | + |
| 3 | +- Status: **Accepted** |
| 4 | +- Date: 2026-08-20 |
| 5 | +- Supersedes: ADR-0026 decision items 1–2 for replacement-v0.6.0 |
| 6 | + reset qualification, and ADR-0025 decision items 4 and 6 for |
| 7 | + replacement-v0.6.0 goodput qualification |
| 8 | +- Preserves: historical derivation revisions and immutable baseline evidence |
| 9 | + |
| 10 | +## Context |
| 11 | + |
| 12 | +The five-profile v0.6.0 baseline retained at |
| 13 | +`docs/validation/firmware/oi1/a8be631df46590166307aa41afaea30b39e29230.json` |
| 14 | +is valid engineering evidence, but it exposed two product-contract problems. |
| 15 | +First, Pico 2 W has a materially different reset path from the four ESP |
| 16 | +profiles. Its pinned upstream BTstack controller initialization normally needs |
| 17 | +a 5–6 second allowance; applying the ESP 3-second discovery SLO to that path is |
| 18 | +not a truthful cross-port requirement. Second, deriving each transfer floor as |
| 19 | +95% of one profile's minimum baseline sample turns a product-usability bound |
| 20 | +into five candidate-fitted regression thresholds. |
| 21 | + |
| 22 | +The retained baseline diagnoses feasibility without selecting either new |
| 23 | +value. Its ESP reset maxima are 1,828, 1,187, 1,594, and 1,167 ms, while the |
| 24 | +Pico maximum is 3,378 ms. Its minimum PUT values are 6,870, 13,740, 13,656, |
| 25 | +16,180, and 12,854 bytes/s; its minimum GET values are 13,240, 20,787, 25,654, |
| 26 | +28,716, and 7,181 bytes/s. The product decision must remain independent of |
| 27 | +those extrema so a failed qualification run can never fit or relax its own |
| 28 | +gate. |
| 29 | + |
| 30 | +## Decision |
| 31 | + |
| 32 | +For the replacement v0.6.0 source era defined by ADR-0038: |
| 33 | + |
| 34 | +1. Reset-to-service-advertisement remains the exact same end-to-end metric: |
| 35 | + controlled reset/power release to the first fresh host scanner callback |
| 36 | + containing the exact PyBLE service UUID. |
| 37 | +2. `reset_to_service_advertisement_max_ms` is exactly `3000` for |
| 38 | + `esp32-4mb`, `esp32-s3-n16r8`, `waveshare-esp32-s3-lcd-147b`, and |
| 39 | + `esp32-c3-4mb`, and exactly `7000` for `rpi-pico2-w`. The derivation |
| 40 | + identifier is |
| 41 | + `fixed-profile-product-slo-esp3000-pico7000-v4`. |
| 42 | +3. Pico's 7-second bound is independently budgeted from the pinned upstream |
| 43 | + BTstack's normal 5–6 second controller-initialization allowance plus one |
| 44 | + fixed second for service-advertisement acquisition and host callback |
| 45 | + delivery. It is not derived from the 3,378 ms observation and MUST NOT be |
| 46 | + widened again after a failure. |
| 47 | +4. Every profile still records exactly 10 reset samples. All 10 must pass its |
| 48 | + profile ceiling; no sample is trimmed, replaced, retried, or selectively |
| 49 | + rerun. The scanner-before-reset ordering, exact-service match, HELLO after |
| 50 | + every sample, 15,000 ms hard health timeout, and separate physical |
| 51 | + power-cycle advertisement check remain exact. |
| 52 | +5. Both committed PUT and verified GET use the fixed product-wide floor |
| 53 | + `6600` bytes/s on all five profiles. Its derivation identifier is |
| 54 | + `fixed-product-slo-64k-under-10s-6600-v3`. |
| 55 | +6. The arithmetic is exactly |
| 56 | + `ceil_100(65536 bytes / 10 seconds) = ceil_100(6553.6) = 6600` bytes/s. |
| 57 | + Because reported goodput is the integer |
| 58 | + `floor(65536 * 10^9 / duration_ns)`, the largest passing duration is |
| 59 | + `9,929,696,969 ns` (approximately `9.9297 s`), not a rounded 10 seconds. |
| 60 | +7. Exactly five PUT and five GET samples remain mandatory per profile. Every |
| 61 | + sample must meet 6,600 bytes/s with no retry or replacement. The exact |
| 62 | + 65,536-byte unique-byte counts, duration arithmetic, byte/size/CRC and |
| 63 | + offset integrity, required ATT MTU/window/chunk, settled link facts, |
| 64 | + retransmit/rewind accounting, reliability totals, zero unexpected |
| 65 | + disconnects, and physical check receive no allowance. |
| 66 | +8. Reset and transfer baseline samples remain immutable diagnostic evidence; |
| 67 | + neither contributes arithmetic to these product SLOs. Static image and |
| 68 | + headroom thresholds remain exact, and heap floors retain |
| 69 | + `floor-min-1024-v1` baseline derivation. The retained `a8be631…` baseline |
| 70 | + is rederived under the bound policy/candidate source era; its own |
| 71 | + `source_commit` never selects the derivation revision. |
| 72 | +9. A candidate or verify run that crosses either fixed SLO fails. Its values |
| 73 | + MUST NOT be used to rederive, fit, trim, or relax the policy; changing a |
| 74 | + product SLO requires another spec-first ADR and fresh qualification. |
| 75 | +10. Historical source eras retain their exact derivation objects and |
| 76 | + arithmetic. In particular, the earlier unpublished v0.6.0 source era |
| 77 | + remains reproducible with `fixed-product-slo-3000-v3` and |
| 78 | + `floor-95pct-min-100-v2`; it does not silently inherit this decision. |
| 79 | + |
| 80 | +## Consequences |
| 81 | + |
| 82 | +- Reset qualification reflects the real controller startup class of each port |
| 83 | + while keeping one exact host-visible endpoint and strict sample discipline. |
| 84 | +- PUT and GET now express the minimum usable 64 KiB product transaction rather |
| 85 | + than the performance of the baseline used to exercise a particular build. |
| 86 | +- The active five-profile policy must replace both derivation identifiers and |
| 87 | + atomically set four ESP reset ceilings to 3,000, Pico's to 7,000, and all ten |
| 88 | + transfer floors to 6,600 before a replacement candidate is built. |
| 89 | +- The immutable `a8be631…` baseline is retained unchanged. It supplies the |
| 90 | + unchanged static/heap inputs and diagnostic performance samples, but is not |
| 91 | + release approval and does not route its own derivation. |
0 commit comments