diff --git a/CHANGELOG.md b/CHANGELOG.md index 43f3671..647f39c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ explicit proposal derivation, desktop schema v23, Android schema v22 and the separate `trainlog-session-preparations` V1 generation participant. +- Completed the controlled Sessions V1 deployment and delivered a six-entry + validation preparation to Android without starting it or replacing an active + draft. Foreground generation retries now emit a fresh daemon request and + resume the exact interrupted generation until both peer halves are durable, + preventing false transport timeouts and duplicate recapture. + - Added compatible non-destructive generation archival on desktop schema v22 and Android schema v21. Only exactly acknowledged generations older than the two active recovery tips leave admission after a verified durable payload diff --git a/docs/android.md b/docs/android.md index 16b1ac1..bccd210 100644 --- a/docs/android.md +++ b/docs/android.md @@ -972,3 +972,11 @@ ledger without changing any domain identity. Its full-generation foreground coordinator waits for correlated objects, tolerates stale objects left by interrupted runs, strictly revalidates desktop-retained historical ACKs, and shows completion only after both durable peer acknowledgements. + +Each explicit foreground generation attempt publishes the Android peer before +emitting one fresh legacy request signal for `trainlog-syncd`. If transport is +interrupted after generation publication, a later attempt resumes the exact +stored generation instead of recapturing mutable data. An acknowledged Android +generation remains resumable only until the desktop generation for that run is +durably consumed; a fully completed run is then excluded from foreground +selection. This preserves late-ACK recovery without replaying completed runs. diff --git a/docs/current_state.md b/docs/current_state.md index 12cd47f..06eb68a 100644 --- a/docs/current_state.md +++ b/docs/current_state.md @@ -72,7 +72,7 @@ parallel implementation of its rules. | Web Dashboard tiles | `WEB_DASHBOARD_TILES_V1=PASS/FROZEN` | | Web Dashboard visualizations | `WEB_DASHBOARD_VISUALIZATIONS_V1=PASS/FROZEN` | | Web Dashboard V1 | `WEB_DASHBOARD_V1=PASS/FROZEN` | -| Web Sessions V1 | `TRAINLOG_WEB_SESSIONS_V1=PASS/FROZEN` (isolated software validation; controlled deployment pending) | +| Web Sessions V1 | `TRAINLOG_WEB_SESSIONS_V1=PASS/FROZEN` (controlled desktop/Android deployment validated) | | Sync orchestrator/report V1 | `TRAINLOG_SYNC_ORCHESTRATOR_REPORT_V1=PASS/FROZEN` | | Web sync API V1 | `TRAINLOG_WEB_SYNC_API_V1=PASS/FROZEN` | | Web sync button V1 | `TRAINLOG_WEB_SYNC_BUTTON_V1=PASS/FROZEN` | @@ -228,6 +228,13 @@ Android schema v22 stores received preparations separately from AI proposals and the active singleton. An exact correlated ACK is required before delivery is shown as acknowledged. +The controlled deployment preserved the installed Android signing identity and +advanced its private `versionCode` without uninstalling or clearing data. The +validation preparation derived from the six-occurrence proposal remained a +separate pending Android preparation across application and service restart. +Two correlated generation conversations completed without a duplicate, +performed fact, or active-draft replacement. + The Next Session tile no longer treats the frozen Dashboard `next_session.available` placeholder as a durable inventory. A separate bounded `GET /api/v1/prepared-items` Core projection distinguishes imported AI diff --git a/docs/sync_exchange.md b/docs/sync_exchange.md index 72562b2..3bcfedf 100644 --- a/docs/sync_exchange.md +++ b/docs/sync_exchange.md @@ -817,6 +817,14 @@ for its ACK). Objects retained from an interrupted conversation are ignored until atomically replaced by matching objects. After both peer ACKs, Android reports completion directly; it does not enter the legacy receipt wait state. +The peer publication precedes one fresh `trainlog-sync-request-v1` signal on +every explicit Android attempt. This wakes the existing user-session daemon; +it is not an ACK and does not alter generation identity. A retry may resume an +exact `captured`, `published`, or `waiting_acknowledgement` generation. It may +also finish the inbound half of an acknowledged outbound generation when no +terminal consumed/rejected inbound ledger row exists for the run. It never +recaptures state under that run identity. + The 2026-09-17 private rollout exercised this path with the production libmtp adapter on one paired Samsung phone. Three complete bidirectional conversations passed, including service/application restart and an idempotent replay whose diff --git a/docs/tests.md b/docs/tests.md index 7dabf50..d007414 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -10,7 +10,11 @@ built into the canonical Meson binary. singleton refusal, explicit start, reserved execution identity and absence of performed facts. `SyncGenerationServiceTest` and `SyncDeploymentConversationTest` exercise the real optional artifact through -generation validation and 24 bidirectional conversations. +generation validation and 24 bidirectional conversations. It also asserts that +every foreground conversation emits exactly one fresh daemon request signal; +the coordinator's production resume predicate preserves an interrupted +generation identity until the counterpart generation has a durable terminal +consumption row. `SyncDeploymentConversationTest` executes both production generation services and reopens Android storage. `test_web_sync_browser.py` adds a real Firefox click