Skip to content

Commit 43b4af8

Browse files
committed
[docs] bind Android acceptance to final keyboard candidate
Signed-off-by: Viwat Vchirawongkwin <viwat.v@chula.ac.th>
1 parent fb97850 commit 43b4af8

1 file changed

Lines changed: 94 additions & 27 deletions

File tree

‎docs/developments/2026-q4-reliable-workflow/c1-s2/05_Android_Acceptance.md‎

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@
66
| Field | Record |
77
|---|---|
88
| Date / operator | 31 October 2026; automated operator on the maintainer's Mac |
9-
| State | Completed Android continuation within the physical scope and limitations recorded below |
9+
| State | Final-candidate affected checks passed; retained acceptance observations and candidate identities are distinguished below |
1010
| Physical device | Lenovo TB-J616X; Android 12 / API 31; landscape 2000 × 1200 pixels at 240 dpi |
1111
| App | `0.3.0 (9)`, normal `lib/main.dart`; isolated qualification application identity preserves the installed store app and its data |
12-
| Final runtime source | `01a7ac8acab32e926c185c8567f9b8dca08d3d68`; Android worktree runtime is byte-equivalent. The native package name alone is changed for the isolated identity |
13-
| Final profile APK SHA-256 | `afc50a741a07344047d3069c9d4a36c1111869b3286e67b0a9f8d4a61a408e89`; also verified against the installed `base.apk` |
14-
| Final arm64 AOT SHA-256 | `2ddb34eb36169466b5aa5aa32515e007354389f1ebdd276c0fdd40638e6e47a4` |
15-
| Final native DEX SHA-256 | `1b62aceb530a2d361980b18d009188994cf7c92118d22842af3a6293757b61bb` |
12+
| Final runtime source | `bef67bded9e5b83437e3eb0e2ec4be6a4cfd1a64`; app tree `60b3a68b693551af5d83076547c502f69838e052`. Android runtime inputs are hash-bound to this source; the native package name is substituted for the isolated identity |
13+
| Final profile APK SHA-256 | `945e9746559831c0d0f793d779bd53a0c53cc8395d02e50df3f45e9ff6790bcf`; also verified against the installed `base.apk` |
14+
| Final arm64 AOT SHA-256 | `b4e42e6b50a2cdd565b2fbcccd457aab1c512c20a40933c9a8674cf38c214a9c` |
15+
| Final `classes.dex` SHA-256 | `1b62aceb530a2d361980b18d009188994cf7c92118d22842af3a6293757b61bb` |
16+
| Native-keyboard profile | Source `01a7ac8acab32e926c185c8567f9b8dca08d3d68`; APK SHA-256 `afc50a741a07344047d3069c9d4a36c1111869b3286e67b0a9f8d4a61a408e89`; arm64 AOT SHA-256 `2ddb34eb36169466b5aa5aa32515e007354389f1ebdd276c0fdd40638e6e47a4` |
1617
| Original debug APK | Source equivalent to `6f5b3ea`; SHA-256 `957982f5acec969f8003d04b2d6444eecbba9af26b7392d760badb5be5d6bd0e`; original failures retained |
1718
| Earlier profile APK | Runtime equivalent to `e54a78a`; SHA-256 `5b93b0c68bfc7bfa06a3a887ab70192a4d47c4786cf82e5428005ef94b199861` |
1819
| Governing evidence | [Recovery contract](../../../specifications/App/current-draft-recovery.md#7-required-evidence-before-acceptance), [operator recipe](01_Operator_Recipe.md), [execution record](00_Execution_Record.md), [validation inventory](../c1-s1/04_Validation_Inventory_and_Operator_Recipe.md) |
1920
| Private evidence | Ignored `local/recovery-completion/android/`: exact artifact/source manifests, native assertions, fresh UI XML/screenshots, logs, initial isolated-data backup and installed-artifact hash |
2021

21-
Both profile candidates were built from the normal application entry point.
22-
The final candidate was built after `flutter clean`, with the new Dart keyboard
23-
helper and native activity handler included. It is a qualification package;
22+
All profile candidates were built from the normal application entry point.
23+
The final candidate was built after `flutter clean`; its packaged Dart AOT
24+
changed from the native-keyboard profile, and all eleven DEX payloads remain
25+
identical. The final change adds the iOS keyboard-guide fallback; on Android
26+
the wrapper returns the existing child without observing or replacing metrics. It is a qualification package;
2427
these observations do not independently establish Play delivery or production
2528
signing. The release record owns that separate packaging evidence.
2629

@@ -29,33 +32,35 @@ signing. The release record owns that separate packaging evidence.
2932
The initial isolated Editor was empty. Its private data was backed up before
3033
qualification, and the store app was not replaced or cleared. Only disposable
3134
text and uniquely named board fixtures were used. No firmware was flashed by
32-
this Android workflow.
35+
this Android workflow. The following observations use the native-keyboard
36+
profile unless an earlier profile is named; the final-candidate recheck is
37+
recorded separately below.
3338

3439
| Recipe | Result / physical oracle | Evidence prefix |
3540
|---|---|---|
36-
| P01 | Pass on final candidate: actual Bluetooth state OFF and Wi-Fi disabled; startup presents the exact checkpoint before any connection workflow | `nativefix-all-offline-relaunch`, `nativefix-offline-bluetooth-confirmed` |
41+
| P01 | Pass on native-keyboard profile: actual Bluetooth state OFF and Wi-Fi disabled; startup presents the exact checkpoint before any connection workflow | `nativefix-all-offline-relaunch`, `nativefix-offline-bluetooth-confirmed` |
3742
| P02 | Pass: named `recovery.py` retains Unicode `✓`, punctuation, blank lines and final newline; native entry was asserted exactly before normal key-event editing | `nativefix-typing-seed`, `nativefix-continuous-expected` |
3843
| P03 | Pass: explicit recovery save acknowledges the matching text; Saved locally and board Unsaved changes remain distinct | `profile-saved-local`, `nativefix-continuous-saved` |
3944
| P04 | Pass: actual force-stop/relaunch reproduces exact named text and checkpoint, including the generated Blocks text | `nativefix-typed-offline-relaunch`, `nativefix-generated-relaunch` |
4045
| P05 | Pass: Back leaves the unresolved recovery decision; relaunch presents the same complete generated checkpoint | `nativefix-recovery-before-back`, `nativefix-recovery-after-back` |
41-
| P06 | Pass on final candidate: explicit Restore shows exact text in the disconnected local panel; connecting remains a separate action | `controlled-3dcb-local-restore` |
46+
| P06 | Pass on native-keyboard profile: explicit Restore shows exact text in the disconnected local panel; connecting remains a separate action | `controlled-3dcb-local-restore` |
4247
| P07 | Pass for ordinary edit/lifecycle behavior: repeated normal key events, idle acknowledged checkpoint, backgrounding, force-stop and exact recovery | `nativefix-continuous-*`, `nativefix-all-offline-relaunch` |
43-
| P08 | Pass on final candidate: Cancel retains the exact copy; confirmed Discard commits the empty slot and another process launch has no recovery prompt | `controlled-3dcb-discard-*`, `controlled-3dcb-empty-slot` |
48+
| P08 | Pass on native-keyboard profile: Cancel retains the exact copy; confirmed Discard commits the empty slot and another process launch has no recovery prompt | `controlled-3dcb-discard-*`, `controlled-3dcb-empty-slot` |
4449
| P09 | Pass on earlier profile: deliberately empty named `acceptance_1730.py` survives checkpoint/process relaunch as a recoverable document | `profile-empty-named-saved`, `profile-empty-named-prompt` |
4550
| P10 | Pass on earlier profile: Save and Run show their current destination and distinct write-only/write-and-run effects; Cancel preserves the document. Confirmed upload and subsequent Run produced `67891` | `profile-save-consent-dialog`, `profile-run-consent-dialog`, `profile-named-upload-consent`, `profile-hello-output-complete` |
4651
| P11 | Pass for physical moved-directory destination: Upload names the actual current directory; cancellation and confirmed upload were exercised | `profile-upload-cwd-consent`, `controlled-3dcb-cwd-upload-consent` |
47-
| P12 | Pass on final candidate: matching confirmed upload clears board dirty; a new connection session requires current-target consent again, which was cancelled | `controlled-3dcb-upload-ack`, `controlled-3dcb-new-session-consent` |
48-
| P13 | Pass on final candidate: Editor New, Board Open and Blocks handoff each protect meaningful pending Unicode text. Cancel retains it exactly; confirmed Blocks replacement installs the generated text | `nativefix-new-*`, `nativefix-board-open-*`, `nativefix-block-handoff-*` |
49-
| P14 / DR-T12 | Pass on final candidate: normal Hello example → Open in Editor → guarded replacement → Save recovery copy → Disconnect → force-stop/relaunch recovers exactly `print('Hello, PyBLE!')\n` as text | `nativefix-generated-checkpoint`, `nativefix-generated-relaunch` |
52+
| P12 | Pass on native-keyboard profile: matching confirmed upload clears board dirty; a new connection session requires current-target consent again, which was cancelled | `controlled-3dcb-upload-ack`, `controlled-3dcb-new-session-consent` |
53+
| P13 | Pass on native-keyboard profile: Editor New, Board Open and Blocks handoff each protect meaningful pending Unicode text. Cancel retains it exactly; confirmed Blocks replacement installs the generated text | `nativefix-new-*`, `nativefix-board-open-*`, `nativefix-block-handoff-*` |
54+
| P14 / DR-T12 | Pass on native-keyboard profile: normal Hello example → Open in Editor → guarded replacement → Save recovery copy → Disconnect → force-stop/relaunch recovers exactly `print('Hello, PyBLE!')\n` as text | `nativefix-generated-checkpoint`, `nativefix-generated-relaunch` |
5055
| P15 | Verified physical scope: 2× recovery controls, Editor/Blocks keyboard layout, and native accessibility focus/labels with TalkBack active. Audible pronunciation and complete gesture navigation were not observed | `nativefix-named-2x-*`, `nativefix-blocks-ime-*`, `talkback-probe-*` |
5156

5257
The generated-text recovery observation does not claim restoration of a Blocks
5358
workspace, revision history or companion files. The UI explicitly states that
5459
the local slot contains one current text draft.
5560

5661
The retained earlier-profile observations cover unchanged storage, target-guard
57-
and transport code. The final runtime changes keyboard dismissal; its affected
58-
Editor/native-WebView behavior and Blocks handoff were repeated on the final
62+
and transport code. The native-keyboard runtime changes keyboard dismissal; its affected
63+
Editor/native-WebView behavior and Blocks handoff were repeated on that exact
5964
installed artifact. This is an impact assessment, not a claim that every earlier
6065
observation was rerun on identical bytes.
6166

@@ -66,6 +71,62 @@ phases. Their physical execution is not inferred from a successful ordinary
6671
restart. Error-panel localization/layout coverage also remains part of the
6772
host widget/semantics/golden evidence.
6873

74+
## Final candidate recheck
75+
76+
The final APK was installed over the isolated app without clearing its data.
77+
The installed hash was checked again after restoring it from the temporary
78+
diagnostic and older-candidate comparisons. No diagnostic Activity or callback
79+
logging remains in that APK or the restored qualification source copy.
80+
81+
| Check | Result on final `945e9746…` APK | Evidence prefix |
82+
|---|---|---|
83+
| Identity and retained data | About shows `Version 0.3.0 (9)`; the previous exact `matrix.py` checkpoint survives installation | `final-guide-about`, `final-guide-preserved-relaunch`, `final-guide-final-installed-sha256` |
84+
| Editor keyboard | Code and navigation remain usable above the keyboard; Expand hides the actual IME and retains exact text and the normal expanded console | `final-guide-editor-ime-*`, `final-guide-editor-expanded` |
85+
| Blocks startup and keyboard | Actual launcher entry loads the empty workspace and Hello example. Opening the native HTML text field shows the IME; semantic Expand hides it, exposes Collapse console, and retains the field/workspace | `final-guide-final-empty-workspace`, `final-guide-hello-ready`, `final-guide-blocks-ime-*`, `final-guide-blocks-expanded` |
86+
| Generated checkpoint / DR-T12 | Guarded Open in Editor and confirmed replacement produce exactly `print('Hello, PyBLE!')\n` in `blocks.py`; explicit local save acknowledges it | `final-guide-handoff-review`, `final-guide-generated-editor`, `final-guide-generated-checkpoint` |
87+
| Offline relaunch and Restore | Bluetooth is actually OFF and Wi-Fi disabled before process termination/relaunch; recovery and explicit disconnected Restore retain the exact generated text and filename | `final-guide-generated-offline-*` |
88+
| Current-target cancellation | After deliberate C3 connection, Save and Run show `/blocks.py` and their distinct effects; each Cancel preserves exact text. No board upload or program run occurs | `final-guide-generated-target-*`, `final-guide-generated-run-*`, `final-guide-generated-result` |
89+
90+
The final change adds an iOS-only keyboard-guide fallback; the Android wrapper
91+
returns the existing child. The unchanged storage, target-guard, BLE, run and
92+
Blocks code, together with identical native DEX and bundled Blocks inputs,
93+
supports retaining the earlier matrix rows below. Those rows are not represented
94+
as new five-board executions of the final APK.
95+
96+
The startup investigation also found a device-environment condition. The
97+
isolated package appeared in Lenovo's DuraSpeed suppression list while its
98+
renderer service remained pending without a process or binder. Real watchdog
99+
failures had no page or JavaScript bridge callbacks; a same-package native
100+
Activity without Flutter reproduced them. A controlled native comparison
101+
passed with the qualifier's Battery mode temporarily set to **Unrestricted**.
102+
The accepted final-app sequence also used its actual, package-verified launcher
103+
icon. Global DuraSpeed configuration was unchanged. These observations qualify
104+
the recorded setup; they do not establish that every shell launch or OEM power
105+
mode works, or that either setup step is universally necessary. The earlier
106+
successful shell-launched profile did not retain a comparable policy snapshot.
107+
No product startup code was changed for this investigation.
108+
109+
After qualification, the original **Optimized** battery mode was restored and
110+
the qualifier was removed from the device-idle exemption list. Global DuraSpeed
111+
configuration remained byte-identical to the recorded baseline. Original radio,
112+
accessibility, touch-exploration and font settings were verified restored; the
113+
final APK and its recovery data remain installed, with the qualifier stopped
114+
and temporary device helpers removed.
115+
116+
Some helper waits were corrected against the retained UI evidence: an empty
117+
initialized workspace offers Browse examples and disables Preview code with
118+
“Add blocks to generate Python.” Waiting for Preview code in that state is not
119+
a startup failure. Both the final and retained native-keyboard APKs reached
120+
that valid state through the actual launcher. Those selector timeouts remain
121+
separate from the genuine earlier watchdog failures.
122+
123+
After radio restoration, the first generated-text C3 connection encountered a
124+
15-second service-discovery timeout before Ready. Its explicit retry reached
125+
Ready and completed both target-cancellation checks. This retained transient is
126+
not counted as a successful first attempt. The separate Classic reconnect
127+
errors are likewise retained; its subsequent board-restoration step does not
128+
replace any app reconnect observation.
129+
69130
## Physical app-only matrix
70131

71132
Every passing core row covers edit, explicit Save, Run, observed stdout, Stop,
@@ -75,11 +136,11 @@ receipts are retained with each row. A Ready scan result alone is not counted.
75136

76137
| Row | Exact profile / board alias | App candidate | Result | Raw prefix |
77138
|---|---|---|---|---|
78-
| Q02 | `esp32-4mb` / 8C9E | Final | Pass | `q8c9e` |
79-
| Q04 | `esp32-s3-n16r8` / 5646 | Final | Pass | `q5646` |
80-
| Q06 | `waveshare-esp32-s3-lcd-147b` / DA86 | Final | Pass | `qda86` |
139+
| Q02 | `esp32-4mb` / 8C9E | Native-keyboard profile | Pass | `q8c9e` |
140+
| Q04 | `esp32-s3-n16r8` / 5646 | Native-keyboard profile | Pass | `q5646` |
141+
| Q06 | `waveshare-esp32-s3-lcd-147b` / DA86 | Native-keyboard profile | Pass | `qda86` |
81142
| Q08 | `esp32-c3-4mb` / C81A | Earlier profile; unchanged transport/run code | Pass, including both required real-UI Stop cases | `profile-c3-*`, `profile-tight-*`, `profile-flood-*` |
82-
| Q10 | `rpi-pico2-w` / 3DCB | Final | Pass after an explicitly retained Android-133 connection failure and retry | `q3dcb` |
143+
| Q10 | `rpi-pico2-w` / 3DCB | Native-keyboard profile | Pass after an explicitly retained Android-133 connection failure and retry | `q3dcb` |
83144

84145
C3 ran both `while True:\n pass\n` and
85146
`while True:\n print(24680)\n`. The recorded UI changed from Running to
@@ -124,9 +185,15 @@ All board connections were explicitly released; temporary diagnostic apps,
124185
device helper files and the debugging forward were removed. The isolated
125186
qualification app/data and private evidence remain available for review. An
126187
exact ownership manifest records the disposable board fixtures. Coordinated
127-
cleanup removed nine authored files and five empty owned directories from the
128-
Classic ESP32, generic S3, Waveshare and Pico. Each file was read and privately
129-
backed up before deletion; unchanged unrelated root entries and disconnection
130-
were verified for every board. The C3 fixtures remain reserved for the iPad
131-
acceptance run. Private per-board cleanup receipts retain the commands,
132-
readback hashes and before/after listings.
188+
Android/iPad cleanup removed nineteen authored files and ten empty owned
189+
directories across all five boards. Each file was read and privately backed up
190+
before deletion; unchanged unrelated root entries and disconnection were
191+
verified for all eight cleanup sessions. Private per-board receipts retain the
192+
commands, readback hashes and before/after listings.
193+
194+
Classic ESP32 remained absent from a fresh scan after the retained reconnect
195+
failures. Its CP2102 endpoint and ROM chip identity were checked against the
196+
earlier binding, then an ordinary RTS reset restored advertising. The ROM-only
197+
command performed no firmware or VFS write. A fresh eight-second scan observed
198+
all five boards advertising. This restores board availability and is not
199+
counted as an app reconnect pass.

0 commit comments

Comments
 (0)