11# PyBLE ESP32-Family Browser Flashing and Release Bundle
22
3- Status: ** FROZEN v1.26 ** · Owner: project maintainer · Frozen:
4- 2026-07-30 (` [docs] ` ; pre-v1 two-profile release eligibility and explicit
3+ Status: ** FROZEN v1.27 ** · Owner: project maintainer · Frozen:
4+ 2026-07-31 (` [docs] ` ; pre-v1 two-profile release eligibility and explicit
55C3 deferral; evidence-derived resource policy and exact HIL V2 records;
6- pre-policy two-root baseline-input staging;
6+ pre-policy two-root baseline-input staging and mechanical baseline/policy
7+ assembly;
78exact-profile manifest, C3 silicon-revision,
89license-audit safety, candidate-finalization, and candidate pin-state
910amendments, plus the real-tool license-evidence and exact license-catalog
@@ -18,7 +19,8 @@ markers, generated-header inputs, and direct-object reconciliation, plus
1819component-owned linked outputs, lexical exact-path validation, nested-build
1920logical paths, shell-free compiler/linker command receipts, executable
2021version-matched recovery-command syntax, and the canonical pre-v1 same-origin
21- publication channel with an optional byte-identical mirror, on the same date)
22+ publication channel with an optional byte-identical mirror, plus bounded
23+ completed-HIL report assembly, on the same date)
2224
2325This document is the source of truth for the initial browser-provisioning
2426release bundle. It refines
@@ -201,6 +203,30 @@ policy, baseline-evidence file, release tag, license evidence, or HIL approval.
201203Its output is measurement input only: it is not a release candidate and MUST
202204NOT be accepted by the website or public release validator.
203205
206+ After both exact-profile baseline runs succeed, the release tool MUST provide
207+ an ` assemble-oi1-baseline ` operation. It accepts the immutable staged baseline
208+ input tree above, exactly two canonical single-profile fragments emitted by
209+ the OI-1 bench, the clean canonical PyBLE proof checkout, and one explicit UTC
210+ ` created_at ` value. It MUST derive ` source_commit ` from that checkout's exact
211+ ` HEAD ` and ` firmware_version ` from its ` versions.lock ` ; operator-supplied
212+ substitutes for either identity are forbidden. Before writing, it MUST require
213+ the proof checkout to be clean, require exactly one fragment for each profile
214+ regardless of input order, validate every fragment and observation field,
215+ bind each fragment's firmware hash, manifest hash, and build measurements to
216+ the corresponding staged bytes, and mechanically derive all nine thresholds
217+ with the frozen formulas.
218+
219+ The operation MUST canonicalize and create the baseline evidence at
220+ ` docs/validation/firmware/oi1/<HEAD>.json ` , compute the digest of those exact
221+ bytes, and atomically update ` firmware/qualification/oi1-gates.json ` with the
222+ exact frozen policy shape and derived thresholds. The baseline path is
223+ no-replace: an existing different file is fatal; an existing byte-identical
224+ file is an idempotent input. The policy update MUST be an atomic same-directory
225+ replacement, and both complete byte payloads MUST pass the production
226+ baseline/policy validator before either destination is changed. This operation
227+ is evidence assembly only; it does not approve a release or mutate staged
228+ measurement inputs.
229+
204230The protected candidate site's build-selected SHA-256 of ` release.json ` is the
205231root identity of the candidate exercised during HIL. The completed HIL
206232evidence MUST record that exact lowercase 64-hex digest. Public finalization
@@ -1246,6 +1272,28 @@ In a candidate every value is `pending`. In a public report every value is
12461272` passed ` ; ` footprint_reliability ` MUST be set by the validator only after the
12471273V2 observations pass, not accepted as independent operator testimony.
12481274
1275+ The release tool MUST provide an ` assemble-hil-report ` operation so completing
1276+ this contract never requires hand-editing ` HIL_REPORT.md ` . It accepts one
1277+ immutable pending candidate, exactly two JSON completion fragments (one per
1278+ profile, in either input order), the canonical qualification checkout, and one
1279+ new no-replace output path. A completion fragment contains only the mutable
1280+ profile ID, physical board descriptions/capacities, UTC test time,
1281+ operator/sign-off and environment strings, the six operator-demonstration
1282+ checks other than ` footprint_reliability ` , one completed ` oi1_observation ` , and
1283+ the redacted console log. It MUST NOT accept status, release identity, artifact
1284+ hashes, policy, or build measurements from an operator fragment.
1285+
1286+ The assembler MUST validate the pending candidate first, compute the exact
1287+ candidate ` release.json ` SHA-256 itself, copy every candidate-frozen field from
1288+ the embedded pending records, require all six supplied checks to be ` passed ` ,
1289+ validate the observation and every profile threshold, and only then insert
1290+ ` footprint_reliability: passed ` and ` status: passed ` . It MUST render exactly one
1291+ canonical ` PYBLE_HIL_RECORDS_V2 ` marker, validate the completed payload against
1292+ the candidate bytes and committed policy, write the output atomically, and
1293+ prove the candidate and completion-fragment inputs did not change during the
1294+ operation. It never mutates the candidate and does not perform public bundle
1295+ promotion; ` finalize-public ` remains the only promotion step.
1296+
12491297` oi1_observation ` is JSON ` null ` in a pending candidate. In a completed report
12501298it is an object with exactly:
12511299
0 commit comments