Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c06fa99
[docs] Define exact unqualified firmware beta
yyods Jul 31, 2026
f8c0919
[red] Guard exact unqualified firmware beta
yyods Jul 31, 2026
d701eab
[green] Enable exact unqualified firmware beta
yyods Jul 31, 2026
4f0d0cd
[red] Guard public beta staging and activation
yyods Jul 31, 2026
3626400
[green] Stage and preserve exact firmware beta
yyods Jul 31, 2026
346a76a
[docs] Align current public beta claims
yyods Jul 31, 2026
a9b54e9
[red] Guard coherent public beta claims
yyods Jul 31, 2026
ab6a293
[red] Require exact firmware source for audited beta
yyods Jul 31, 2026
e9d222a
[red] Preserve qualified installer without beta evidence
yyods Jul 31, 2026
7c3777c
[red] Keep firmware availability copy selector-driven
yyods Jul 31, 2026
ccc5941
[red] Require stable repo-local IDF path mapping
yyods Jul 31, 2026
c13548d
[green] Stabilize repo-local IDF build paths
yyods Jul 31, 2026
e4b6106
[red] Reject Python cache contaminated source evidence
yyods Jul 31, 2026
c41bc48
[red] Reject cacheable firmware error responses
yyods Jul 31, 2026
ce02b68
[green] Stabilize supplemental source evidence
yyods Jul 31, 2026
9924f71
[red] Keep qualified flash copy actionable
yyods Jul 31, 2026
454a270
[green] Activate exact audited v0.4.2 beta
yyods Jul 31, 2026
fa4b207
[build] Integrate reproducible v0.4.2 source
yyods Jul 31, 2026
17c7266
[docs] Record v0.4.2 production browser HIL
yyods Jul 31, 2026
f331967
[red] Require scoped hardware-tested beta copy
yyods Jul 31, 2026
88b649c
[green] Publish hardware-tested beta status
yyods Jul 31, 2026
4b8b9af
[refactor] Reconcile public main with tested v0.4.2 lineage
yyods Aug 1, 2026
5268b3c
[red] Guard v0.4.2 production attestation
yyods Aug 1, 2026
ad2ed86
[green] Publish v0.4.2 production attestation
yyods Aug 1, 2026
9828500
[red] Guard current firmware beta terminology
yyods Aug 1, 2026
0648801
[docs] Align specifications with v0.4.2 hardware beta
yyods Aug 1, 2026
dff3440
[red] Guard capability-defined firmware target wording
yyods Aug 1, 2026
c26fed9
[green] Correct capability-defined target wording
yyods Aug 1, 2026
148c712
[red] Guard retired public release artifacts
yyods Aug 1, 2026
2863c94
[green] Enforce retirement of pre-public artifacts
yyods Aug 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@ are released independently from this monorepo.
- Established `PyBLE-dev/PyBLE` as the canonical public monorepo.
- Added public contributor, security, architecture, protocol, and validation
documentation.
- Selected firmware agent `0.4.2` for fresh reproducible builds and
two-profile qualification from the canonical public history.

## Firmware 0.4.2 — 2026-07-31

- Published the exact hardware-tested beta for `esp32-4mb` and
`esp32-s3-n16r8`; ESP32-C3 remains unavailable.
- Validated production Chrome installation, deliberate interruption,
interrupted-flash recovery, and reset on real hardware for both exact
profiles.
- Bound the public release to its annotated source tag, immutable metadata,
binary hashes, and post-release production-browser attestation.
- The complete release qualification remains pending across the app, PBLE/1,
resource, and remaining firmware matrices.

## App 0.1.0-beta — 2026-07-30

Expand Down
37 changes: 23 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,21 @@ BLE GATT peripheral. It supports:
- board naming and identify support; and
- upstream MicroPython’s standard `neopixel` module.

The public browser installer is currently unavailable pending v0.4.2 HIL on
both exact current profiles:

| Installer profile | Exact target constraint | Public status |
| ----------------- | ------------------------------------------------------------ | --------------------------------------------------- |
| `esp32-4mb` | Classic ESP32, 4 MiB external SPI flash; no PSRAM assumed | v0.4.2 HIL pending; installer unavailable |
| `esp32-s3-n16r8` | ESP32-S3, 16 MiB flash / 8 MiB Octal PSRAM; N16R8-class only | v0.4.2 HIL pending; installer unavailable |
| `esp32-c3-4mb` | ESP32-C3, 4 MiB external SPI flash; no PSRAM assumed | Planned; no public image; exact-profile HIL pending |
The public browser installer currently offers the exact v0.4.2 hardware-tested
beta for both current profiles. Production Chrome erase/install and deliberately
interrupted-flash recovery passed on real hardware for both exact profiles.
Complete release qualification continues across the app, PBLE/1, resource, and
remaining firmware matrices:

| Installer profile | Exact target constraint | Public status |
| ----------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| `esp32-4mb` | Classic ESP32, 4 MiB external SPI flash; no PSRAM assumed | v0.4.2 hardware-tested beta; browser install/recovery passed |
| `esp32-s3-n16r8` | ESP32-S3, 16 MiB flash / 8 MiB Octal PSRAM; N16R8-class only | v0.4.2 hardware-tested beta; browser install/recovery passed |
| `esp32-c3-4mb` | ESP32-C3, 4 MiB external SPI flash; no PSRAM assumed | Planned; unavailable; no public image |

See the
[post-release production-browser attestation](docs/validation/browser-flashing/v0.4.2-production.md)
for the exact hashes, completed checks, and deliberately bounded claim.

These are the initial port targets, not a chip-family allowlist. A future board
is compatible when it has a maintained PyBLE agent port, BLE GATT
Expand Down Expand Up @@ -106,12 +113,14 @@ shared conformance corpus, documentation, and CI atomically.
1. Install the iPad beta from
[TestFlight](https://testflight.apple.com/join/yU4e8s6d), or build the
Flutter app locally.
2. Check [pyble.dev/flash](https://pyble.dev/flash) in desktop Chrome or Edge.
The public installer is currently unavailable pending v0.4.2 HIL. Wait for
that page to show an active release version, your exact profile, and an
enabled install action.
3. Only after that gate opens, back up the board, confirm its exact memory
profile, and use the one-time wired installer. Flashing erases the board.
2. Open [pyble.dev/flash](https://pyble.dev/flash) in desktop Chrome or Edge.
The exact v0.4.2 hardware-tested beta is active. Browser installation and
interrupted-flash recovery passed on both exact profiles; complete release
qualification continues. Confirm the active version, your exact profile,
and the enabled install action.
3. Before flashing, back up the board, confirm its exact memory profile, and
accept every safety acknowledgement before using the one-time wired
installer. Flashing erases the board.
4. Open PyBLE, scan for the provisioned board, connect, and run an example over
BLE.

Expand Down
8 changes: 5 additions & 3 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ promising dates; accepted work is tracked through GitHub issues and milestones.
- iPad external beta through TestFlight
- PBLE/1 editing, run/stop, console, and file workflows over BLE
- Offline Blockly with beginner GPIO and NeoPixel examples
- Browser installation for qualified `esp32-4mb` and `esp32-s3-n16r8`
profiles
- Browser installation for the exact `esp32-4mb` and `esp32-s3-n16r8` profiles
as the v0.4.2 hardware-tested beta; production Chrome install/recovery passed
on both profiles
- MIT-licensed app, agent firmware, protocol, website, tests, and release tools

## Near term

- Re-establish firmware release provenance from the canonical public history
- Complete the app, PBLE/1, resource, and remaining firmware release
qualification for the exact v0.4.2 bytes
- Complete real-hardware qualification before enabling the ESP32-C3 installer
- Expand user-facing setup, recovery, and board-specific wiring guidance
- Open and document the Android beta distribution path
Expand Down
27 changes: 14 additions & 13 deletions docs/specifications/firmware.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# PyBLE — Agent Firmware

Status: **DRAFT** · Last updated: 2026-07-30
Status: **DRAFT** · Last updated: 2026-08-01

The PyBLE agent is small board-side firmware that turns a compatible
MicroPython target into a PyBLE-speaking board: it advertises the BLE service,
Expand Down Expand Up @@ -67,14 +67,15 @@ confined to Layer 2 (board overlay: pins, flash size, USB), and the shared agent
core contains no per-chip product logic.

The browser installer does not publish unqualified family-wide images. The
v0.4.2 candidate set is `esp32-4mb` (classic ESP32, 4 MiB flash) and
`esp32-s3-n16r8` (ESP32-S3, 16 MiB flash plus 8 MiB Octal PSRAM), but the
public browser installer remains unavailable pending final HIL on the exact
candidate bytes for both profiles. `esp32-c3-4mb` remains a known initial v1
profile but is not released or selectable until exact-profile real-hardware
validation is complete. ESP Web Tools detects the chip family but cannot by
that fact alone prove the required flash/PSRAM topology. The full compatibility
and artifact contract is frozen in
exact v0.4.2 bundle is offered as a hardware-tested beta for `esp32-4mb`
(classic ESP32, 4 MiB flash) and `esp32-s3-n16r8` (ESP32-S3, 16 MiB flash plus
8 MiB Octal PSRAM). On both exact profiles, browser installation and interrupted-flash recovery passed;
complete release qualification remains pending.
`esp32-c3-4mb` remains a known initial v1 profile but is unavailable
and has no public image until exact-profile real-hardware validation is
complete. ESP Web Tools detects the chip family but cannot by that fact alone
prove the required flash/PSRAM topology. The full compatibility, artifact, and
bounded public-beta contracts are frozen in
[firmware/browser-flashing.md](firmware/browser-flashing.md).

These targets are the initial reference/build family, not the product boundary.
Expand Down Expand Up @@ -118,13 +119,13 @@ MUST NOT require a known-chip allowlist.
The measurement method is frozen in
[firmware/specs.md §5.3](firmware/specs.md#53-footprint-gates-nfr-fp);
numeric values remain provisional until derived from retained baseline samples.
The v0.4.2 candidate qualification scope is profile-scoped:
The current v0.4.2 qualification work remains profile-scoped:

| Profile | Current numeric status | Release effect |
|---|---|---|
| `esp32-4mb` | Measure, derive, freeze, and verify on the owned exact profile | Required before v0.4.2 candidate qualification and installer activation |
| `esp32-s3-n16r8` | Measure, derive, freeze, and verify on the owned exact N16R8 profile | Required before v0.4.2 candidate qualification and installer activation |
| `esp32-c3-4mb` | Deferred; no current threshold or HIL row | Blocks C3 enablement and v1.0, but not qualification of the two-profile candidate |
| `esp32-4mb` | Browser install/recovery passed; numeric/resource qualification pending | Enabled only by the exact v0.4.2 public-beta exception; required for qualification |
| `esp32-s3-n16r8` | Browser install/recovery passed; numeric/resource qualification pending | Enabled only by the exact v0.4.2 public-beta exception; required for qualification |
| `esp32-c3-4mb` | Deferred; no current threshold or HIL row | Blocks C3 enablement and v1.0; absent from the v0.4.2 beta |

The enforced metrics are:

Expand Down
47 changes: 28 additions & 19 deletions docs/specifications/firmware/TDD.md
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,10 @@ Download (`FILE_GET_*`) is the symmetric streamer: `FILE_GET_BEGIN{path,offset}`

Static, boot-time allocation of all large buffers (D3) makes resource
headroom repeatable enough to measure after HELLO and after transfer workloads.
The current pre-v1 release measures the owned exact profiles
`esp32-4mb` and `esp32-s3-n16r8`. The S3's PSRAM is useful Python headroom but
The current v0.4.2 public-beta qualification work measures the owned exact
profiles `esp32-4mb` and `esp32-s3-n16r8`. Its supplemental production-browser
rows passed, while its formal resource and remaining HIL rows stay open. The
S3's PSRAM is useful Python headroom but
MUST NOT conceal internal-RAM pressure, so the gate records Python GC memory
and internal ESP-IDF heap separately. The design still targets the
**ESP32-C3 floor** for v1.0 (single-core RISC-V, ~400 KB SRAM —
Expand Down Expand Up @@ -720,10 +722,12 @@ pipeline while retaining the shared PBLE/1 conformance gates.
generate THIRD_PARTY_LICENSES.txt mechanically BLD-8/14
11. run no-leak, SPDX, manifest/integrity/license/reproducibility gates CON-6,
BLD-14/18
12. publish identical immutable bytes to the versioned same-origin path
and matching GitHub Release only after every included profile passes HIL;
the current pre-v1 gate covers esp32-4mb and esp32-s3-n16r8, while C3 is
unavailable until a later candidate BLD-7/21/22
12. publish identical immutable bytes to the versioned same-origin path and
matching GitHub Release only after every included profile passes HIL;
alternatively, the exact digest-bound v0.4.2 exception may publish the two
profiles as a hardware-tested beta and GitHub pre-release after both pass
the scoped production-browser install/recovery run; C3 stays unavailable
BLD-7/21/22
```

### 10.2 Entry points
Expand Down Expand Up @@ -774,8 +778,8 @@ exact public tree, manifest, separate integrity/provenance metadata, recovery,
HIL report, activation, and rollback are frozen in
[browser-flashing.md](browser-flashing.md). Identical immutable bytes publish
both at the versioned `pyble.dev` path and through the matching GitHub Release,
with exact release-profile parity: two qualified profiles in the current
pre-v1 release and all three at v1.0 (BLD-7/17…22). `DEVICE_INFO`/HELLO,
with exact release-profile parity: two hardware-tested beta profiles in v0.4.2
and all three qualified profiles at v1.0 (BLD-7/17…22). `DEVICE_INFO`/HELLO,
`manifest.json`/`release.json`, tag, and release notes make agent/protocol/
upstream/source/artifact versions recoverable (BLD-13); the agent follows
SemVer (BLD-12).
Expand Down Expand Up @@ -1077,7 +1081,7 @@ Chip facts are owned by [hardware.md §1](../hardware.md#1-supported-chip-famili
frozen-Python does not fit, hot paths go native (D1,
[§8.6](#86-esp32-c3-mitigation)). The known `esp32-c3-4mb` provisioning
profile is defined only for C3 silicon revision v0.3 or newer but remains
unavailable in the current pre-v1 release pending exact-profile HIL. Its
unavailable in the current v0.4.2 public beta pending exact-profile HIL. Its
exact image revision window appears in release metadata only after a later
candidate qualifies it.

Expand Down Expand Up @@ -1155,22 +1159,27 @@ PBLE/1 **conformance** tests run against an **in-memory fake transport** shared
toolchain-distribution license bytes from the trusted ESP-IDF download cache,
exact metadata/cache/install binding with distinct archive and version roots,
absence of host-absolute paths in receipts, and profile-specific zero-input
not-shipped proof.
not-shipped proof. Supplemental source-tree digests exclude Python bytecode
cache artifacts while the audit rejects any such artifacts in the retained
checkout; release builds force bytecode generation off so checkout-local
absolute paths cannot contaminate otherwise identical source evidence.
- **size:** enforce the total application-image ceiling and derived
factory-partition headroom floor during build/candidate validation. Continue
structural application-fit checks on all three source targets, including
deferred C3. Heap, boot, goodput, and reliability are not mislabeled as
static size gates.
- **HIL:** the release-blocking bench runs on every exact profile included in
the release. For the current pre-v1 candidate that is exactly
the release. For the v0.4.2 formal candidate matrix that is exactly
`esp32-4mb` and `esp32-s3-n16r8`; it covers the frozen §8.5 resource
workload, multi-file integrity (NFR-REL-5), STOP authority (NFR-SAFE-1),
cold-boot safety (NFR-SAFE-3), candidate-browser install, and
interrupted-flash recovery from an access-controlled,
production-equivalent HTTPS deployment (BLD-20/21). C3 HIL and
footprint/goodput gates remain open, block C3 enablement, and block v1.0.
Public activation then needs only the non-destructive origin/integrity smoke
defined by BLD-22.
The later supplemental production-browser run completed only the browser
install and interrupted-recovery rows for both profiles. The other formal
rows remain open; the exact public-beta activation follows the bounded
exception in browser-flashing §10 rather than claiming BLD-21 completion.

### 14.4 Required red matrix for pre-v1 qualification

Expand Down Expand Up @@ -1240,12 +1249,12 @@ Design element → satisfied requirement IDs. Each `FR-*` block has at least one
- **R2 — Frozen→native trigger point.** Which paths move to C, and on which chip the budget forces it, is undecided until HIL measurement (OI-3). The module boundaries ([§4](#4-module-design)) are drawn to make the move contract-neutral (NFR-MAINT-3).
- **R3 — iOS/Android BLE MTU quirks.** Central platforms negotiate MTU differently and may not grant 247; the firmware must operate correctly across the negotiated MTU down to the default (FR-BLE-8). Fragmentation/reassembly is tested across an MTU matrix ([§14.1](#141-per-module-verification-approach)).
- **R4 — Single-core C3 STOP latency.** With one core the runner and BLE/agent task time-share; STOP must still land promptly against a tight loop ([§5.2](#52-stop-delivery)). Validate on C3 HIL first ([§11](#11-per-chip-design-notes)).
- **R5 — Candidate pins not yet selected or HIL-approved.** `versions.lock`
values (MicroPython v1.28.0 / ESP-IDF v5.5.1) remain proposed defaults until
selected as candidate-frozen inputs before the release builds and HIL
(OI-2). Candidate-freezing makes the input immutable; it does not approve
C3 compatibility or public release. A pin change creates a new candidate and
reruns all build, audit, deployment, and exact-profile HIL gates through
- **R5 — v0.4.2 candidate pins are selected but not fully HIL-approved.** The
exact `versions.lock` values (MicroPython v1.28.0 / ESP-IDF v5.5.1) are
candidate-frozen for v0.4.2 (OI-2). Candidate-freezing makes the input
immutable; it does not approve the remaining formal matrix, C3 compatibility,
or a qualified release. A pin change creates a new candidate and reruns all
build, audit, deployment, and exact-profile HIL gates through
`upgrade_micropython.sh` (BLD-9/19/21).
- **R6 — PBLE/1 still DRAFT.** Opcode/UUID/status numbers are provisional until [protocol.md](../protocol.md) §2/§4 freeze (OI-4); the single constants mirror (D6) localizes the churn.
- **R7 — Auto-run caps flag naming.** The opt-in `main.py` auto-run flag name/encoding is owned by [protocol.md §7](../protocol.md#7-hello--capabilities) and must be fixed before F-12 (OI-5).
Expand Down
Loading
Loading