Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a75d478
[red] expose stale editor board operations across revisions and sessions
yyods Oct 31, 2026
80b6053
[green] fence editor transfers by revision and connection session
yyods Oct 31, 2026
4c4ee3a
[red] specify session-bound consent for recovered board actions
yyods Oct 31, 2026
ce5e8a6
[red] specify file-backed current-draft recovery invariants
yyods Oct 31, 2026
8a03bf9
[red] define next recovery candidate as app 0.3.0 build 9
yyods Oct 31, 2026
1cbd04e
[green] require recovery target consent and serialize editor replacem…
yyods Oct 31, 2026
2e43ab9
[red] specify durable draft recovery coordination and race behavior
yyods Oct 31, 2026
628b56f
[green] coordinate durable current-text recovery and guarded replacem…
yyods Oct 31, 2026
7664743
[green] persist bounded current text with atomic Drift checkpoints
yyods Oct 31, 2026
5115294
[refactor] clarify recovery repository test guards
yyods Oct 31, 2026
90dceec
[red] require explicit reread after recovery generation conflict
yyods Oct 31, 2026
c9310c6
[green] reread preserved recovery state after unsafe storage failures
yyods Oct 31, 2026
1324fec
[red] specify local recovery preview and explicit choices
yyods Oct 31, 2026
b7b0fed
[green] add accessible local recovery preview and confirmations
yyods Oct 31, 2026
a79c15b
[red] cover recovery startup timeout and preserved live text
yyods Oct 31, 2026
8c1deb4
[green] integrate startup recovery and offline draft controls
yyods Oct 31, 2026
10bfdbd
[green] verify durable recovery across controller sessions
yyods Oct 31, 2026
322e153
[green] verify explicit volatile replacement consent guards
yyods Oct 31, 2026
6a6d086
[docs] record bounded recovery candidate and remaining release evidence
yyods Oct 31, 2026
c760320
[red] reproduce recovery retry and compact volatile UI gaps
yyods Oct 31, 2026
29455b6
[green] preserve live drafts through recovery retries and compact errors
yyods Oct 31, 2026
4479ff6
[green] finish recovery consent fallback and prepare app 0.3.0 build 9
yyods Oct 31, 2026
c40a338
[docs] record recovery candidate validation and remaining platform gates
yyods Oct 31, 2026
18eee79
[red] bound corrupt local recovery metadata before hydration
yyods Oct 31, 2026
8657e5a
[green] preflight recovery metadata bounds on database isolate
yyods Oct 31, 2026
90311f3
[build] retain explicit receipts from profile device qualification
yyods Oct 31, 2026
709556e
[docs] record both-tablet storage verification and discovery observat…
yyods Oct 31, 2026
9badcdb
[docs] close classic workspace incident and record real recovery work…
yyods Oct 31, 2026
ace7dbb
[docs] fix recovery report filesystem section link
yyods Oct 31, 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
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ and submission packet do not claim Play submission, approval, or rollout.

### App source

- Prepared app source candidate `0.3.0+9` with bounded on-device current-text
recovery using Drift. Exact text and metadata commit atomically; startup
offers offline preview, Restore and confirmed Discard, with separate local
checkpoint status and an explicit Save recovery copy action. Storage errors
preserve the previous copy and live text, with explicit volatile continuation.
- Added document-epoch and connection-session guards for Editor Save/Run,
Files Open/Upload and Blocks-to-Editor replacement. Restored drafts require
current-destination confirmation before board writes; a board swap after text
upload refuses Run and reports the partial outcome. Full project and Blocks
graph persistence remain carried. Candidate validation is recorded under
`docs/developments/2026-q4-reliable-workflow/c1-s2/`; no store release claimed.

- Added a full offline Privacy policy route from About, with the published
policy, effective date and privacy contact. Reading it preserves the live
board session, editor, Blocks and console state, including at large text
Expand Down Expand Up @@ -90,8 +102,8 @@ and submission packet do not claim Play submission, approval, or rollout.
results or new release are claimed.
- Specified bounded Drift current-text recovery, local restore/discard,
failure handling and document/session guards in ADR-0048 and the App
contracts. Implementation remains pending; sizing requires revising the
original S2 forecast.
contracts. The bounded successor is implemented in the 0.3.0 source candidate;
acceptance and broader persistence obligations follow the C1-S2 record.
- Verified live Android open-testing wording and prepared correction of the
older public TestFlight description. Installed identities are now recorded;
Android code/assets match the retained build-8 AAB, while iPad build-6 source
Expand Down
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fetches and validates the complete batch, shows the exact destination paths,
and asks separately before overwriting existing files. Import never creates a
remote folder hierarchy, opens an editor document, or runs downloaded code.

