Skip to content

Commit 9badcdb

Browse files
committed
[docs] close classic workspace incident and record real recovery workflow
Signed-off-by: Viwat Vchirawongkwin <viwat.v@chula.ac.th>
1 parent 709556e commit 9badcdb

4 files changed

Lines changed: 163 additions & 11 deletions

File tree

‎docs/developments/2026-q4-reliable-workflow/c1-s2/00_Execution_Record.md‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ records the final complete run and exact candidate revision before acceptance.
7070
| DR-T07 | Explicit Restore/Discard, failed discard, volatile Retry, late hydration and no implicit board writes | Automated suite and Lenovo Restore/offline preview/relaunch pass; complete interaction matrix pending |
7171
| DR-T08 | Deterministic 500ms / continuous-edit 2s scheduling; delayed commits, startup timeout and epoch tests | Component tests passing; physical lifecycle interruption pending |
7272
| DR-T09 | Active write/replacement serialization, tombstones and no queued resurrection | Automated integrated suite passing |
73-
| DR-T10 | Recovered-target cancellation and stale document/path/session consent | Recording-connection tests passing; physical target consent pending |
73+
| DR-T10 | Recovered-target cancellation and stale document/path/session consent | Recording-connection tests and Lenovo current-target Save/Run consent pass; iPad physical board consent pending |
7474
| DR-T11 | Stable-facade board swap, delayed GET, stale completion and PUT-to-Run attachment refusal | Recording-connection tests passing; final integrated regression pending |
7575
| DR-T12 | Explicit generated text handoff with editor-epoch/revision guards; existing workspace/sidecar behavior retained | Affected automated regression required in final suite; representative device checks pending |
7676
| DR-T13 | Local/board status separation, ARB error/status copy, disconnected preview, keyboard and 2× text | Automated UI/localization pass; physical Lenovo 2× preview observed; local golden baseline mismatch reproduced unchanged, pinned CI pending |
@@ -115,13 +115,19 @@ All 33 rendered test images match byte-for-byte with the same tests run from
115115
unchanged `origin/main` at `8dde8d6` on this host. Existing baselines are retained;
116116
this result is not a golden pass. The workflow pins macOS 15, whose result is
117117
tracked on [draft PR #40](https://github.com/PyBLE-dev/PyBLE/pull/40).
118-
The source and documentation are reviewable on `feature/current-draft-recovery`.
118+
At `709556e`, both the push and pull-request workflow runs passed all 18 jobs
119+
(36 successful checks total), including the pinned golden and native Android
120+
jobs. Subsequent changes in this record are documentation-only; their workflow
121+
state remains visible on the PR. The source and documentation are reviewable
122+
on `feature/current-draft-recovery`.
119123
No merge or store publication is implied by that draft.
120124

121125
The final boundedness audit added SQL byte/count preflights before metadata or
122126
row materialization: corrupt metadata is capped before JSON reaches the UI
123127
isolate. The final ordinary suite is 972 passing tests. [Platform results](02_Platform_Qualification.md)
124128
include successful iPad profile assertion receipts and a killed-process boundary.
125-
Five powered boards were reported by the owner; the Lenovo fresh scan currently
126-
shows four advertisements, with historical classic ESP32 label `8C9E` absent.
127-
That discovery observation is under investigation and is not a four-result cap.
129+
All five boards now appear in the Lenovo scan after the [classic ESP32 recovery](03_Classic_ESP32_Workspace_Recovery.md).
130+
Its workspace exactly matched an intentional invalid-media fixture left by an
131+
earlier qualification run. A fresh backup and the verified valid original
132+
workspace were preserved; restoring only that region returned `8C9E` to normal
133+
advertising. No firmware or scan-count logic changed.

‎docs/developments/2026-q4-reliable-workflow/c1-s2/02_Platform_Qualification.md‎

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ technology and P01–P15 coverage are still outstanding.
6767
| Release compile | `flutter build ios --release --no-codesign` succeeded in the isolated copied project |
6868
| Signed harness compile | `flutter build ios --debug --target integration_test/draft_recovery_device_qualification.dart --dart-define=PYBLE_RECOVERY_TEST_PHASE=seed` succeeded using an available development identity |
6969
| Installation | Direct `devicectl` installation of the signed isolated harness succeeded; the existing TestFlight application was preserved |
70-
| Launch | Both wireless and USB Flutter attempts reported that Developer Mode must be enabled; no successful harness or production-UI execution is claimed |
71-
| Next action | Owner enables Settings → Privacy & Security → Developer Mode, restarts/confirms if required, unlocks and reconnects; then execute seed → terminate → verify and P01–P15 as applicable |
70+
| Launch | Wireless and USB Flutter debug attempts reported that Developer Mode must be enabled; subsequent signed profile harness execution succeeded as recorded below |
71+
| Next action | Complete production UI/board P01–P15 as applicable. Profile seed → terminate → verify has passed using current settings; Developer Mode remains an optional prerequisite for the separate debug/JIT route |
7272

7373
A signed build is build evidence. It does not establish successful installation,
7474
execution, offline restoration, TestFlight availability or physical BLE behavior.
@@ -106,10 +106,26 @@ Names are contextual labels, not new identity or authorization evidence.
106106
Source inspection found no four-result limit: the adapter filters by PBLE
107107
service UUID, the accumulator retains distinct OS device IDs and the list
108108
renders the complete hit count. Both ESP/Pico agents resume advertising after
109-
disconnection. An active connection elsewhere or absent firmware advertising
110-
can explain a missing board, but neither cause has yet been established for
111-
`8C9E`. USB enumeration of its CP2102 adapter alone does not prove agent health.
112-
No board was reset, flashed or sent a command during this diagnosis.
109+
disconnection. The live classic ESP32 was subsequently identified through its CP2102 ROM
110+
interface: ESP32-D0WD revision 1.0, base MAC ending `8C:9C` (Bluetooth suffix
111+
`8C9E`). A 115200-baud read of the first 256 KiB matches the retained c8f549ee
112+
0.6.1 install prefix at offset 0x1000. The initial 460800-baud attempt had a
113+
framing error; no flash write occurred. Exact complete-image equivalence is
114+
not inferred from a prefix.
115+
116+
A 45-second controlled startup trace then captured:
117+
`PyBLE workspace recovery is required; reconnect by USB.`, followed by the
118+
MicroPython 1.28.0 / PyBLE 0.6.1 banner and REPL. This confirms the workspace
119+
mount/refusal path, which deliberately withholds BLE agent startup. It explains
120+
the absent fifth advertisement. Short early captures missed the later message;
121+
the guard scans the complete 2 MiB workspace before refusing it.
122+
123+
Retained September qualification records for the same board contain an
124+
intentional invalid-media fixture and a failed acquisition before its planned
125+
recovery. Its fixture hash is preserved separately; this history alone does not
126+
prove current contents. The fresh complete current workspace backup exactly matched that refusal fixture. The verified original owner backup
127+
and its valid LFS2 workspace remain intact, with identical partition geometry.
128+
ROM reads and startup tracing involved controlled resets. The verified valid pre-test workspace was then restored only to its original region, and the next scan shows all five boards. See the [recovery report](03_Classic_ESP32_Workspace_Recovery.md) for backups, hashes, offline inventory and the verified write.
113129

114130
## Remaining release evidence
115131

@@ -118,3 +134,39 @@ explicit harmless physical board Save/Run/Files destination consent, applicable
118134
Blocks handoff checks and the selected release matrix. Preserve candidate
119135
provenance and report every unrun row. Participant follow-up and the unfinished
120136
M-01/SG0 pilot work remain separate from engineering recovery evidence.
137+
138+
## Lenovo production workflow on recovered classic ESP32
139+
140+
The final production entry connected to `8C9E` and showed **Ready**, runtime
141+
`esp32` and agent **0.6.1**. The initial Editor was empty. A disposable
142+
`print(123)` draft was entered, explicitly checkpointed and shown **Saved
143+
locally**. The app was force-stopped and relaunched; startup preview offered the
144+
exact text before any connection. Explicit Restore displayed it while
145+
Disconnected. Only then was the classic board selected again.
146+
147+
Board Save displayed the exact `/untitled.py` destination and explained that
148+
upload does not run code. Cancel dismissed that choice. A subsequent explicitly
149+
confirmed upload succeeded and cleared board-dirty state while local status
150+
remained separate. Run requested separate upload-and-run consent for the same
151+
current destination. On confirmation the board console returned `123` and
152+
**Finished**, and the connection returned Ready. Files refresh showed the
153+
10-byte test file. The transfer stayed on the selected physical board; this is
154+
an observed happy path, not a physical board-swap race test.
155+
156+
Raw UI XML records under the ignored evidence directory include
157+
`lenovo-live-relaunch-prompt.xml`, `lenovo-live-restored-offline.xml`,
158+
`lenovo-real-save-consent.xml`, `lenovo-real-run-consent.xml` and
159+
`lenovo-print-run-result.xml`. The automated recording seams remain the evidence
160+
for exact zero-verb cancellation/race assertions; no radio packet capture was
161+
claimed for the physical cancellation.
162+
163+
Afterward only the created 10-byte `/untitled.py` test file was explicitly
164+
deleted, with its exact-name confirmation. Existing directories were preserved.
165+
New then committed the empty local slot; the disposable Editor text was cleared
166+
and its saved-local status retained. A fresh launch after that tombstone showed no stale recovery prompt or test text, and the final disconnected scan again showed all five boards.
167+
168+
The iPad's isolated harness was terminated and removed after its receipts,
169+
checkpoint files and signed archives were retained. The original TestFlight
170+
application remained installed and was brought forward without terminating it.
171+
The separate Lenovo production-entry candidate remains available for review;
172+
its test draft and board test file were cleared as described above.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<!-- SPDX-License-Identifier: MIT -->
2+
<!-- Part of PyBLE (https://pyble.dev) — see /LICENSE. -->
3+
4+
# Classic ESP32 — missing advertisement and workspace recovery
5+
6+
| Field | Record |
7+
|---|---|
8+
| Date | 31 October 2026; Asia/Bangkok |
9+
| Trigger | Owner connected all five boards but Lenovo scan showed four |
10+
| Physical board | Classic ESP32-D0WD revision 1.0; CP2102 adapter; ROM base MAC ending `8C:9C`, Bluetooth suffix `8C9E` |
11+
| Missing / present | `8C9E` absent; `C81A`, `3DCB`, `5646` and `DA86` present |
12+
| Confirmed cause | Workspace contained exactly the intentional invalid-media fixture from the earlier qualification run; firmware correctly refused mounting and withheld BLE agent startup |
13+
| Result | Verified pre-test workspace restored; native scan subsequently shows all five boards including `PyBLE-8C9E` |
14+
| Firmware | Existing PyBLE 0.6.1 retained; no application, bootloader or partition-table update |
15+
| Evidence | Ignored `local/recovery-implementation/`: startup trace, fresh backups, hashes, restoration log, offline inventory and five-board UI XML |
16+
17+
## Diagnosis and preservation
18+
19+
Source inspection established that there is no four-result limit. The adapter
20+
filters only by PBLE service UUID, the accumulator retains distinct OS device
21+
IDs and the UI renders the full result count. Pico 2 W (`3DCB`) was present.
22+
23+
Serial ownership was free. Short UART captures saw only the ROM boot; a longer
24+
45-second controlled capture reached the workspace recovery message, then the
25+
MicroPython 1.28.0 / PyBLE 0.6.1 banner and REPL. This is the intentional
26+
[nonblank-media protection](../../../specifications/firmware/TDD.md#91-filesystem)
27+
path, rather than evidence of unsupported silicon or a scan-list cap. The
28+
complete read-only media scan explains the delayed startup message.
29+
30+
A 115200-baud ROM read established that the installed first 256 KiB matches the
31+
retained c8f549ee candidate image prefix at flash offset 0x1000. An earlier
32+
460800-baud attempt had framing errors; no write was attempted at that speed.
33+
Only prefix correspondence is claimed, not an independently read whole-image
34+
hash.
35+
36+
The fresh **entire 2 MiB workspace** exactly matched the earlier refusal fixture:
37+
first 8,192 bytes `0x00`, remainder `0xFF`. This proves the current region contains
38+
the synthetic test fixture rather than a new user filesystem. The earlier run
39+
failed after that test and never produced its planned erased-media/recovery
40+
receipt. That leftover test state should have been restored before handback.
41+
42+
| Preserved or prepared input | SHA-256 / validation |
43+
|---|---|
44+
| Fresh current workspace backup | `cc5fcfcad390f42a5f7b0603f08f0142e9d0618c3ac102cb2ffab08722626ee1`; 2,097,152 bytes, exact equality with retained fixture |
45+
| Immutable original full owner backup | `2aa2280b9fa0d66bbd60e73d0858e8df62f8025aa1e93f1c900ea86eb36aca3e`; rehashed before extraction |
46+
| Original valid workspace extraction | `33490a100808d7fc89854d079bfa072e53ee0d48a80aa2ce8cd895ca643a0f37`; same 2 MiB region and identical partition geometry |
47+
| Offline original-workspace inspection | Explicit LFS2 mount on a copied buffer; one empty diagnostic `.pbltmp` file, no user programs or boot scripts; original bytes unchanged |
48+
| Existing NVS region | Erased in the captured image; workspace restoration does not restore old autorun settings |
49+
50+
The offline reader (`littlefs-python` 0.19.0) was installed only in an ignored
51+
inspection environment. Its buffer was mounted explicitly without formatting;
52+
no board or immutable backup was changed during inspection. It is not an app
53+
or firmware dependency.
54+
55+
## Controlled restoration and result
56+
57+
The explicit operator restoration wrote **only flash 0x200000–0x3fffff**, using
58+
the verified original workspace extraction. Both current and original backups
59+
remain preserved. The operation restored the board from synthetic test data to
60+
its valid pre-test workspace; it did not format unknown owner data or install a
61+
new firmware image.
62+
63+
The flash tool reported `Hash of data verified.` before its normal reset. The
64+
next native Lenovo scan included `PyBLE-8C9E` at approximately −45 dBm and
65+
reported **Boards seen: 5**. The other four advertisements remained present.
66+
67+
```mermaid
68+
flowchart LR
69+
FIXTURE["Invalid test fixture left on board"] --> REFUSE["Workspace mount refused"]
70+
REFUSE --> OFF["BLE agent not started"]
71+
OFF --> FOUR["Four boards visible"]
72+
BACKUP["Fresh backup and verified original workspace"] --> RESTORE["Restore workspace region only"]
73+
RESTORE --> MOUNT["Valid LFS2 mount"]
74+
MOUNT --> ADV["8C9E advertises again"]
75+
ADV --> FIVE["Five boards visible"]
76+
```
77+
78+
## Future qualification handback
79+
80+
After intentional invalid-media or interrupted-install tests, retain the actual
81+
failed evidence and explicitly restore or hand off the disposable board state.
82+
A completed host report does not prove that the physical board is ready for
83+
ordinary use. Verify normal startup and advertisement, and record remaining
84+
work before disconnecting the bench. Do not run old destructive qualification
85+
collectors as a recovery shortcut or silently format a nonblank workspace.

‎tests/firmware_tests/hil/README.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,15 @@ finishes post-readback in loader mode; returning to normal runtime or another
152152
clean install is a separate, explicitly sequenced qualification operation.
153153
Keep both receipts and all their siblings beside the later hardening result.
154154

155+
Before handing a board back for ordinary use, account for intentional
156+
invalid-media fixtures even when acquisition failed. Preserve the failed
157+
receipts and fresh current-media backup, then explicitly restore the verified
158+
pre-test workspace or record that the board remains in recovery. Verify normal
159+
startup and advertising after that separate operation. A host report or USB
160+
connection does not establish runtime readiness. See the [classic ESP32
161+
recovery record](../../../docs/developments/2026-q4-reliable-workflow/c1-s2/03_Classic_ESP32_Workspace_Recovery.md)
162+
for the diagnosed leftover-fixture case; do not silently format nonblank media.
163+
155164
The live runner receives the protected candidate directory, exact profile,
156165
private BLE address, both receipt paths, and new raw-log/output paths. It emits
157166
no passing result unless all seven live scenarios and both pre-service

0 commit comments

Comments
 (0)