|
1 | 1 | <!-- SPDX-License-Identifier: MIT --> |
2 | 2 | <!-- Part of PyBLE (https://pyble.dev) — see /LICENSE. --> |
3 | 3 |
|
4 | | -# iPad recovery acceptance continuation |
| 4 | +# iPad recovery and app compatibility acceptance |
5 | 5 |
|
6 | 6 | | Field | Record | |
7 | 7 | |---|---| |
8 | 8 | | Date | 31 October 2026, Asia/Bangkok | |
9 | | -| Scope | Remaining normal-app recovery and affected workflow observations for PYB-006.2 / PYB-008.1 | |
10 | | -| Current outcome | Candidate installation and launch pass; automated native UI execution awaits the device owner's iPadOS authentication | |
11 | | -| Source | PR #40 merged at `6f5b3ea73a70342331fb49d0685938ce2a4cae11`; subsequent planning changes do not change app runtime bytes | |
| 9 | +| Scope | Normal-app recovery and affected workflow observations for PYB-006.2 / PYB-008.1; app-only compatibility rows Q01/Q03/Q05/Q07/Q09 | |
| 10 | +| Outcome | Exact offline restoration, current-board consent and normal Blocks-generated text recovery observed; final keyboard repair and all five app-only iPad board rows pass within the recorded scope below | |
| 11 | +| Current runtime | `bef67bded9e5b83437e3eb0e2ec4be6a4cfd1a64`, app tree `60b3a68b693551af5d83076547c502f69838e052`; PR #41 | |
12 | 12 | | Candidate | PyBLE Preview `0.3.0 (9)`, normal `lib/main.dart`, signed profile mode, isolated `dev.pyble.recoveryqualification` identity | |
13 | | -| Physical platform | iPad Air 13-inch (M4), model `iPad16,10`, iPadOS `26.6.2` | |
14 | | -| Operator | Automated engineering run on the maintainer's Mac; no independent human review or participant observation claimed | |
15 | | -| Prior results | [Platform observations](02_Platform_Qualification.md); native storage seed/kill/verify is distinct from normal-app interaction acceptance | |
16 | | - |
17 | | -## Candidate and initial state |
18 | | - |
19 | | -The signed app archive is retained privately as |
20 | | -`local/recovery-implementation/ipad-preview-0309/PyBLE-Preview-0.3.0-9-profile.app.zip`. |
21 | | -Its SHA-256 is |
22 | | -`c91bc6f7e14f421a528668bd3723e3f965d55f79f11ea90fec707a8fb15a4d1a`. |
23 | | -The copied Dart runtime matches merged source; only the isolated native identity |
24 | | -and display name distinguish the installation. Signature verification, |
25 | | -installation and foreground launch passed. The disconnected scan displayed all |
26 | | -five board labels. Discovery alone does not establish a connection or completed |
27 | | -board workflow. |
28 | | - |
29 | | -The existing TestFlight `dev.pyble.pyble` installation remains version |
30 | | -`0.2.0 (6)`. The Preview application support files were copied privately before |
31 | | -continuation. The copied SQLite database passes `integrity_check` and contains |
32 | | -zero draft rows and zero content bytes. No storage reset, user-data deletion or |
33 | | -board write was used to establish that initial state. |
34 | | - |
35 | | -## Native UI runner attempt |
36 | | - |
37 | | -| Step | Actual observation | |
| 13 | +| Physical platform | iPad Air 13-inch (M4), model `iPad16,10`, iPadOS `26.6.2`, wired to the maintainer's Mac | |
| 14 | +| Operator | Automated engineering run through native XCTest; no independent human review, participant observation or audible VoiceOver evaluation claimed | |
| 15 | +| Prior results | [Platform observations](02_Platform_Qualification.md); storage seed/kill/verify is distinct from this normal-app interaction evidence | |
| 16 | + |
| 17 | +## Installed artifacts and continuity |
| 18 | + |
| 19 | +| Runtime | Private archive SHA-256 | Observations | |
| 20 | +|---|---|---| |
| 21 | +| Merged PR #40 `6f5b3ea` | `c91bc6f7e14f421a528668bd3723e3f965d55f79f11ea90fec707a8fb15a4d1a` | Initial installed identity and five-board discovery; superseded for layout qualification | |
| 22 | +| Landscape repair `e54a78a` | `ddf611e85065db05c1622faef59c6eddc5b821dfd1a2702ec0cbb66d093e5a0b` | Unicode lifecycle/offline recovery, current-target consent, empty named draft and classic ESP32 workflow | |
| 23 | +| Native dismissal `01a7ac8` | `3a2775d1648fe3a188b89f30912af0b7f771ec08b8c0e3b9f4d0c3d49d33510b` | Blocks-to-Editor recovery and C3 workflow; input-palette geometry defect reproduced | |
| 24 | +| Native keyboard guide `bef67bd` | `7d39100283fb2cd9189d448881b788ad5eadfdf813a0e5f36ff9a2850fa6c471` | Clean profile build; exact Dart/AppDelegate source manifest matches the runtime; compiled guide channel present and diagnostic instrumentation absent | |
| 25 | + |
| 26 | +Archives, source manifests, native accessibility trees, screenshots and |
| 27 | +`.xcresult` bundles are retained under ignored |
| 28 | +`local/recovery-completion/ipad/`; the original baseline archive is under |
| 29 | +`local/recovery-implementation/ipad-preview-0309/`. Only bundle/display identity |
| 30 | +differs from the normal application. Signature verification and installation |
| 31 | +pass. Installs reuse the same Preview container without clearing its data. |
| 32 | + |
| 33 | +The existing TestFlight `dev.pyble.pyble` installation remains `0.2.0 (6)`. |
| 34 | +Preview acceptance does not establish a TestFlight-delivered upgrade. Before |
| 35 | +these runs, a private backup of Preview application support passed SQLite |
| 36 | +`integrity_check` and contained zero draft rows and zero content bytes. No |
| 37 | +storage reset established that initial state. |
| 38 | + |
| 39 | +## Recovery observations |
| 40 | + |
| 41 | +The [operator recipe](01_Operator_Recipe.md) and |
| 42 | +[normative evidence matrix](../../../specifications/App/current-draft-recovery.md#7-required-evidence-before-acceptance) |
| 43 | +remain authoritative. A receipt marked partial below contributes only its |
| 44 | +completed assertions; its later failure is retained separately. |
| 45 | + |
| 46 | +| Procedure | Actual result and receipt | |
| 47 | +|---|---| |
| 48 | +| P01/P04/P06: offline startup and Restore | `offline-restore-radio-target`: terminate the same app/container, explicitly verify Wi-Fi and Bluetooth off, relaunch, inspect exact filename/source, Restore into the disconnected local panel. No connection is required. Original radios restored | |
| 49 | +| P02/P03: exact named checkpoint | `classic-unicode-checkpoint`: `/q0309i_e54a/recovery.py`, exact `# café λ` followed by `print(271828)`; native text-value assertion and **Saved locally** after manual checkpoint | |
| 50 | +| P05: unresolved decision | Discard Cancel preserves the exact preview. In `classic-discard-loop`, backgrounding to Settings and returning preserves the unresolved recovery prompt | |
| 51 | +| P07: editing/lifecycle | Real native typing and multiple acknowledged checkpoints survive process termination/relaunch. On final `bef67bd`, `settled-native-input` injects the complete `print(424242` batch after the full keyboard is visibly settled, obtains exact `print(424242)`, checkpoints and restores it after termination without a board write. Continuous-edit debounce behavior remains covered by automated tests; no unacknowledged final keystroke is promised durable | |
| 52 | +| P08: explicit Discard | `classic-discard-loop` completes Cancel, confirmed Discard and terminate/relaunch assertions: the next launch shows Scan without a recovery prompt. Its later folder-tap failure does not erase these observations | |
| 53 | +| P09: empty named draft | `classic-readback-empty`: deliberately created `empty.py` checkpoints and returns as a named empty recovery copy; distinct from an empty untitled slot | |
| 54 | +| P10: actual Save/Run target | `classic-target-cancel`: both current destination `/recovery.py` and distinct write/write-and-run effects are shown; Cancel retains the draft. The board is deliberately connected after Restore | |
| 55 | +| P11/P12: Files destination and completion | `classic-upload-run`: move to the owned folder, cancel Upload, confirm its actual folder/file target, then explicitly confirm Run and observe `271828` with Finished. Real clear/Open readback verifies the Unicode source. Session/epoch mutation races remain covered by automated tests | |
| 56 | +| P13: replacement guards | `blocks-handoff-recovery` cancels Blocks handoff over Unicode before later confirming. `c3-replacement-finite` and its resume cancel Editor New and board Open over the meaningful generated draft; source remains exact | |
| 57 | +| P14 / DR-T12: generated text | `blocks-handoff-recovery`: ordinary Hello example generates exact `print('Hello, PyBLE!')` plus trailing newline, guarded adoption into `blocks.py`, acknowledged checkpoint and actual process termination/relaunch recover that exact text. The next process's Blocks surface offers a new example; no workspace graph restoration is inferred | |
| 58 | +| P15 / DR-T13 | Widget/localization/semantics and 2× text coverage is recorded in source validation. Physical native keyboard checks are below. Native XCTest accessibility labels/values are observed; this is not a claim of audible VoiceOver speech or a complete human gesture evaluation | |
| 59 | + |
| 60 | +The offline panel intentionally previews restored text before connection; the |
| 61 | +normal Editor shell appears after an explicit board connection. An early final |
| 62 | +candidate helper incorrectly expected an Editor text field while still on that |
| 63 | +panel. The panel held the exact recovered text; the corrected connected check |
| 64 | +passed. That selector error is not a restoration failure. |
| 65 | + |
| 66 | +## Keyboard defects and physical regression |
| 67 | + |
| 68 | +Three separately tested repairs address measured failures: landscape overflow, |
| 69 | +native WebView keyboard dismissal, and the iPad input-palette transition. |
| 70 | +In the last case UIKit reported an off-screen end frame after **Hide keyboard → |
| 71 | +Keyboard → Show Keyboard**, while `keyboardLayoutGuide` reported the actual |
| 72 | +498-point occlusion. Private logging established that mismatch; its instrumented |
| 73 | +binary is excluded from acceptance and distribution. |
| 74 | + |
| 75 | +The final native guide observer supplies the missing geometry, and Flutter uses |
| 76 | +the larger valid platform/native inset without summing them. A remaining input |
| 77 | +palette is a real occlusion; hiding the full keyboard does not imply zero inset. |
| 78 | +Ending editing returns to ordinary safe-area layout. |
| 79 | + |
| 80 | +| Final `bef67bd` receipt | Actual observation | |
38 | 81 | |---|---| |
39 | | -| Build | Native XCTest helper builds successfully against the connected physical-device SDK; it operates the separately installed normal app | |
40 | | -| Runner startup | Signed helper starts on the iPad | |
41 | | -| OS authentication | iPadOS displays **Touch ID for “XCTest” — Enable UI Automation** | |
42 | | -| Result | Runner initialization times out after 60 seconds while enabling automation mode; the test body does not run | |
43 | | -| Classification | Operator-access dependency, not a failed PyBLE recovery assertion | |
44 | | -| Required action | Device owner authenticates the iPadOS prompt; retry the retained test and then execute the remaining workflow steps | |
| 82 | +| `guide-editor-connected` | Existing exact generated checkpoint restores; C3 Ready; the normal Editor receives native focus | |
| 83 | +| `guide-editor-palette` | Full keyboard shown, hidden and shown again through the native palette. Editor text-field height remains 218 points with the full keyboard; console Expand occupies y=478…526 above it. Expand is hittable, hides the actual native keyboard, restores the 555-point normal Editor viewport and preserves exact text. Screenshots and accessibility frames agree | |
| 84 | +| `guide-blocks-palette` | Native Blocks field repeats Hide → Show Keyboard; Expand remains hittable, dismisses the keyboard, and retains exact `Hello, PyBLE!`. Cancel closes the field without changing its block; returning to Editor retains the exact generated text | |
| 85 | + |
| 86 | +The final source has 984 passing ordinary tests, including guide geometry, |
| 87 | +observer lifecycle and stale-generation coverage. iOS profile compilation and |
| 88 | +repository analysis/source gates pass. Automated coverage does not replace the |
| 89 | +physical input-palette sequence above. |
45 | 90 |
|
46 | | -The owner was asked to authenticate on the device. No passcode or biometric |
47 | | -material was requested, captured or substituted. Raw screenshots and the |
48 | | -`.xcresult` remain in ignored `local/recovery-completion/ipad/`; they are not |
49 | | -public documentation assets. |
| 91 | +## App-only board matrix |
50 | 92 |
|
51 | | -## Acceptance accounting |
| 93 | +Immutable program verification identifies the selected firmware: classic ESP32 uses |
| 94 | +published `c8f549ee`; S3, Waveshare S3, C3 and Pico use retained observer |
| 95 | +`96497b9`. Exact component hashes and the source-impact assessment are in the |
| 96 | +[execution record](00_Execution_Record.md) and |
| 97 | +[release readiness](06_Release_Readiness.md). No firmware was reflashed for this |
| 98 | +app qualification. Identical relevant runtime/build-driver source does not make |
| 99 | +the two firmware artifacts byte-identical. |
52 | 100 |
|
53 | | -| Evidence | State after this attempt | |
| 101 | +| Row | Physical profile / suffix | Installed app | Result / receipt | |
| 102 | +|---|---|---|---| |
| 103 | +| Q01 | `esp32-4mb` / 8C9E | `e54a78a` | Pass: ordinary discovery/Ready, named Unicode edit/save, stdout/Finished, tight-loop Run/Stop→Idle, exact clear/Open readback, disconnect/reconnect continuity and recovery/current-target cases. Receipts `classic-*`; helper failures retained below | |
| 104 | +| Q03 | `esp32-s3-n16r8` / 5646 | `bef67bd` | Pass: ordinary Ready; owned finite source Save/Run→`424242`/Finished; tight-loop Run/Stop→Idle; true clear/Open exact readback of both files; disconnect/reconnect continuity; acknowledged `loop.py` checkpoint, terminate/relaunch and exact Restore. Receipts `matrix-5646*`; initial failed attempts retained | |
| 105 | +| Q05 | `waveshare-esp32-s3-lcd-147b` / DA86 | `bef67bd` | Pass: all common finite-output/Stop/readback/reconnect checks and named checkpoint/relaunch/Restore in one `matrix-da86` run | |
| 106 | +| Q07 | `esp32-c3-4mb` / C81A | `01a7ac8` | Pass: ordinary Ready, owned `blocks.py` upload/Hello stdout/Finished, genuine clear/Open readback, tight-loop and print-flood Stop→Idle, connection remains usable, reconnect continuity and subsequent bounded Hello run. `c3-replacement-finite-resume`, completed `c3-readback-stops` assertions, `c3-stop-flood-now`, `c3-final-matrix` | |
| 107 | +| Q09 | `rpi-pico2-w` / 3DCB | `bef67bd` | Pass after retained initial disconnect: `matrix-3dcb-retry` completes finite-output/Stop, true clear/Open readback, reconnect continuity and exact named checkpoint/relaunch/Restore | |
| 108 | + |
| 109 | +Earlier rows retain their actual installed identities. Later native/layout |
| 110 | +changes do not alter transport, storage or Stop behavior, but final keyboard |
| 111 | +checks are separately required. These UI Stop observations establish neither a |
| 112 | +fresh C3 firmware qualification nor a sub-500-ms wire-level timing result. |
| 113 | + |
| 114 | +## Retained failures and cleanup |
| 115 | + |
| 116 | +| Observation | Classification / disposition | |
54 | 117 | |---|---| |
55 | | -| Installed normal candidate, version and signature | Pass, limited to the local Preview identity | |
56 | | -| Foreground launch and five-board discovery | Pass, disconnected discovery only | |
57 | | -| Native storage process termination/reopening | Prior passing seed/verify evidence retained in the platform report | |
58 | | -| DR-T12 normal Blocks-to-Editor checkpoint/relaunch | Not run in this continuation; native UI access pending | |
59 | | -| DR-T14 normal offline Restore and physical current-board consent | Not run in this continuation; native UI access pending | |
60 | | -| Remaining applicable P01–P15 steps | Execute and record actual outcomes after UI authorization; the prepared test is not execution evidence | |
61 | | -| Five-profile iPad release rows | Pending; no qualification inferred from the five scan results | |
62 | | -| M-02 / release admission | Remain pending until mandatory evidence and review are complete | |
| 118 | +| XCTest Touch ID authorization timeout | Owner completed the prompt; normal-app native automation subsequently runs. Resolved operator-access dependency | |
| 119 | +| Newly installed helper launch denied while offline | Developer-certificate verification occurred before the test body. Retry entered offline mode within one running helper, verified both radios and passed; original radios restored | |
| 120 | +| Native helper folder/file selector and terminated-app screenshot errors | Corrected using observed controls and device-screen capture; exact retries retained. No passing result inferred from preparation | |
| 121 | +| C3 flood stdout prefix assertion | Existing Hello output preceded flood output in the same console label. Stop immediately returned Idle; retry cleared the console first and passed the intended stdout/Stop/readback/reconnect/bounded-run checks | |
| 122 | +| Rapid synthetic typing and initial file-row attempts on S3 | One batched XCTest `print(424242` input produced `print(24242)` and failed the exact oracle before Save. Waiting for the visible keyboard and observing automatic `print()` insertion before injecting digits produced exact text; this is a controlled retry, not a code fix. Source review found no digit-normalization rule; the suspected platform/controller feedback timing was not proven. A further final-candidate control injects the original whole batch after the keyboard is fully visible and settled and passes exact text plus checkpoint/relaunch/Restore (`settled-native-input`); the failure is not reproduced under that controlled focus condition. Two initial file-Open assertions also timed out; explicit retries obtained exact source after a genuine empty Editor, and their failures remain retained | |
| 123 | +| Early typing before async New-file GET completed | The editor epoch guard retained the newly typed buffer; no stale GET replaced it. A disposable classic `/untitled.py` was consequently written by the explicit Save/Run; this exact owned file was backed up and removed during coordinated cleanup | |
| 124 | +| Initial Pico connection | Reached Ready, then disconnected before folder creation. A continuation incorrectly assumed the old connected layout and selected the Waveshare scan row; its Name-field assertion failed before any write. Waveshare cleanup had already finished. The corrected retry explicitly disconnected, rescanned, checked Pico Ready and passed the complete row; no firmware or transport fix is claimed | |
| 125 | +| iPad input-palette geometry | Product defect reproduced with measured native frames; final repair and physical results above | |
63 | 126 |
|
64 | | -The [operator recipe](01_Operator_Recipe.md) and |
65 | | -[normative scenario matrix](../../../specifications/App/current-draft-recovery.md#7-required-evidence-before-acceptance) |
66 | | -remain the acceptance authority. This record does not change their requirements. |
| 127 | +Only disposable qualification files/folders are written. The classic fixtures |
| 128 | +and their CRC-verified backups/cleanup are recorded with the |
| 129 | +[Android continuation](05_Android_Acceptance.md); pre-existing root entries are |
| 130 | +preserved. The S3, Waveshare and Pico follow-up fixtures have likewise been CRC-verified, |
| 131 | +backed up and removed with unrelated root entries unchanged. C3 fixtures remain |
| 132 | +tracked privately for cleanup after the final Android continuation. Raw captures, binaries, database backups and helper |
| 133 | +sources remain ignored. No user project or original store installation is reset. |
| 134 | + |
| 135 | +This report establishes only its recorded observations. Final admission, |
| 136 | +production package identity and channel delivery are tracked in |
| 137 | +[release readiness](06_Release_Readiness.md); independent pilot and Ready-program |
| 138 | +obligations remain separate. |
0 commit comments