The current App source version is `0.2.0+8`; App and firmware versions are
The next App source candidate is `0.3.0+9`; App and firmware versions are
independent. The published Android version is `0.2.0`, available through
[Google Play open testing](https://play.google.com/store/apps/details?id=dev.pyble.pyble).
iPad testing continues through TestFlight. The
Expand All @@ -91,6 +91,22 @@ does not establish its installed build/source identity or mean those earlier
artifacts contain later connection-lifecycle fixes. Both platforms share the
same Flutter source and app test gates. The iOS/iPadOS project minimum is 15.

### Next app candidate: local draft recovery

The `0.3.0+9` source candidate adds one on-device current-text recovery copy.
After restart, preview and explicitly Restore or Discard the last committed
copy before connecting. “Saved locally” means the matching transaction finished;
pending edits may not survive immediate termination. The separate **Save
recovery copy** action works without a board. Recovered text requires explicit
confirmation of the current board destination before Save, Run or Files Upload.

This bounded feature covers text up to 1 MiB, including Python explicitly copied
from Blocks. Blocks workspace graphs, projects/history and exported backups
remain outside this increment. Uninstalling or clearing app data removes local
copies. See the [candidate execution record](docs/developments/2026-q4-reliable-workflow/c1-s2/00_Execution_Record.md)
for automated and device evidence; source implementation does not establish
store availability or release qualification.

### Firmware

The board-side agent is built with upstream MicroPython and exposes PBLE/1 as a
Expand Down
83 changes: 81 additions & 2 deletions app/DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ Toolchain pin: **Flutter 3.44.1 (stable)** / Dart SDK `^3.12.1` (see
| `http` | runtime | `^1.6.0` | 1.6.0 | BSD-3-Clause | The bounded public GitHub REST client for the connected A-33 subset ([ADR-0040](../docs/decisions/0040-sha-pinned-connected-github-import.md)). The direct dependency is confined to `lib/github_import/`'s production composition point and `GithubRepositoryClient`; all feature consumers bind to the neutral `GithubApi` seam. The adapter accepts only canonical public repository input, sends no credential or user source, permits requests only to exact HTTPS host `api.github.com`, disables redirects, pins every browse to a full commit SHA, and bounds time and response bodies. Min 1.6.0 supplies the abortable request surface used by the cancellation contract on the pinned Dart/Flutter toolchain. |
| `highlight` | runtime | `^0.7.0` | 0.7.0 | MIT | Python grammar data consumed directly by `lib/editor`'s rich adapter (A-20). It also appears in `flutter_code_editor`'s closure, but PyBLE's direct import makes the dependency and compatible minimum explicit under BLD-2. |
| `webview_flutter` | runtime | `^4.14.1` | 4.14.1 | BSD-3-Clause | The offline platform-WebView host for the pinned Blockly runtime (A-31, ADR-0013). Min 4.14.1 is compatible with PyBLE's Android 24 / iOS 15 platform floors and supplies `loadFlutterAsset`, JavaScript channels, and navigation delegates. Its sole importer is `lib/blocks/`; generated source and board actions stay in Dart behind the neutral `Connection` seam. |
| `drift` | runtime | `^2.35.3` | 2.35.3 | MIT | ADR-0048 bounded current-text recovery. Typed atomic SQLite transactions and owned background native executor; no second persistence backend. |
| `sqlite3` | runtime | `3.5.0` (exact) | 3.5.0 | MIT | Native SQLite bindings/build hooks used by Drift; exact compatibility ceiling for Flutter 3.44.1's pinned `meta` 1.18.0. Later sqlite3 releases require newer hooks/meta; no dependency override is used. SQLite itself is public domain; default upstream SQLite build, no sqlite3mc/encryption fork. |
| `crypto` | runtime | `^3.0.8` | 3.0.8 | BSD-3-Clause | Exact UTF-8 SHA-256 identity checks for local recovery; accidental corruption detection, never board authority or authenticity. Promoted from transitive to explicit direct dependency. |
| `path_provider` | runtime | `^2.1.6` | 2.1.6 | BSD-3-Clause | Resolves the app-private persistent Application Support directory for the single Drift store. No temp/cache/external storage, source upload or remote sync. |
| `drift_dev` | dev | `^2.35.2` | 2.35.2 | MIT | Typed table generation and initial v1 schema export; build-time only. |
| `build_runner` | dev | `^2.15.1` | 2.15.1 | BSD-3-Clause | Reproducible Drift source generation. Resolved with the pinned SDK/meta without overrides; build-time only. |
| `flutter_test` | dev (SDK) | Flutter SDK | 3.44.1 | BSD-3-Clause | Widget/unit/golden test harness; the substrate for the G1 suites (NFR-MAINT-4). |
| `integration_test` | dev (SDK) | Flutter SDK | 3.44.1 | BSD-3-Clause | On-device Android/iPadOS parity coverage for the real Blockly platform WebView, local asset load, JavaScript bridge, generated Python, and file-backed actions (A-31). Ships with the Flutter SDK and is never part of a release build. |
| `flutter_lints` | dev | `^6.0.0` | 6.0.0 | BSD-3-Clause | Recommended Flutter lint set, activated via `analysis_options.yaml`; the static-analysis floor for the app CI gate. Toolchain-default major for Flutter 3.44.1. |
Expand All @@ -68,7 +74,6 @@ below the table.
| `charcode` | 1.4.0 | BSD-3-Clause |
| `clock` | 1.1.2 | Apache-2.0 |
| `collection` | 1.19.1 | BSD-3-Clause |
| `crypto` | 3.0.7 | BSD-3-Clause |
| `dbus` `‡` | 0.7.14 | MPL-2.0 |
| `equatable` | 2.1.0 | MIT |
| `fake_async` | 1.3.3 | Apache-2.0 |
Expand Down Expand Up @@ -133,6 +138,64 @@ below the table.
| `win32` | 6.3.0 | BSD-3-Clause |
| `xml` | 6.6.1 | MIT |

### Recovery dependency additions (PYB-006.2)

These additional locked transitive packages were checked against the exact package
`LICENSE` files on 31 October 2026. Build generators, analyzer and their helper
packages are development inputs; platform adapters compile only for their target.
The original transitive table plus this table covers the resolved graph.

| Package | Resolved | SPDX |
|---|---|---|
| `_fe_analyzer_shared` | 100.0.0 | BSD-3-Clause |
| `analyzer` | 13.0.0 | BSD-3-Clause |
| `build` | 4.0.7 | BSD-3-Clause |
| `build_config` | 1.3.3 | BSD-3-Clause |
| `build_daemon` | 4.1.7 | BSD-3-Clause |
| `built_collection` | 5.1.2 | BSD-3-Clause |
| `built_value` | 8.13.0 | BSD-3-Clause |
| `checked_yaml` | 2.0.4 | BSD-3-Clause |
| `cli_util` | 0.6.0 | BSD-3-Clause |
| `code_assets` | 1.2.1 | BSD-3-Clause |
| `convert` | 3.1.2 | BSD-3-Clause |
| `dart_style` | 3.1.9 | BSD-3-Clause |
| `fixnum` | 1.1.1 | BSD-3-Clause |
| `glob` | 2.2.0 | BSD-3-Clause |
| `graphs` | 2.3.2 | BSD-3-Clause |
| `hooks` | 2.0.2 | BSD-3-Clause |
| `http_multi_server` | 3.2.3 | BSD-3-Clause |
| `io` | 1.1.0 | BSD-3-Clause |
| `jni` | 1.1.1 | BSD-3-Clause |
| `jni_flutter` | 1.0.4+1 | BSD-3-Clause |
| `jni_util` | 1.0.0 | BSD-3-Clause |
| `json_annotation` | 4.12.0 | BSD-3-Clause |
| `logging` | 1.3.0 | BSD-3-Clause |
| `mime` | 2.1.0 | BSD-3-Clause |
| `native_toolchain_c` | 0.19.2 | BSD-3-Clause |
| `objective_c` | 9.5.0 | BSD-3-Clause |
| `package_config` | 2.2.0 | BSD-3-Clause |
| `path_provider_android` | 2.3.1 | BSD-3-Clause |
| `path_provider_foundation` | 2.6.0 | BSD-3-Clause |
| `path_provider_linux` | 2.2.2 | BSD-3-Clause |
| `path_provider_platform_interface` | 2.1.3 | BSD-3-Clause |
| `path_provider_windows` | 2.3.0 | BSD-3-Clause |
| `pool` | 1.5.3 | BSD-3-Clause |
| `pub_semver` | 2.2.1 | BSD-3-Clause |
| `pubspec_parse` | 1.7.0 | BSD-3-Clause |
| `recase` | 4.1.0 | BSD-2-Clause |
| `record_use` | 0.6.0 | BSD-3-Clause |
| `shelf` | 1.4.3 | BSD-3-Clause |
| `shelf_web_socket` | 3.0.0 | BSD-3-Clause |
| `source_gen` | 4.2.4 | BSD-3-Clause |
| `sqlparser` | 0.45.1 | MIT |
| `stream_transform` | 2.1.2 | BSD-3-Clause |
| `watcher` | 1.2.1 | BSD-3-Clause |
| `web_socket` | 1.0.1 | BSD-3-Clause |
| `web_socket_channel` | 3.0.3 | BSD-3-Clause |
| `xdg_directories` | 1.1.0 | BSD-3-Clause |
| `yaml` | 3.1.4 | MIT |
| `yaml_edit` | 2.2.4 | BSD-3-Clause |

### `†` Owner-ratified shipped carve-out — `autotrie` 2.0.0 (MPL-2.0)

`flutter_code_editor` constructs its autocomplete index with `autotrie`, even
Expand Down Expand Up @@ -205,6 +268,22 @@ rationale when added:

| Package | Sprint / story | Purpose |
|---|---|---|
| `drift`, `sqlite3` | S5 / A-24 | Local persistence. |
| `fl_chart` | later | Plotting surface. |
| `go_router` | — | Not planned for S1; navigation is index-based via a Riverpod `StateProvider` + `IndexedStack`. |

## Recovery build and notice reproduction

- Run `dart run build_runner build` from `app/`, then
`dart run drift_dev schema dump lib/data/draft_database.dart drift_schemas/`.
The first generated database source and schema are reviewed and committed;
`build.yaml` preserves the authored-source SPDX preamble on regeneration.
- Pub-package license texts remain in Flutter's mechanically generated
`NOTICES.Z` and in-app LicenseRegistry. The SQLite native amalgamation's
public-domain provenance is separately bundled in
`assets/licenses/SQLite-PUBLIC-DOMAIN.txt`; PyBLE adds no custom SQLite code.
- The default `sqlite3` build hook obtains its upstream binaries from the
package's release assets, with the package-pinned SHA-256 checks. No binaries,
compiler outputs or native signing inputs are committed here.
- The database is `pyble.sqlite` in Application Support. Its `-wal`/`-shm`
companions belong to the same store. Device/OS backup behavior is external
to PyBLE's local checkpoint promise; no backup/sync feature is added.
11 changes: 11 additions & 0 deletions app/assets/licenses/SQLite-PUBLIC-DOMAIN.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
SQLite native database engine

SQLite is public-domain software, as documented by the SQLite project:
https://www.sqlite.org/copyright.html

PyBLE uses the default SQLite engine supplied by the unmodified sqlite3 Dart
package's build hook. The Dart bindings are separately MIT licensed; their
license is included in Flutter's generated package notices. PyBLE does not
ship the optional sqlite3mc engine.

Package provenance and locked versions: app/DEPENDENCIES.md and pubspec.lock.
11 changes: 11 additions & 0 deletions app/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: MIT
# Part of PyBLE (https://pyble.dev) — see /LICENSE.

targets:
$default:
builders:
source_gen:combining_builder:
options:
preamble: |
// SPDX-License-Identifier: MIT
// Part of PyBLE (https://pyble.dev) — see /LICENSE.
Loading
Loading