diff --git a/CHANGELOG.md b/CHANGELOG.md index 12621b3..17dd0a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ ## Unreleased — 0.1.2 +- Completed the authorized private full-generation rollout over production + direct MTP: verified Android and desktop backups, signing-preserving Android + updates, schema migrations, persistent peer pairing, bidirectional durable + ACKs, restart and idempotent replay. This did not publish a release or modify + v0.1.1. + +- Fixed rollout-discovered feedback idempotence across SQLite row modes, + packaged the complete generation exporter closure, ignored stale Android + coordination objects until their run/generation correlation matches, and + made the Android screen report completed generation conversations instead of + waiting for a legacy receipt. + - Packaged `trainlog-sync-once` and `trainlog-syncd` with the relocatable sync candidate so user services cannot mix a versioned install with live-checkout helpers during rollout. diff --git a/README.md b/README.md index 29830e2..88fec83 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,16 @@ Android and the TUI in each stable release share the same Trainlog product version on both mirrors. Database schemas and JSON protocol versions are independent. +### Daily synchronization on an opted-in installation + +Connect and unlock the paired phone, keep Trainlog's Synchronization screen in +the foreground, then select **Synchronize** in the local Web Dashboard and +**Synchronize now** on Android. Wait until Web reports completion and Android +shows that synchronization completed on both Android and PC. A failure remains +durable and should be diagnosed before retrying; do not delete generation, +ACK, database, or backup files. Full-generation mode is a trusted local opt-in; +other installations continue to use the established V3 request/receipt path. + ### Build from source Desktop: diff --git a/docs/android.md b/docs/android.md index 23a4227..ef74fa7 100644 --- a/docs/android.md +++ b/docs/android.md @@ -956,3 +956,11 @@ The installed schema-v17 release has no backup UI. The reproducible adds only the backup surface, assigns a higher candidate version code and builds/tests an APK without installing it. Its synthetic v17 archive is also restored by current code and migrated through the normal v17-to-v20 path. + +The authorized private rollout used the bridge only to add the backup surface +without clearing package data, verified the resulting plaintext archive, then +installed the current signed release variant through a strictly increasing +version-code chain. The final installed private candidate retains product +version 0.1.2 and schema v20. Its full-generation foreground coordinator waits +for correlated objects, tolerates stale objects left by interrupted runs, and +shows completion only after both durable peer acknowledgements. diff --git a/docs/current_state.md b/docs/current_state.md index de7e1c3..530f3e8 100644 --- a/docs/current_state.md +++ b/docs/current_state.md @@ -1,12 +1,13 @@ # Current implementation state -The development branch has opt-in full-generation coordination with durable Web -progress and a foreground Android conversation. Its production generation MTP -adapter is integrated and tested through an object-I/O boundary double. Android -also has a complete same-installation backup/verify/restore container, and a -non-installed schema-v17 bridge candidate is reproducibly built and tested. -Physical-device MTP, release signing, real user backup/restore, main integration -and deployment are not complete. +The opt-in full-generation path is operational on the private daily +installation. The loopback Web control and foreground Android coordinator use +the production direct-libmtp adapter, correlated manifest/ACK V1 objects, and +persistent peer identities. The controlled rollout verified real backups, the +schema-v17 to v20 Android update chain, desktop v18 to v21 migration, three +complete hardware conversations, restart, and idempotent replay. Drive was not +configured and remains outside this local MTP result. This is a private 0.1.2 +development deployment, not a public release; v0.1.1 is unchanged. `TRAINLOG_NATIVE_BUILD_AND_CANDIDATE_V1` closes the native warning gate. Strict GCC 16.2.1 and Clang 22.1.8 builds now pass the same 81-test inventory, and the @@ -75,6 +76,7 @@ parallel implementation of its rules. | Web sync API V1 | `TRAINLOG_WEB_SYNC_API_V1=PASS/FROZEN` | | Web sync button V1 | `TRAINLOG_WEB_SYNC_BUTTON_V1=PASS/FROZEN` | | Sync Web end-to-end wrapper | `TRAINLOG_SYNC_WEB_END_TO_END_V1=PASS/FROZEN` (isolated) | +| Private full-generation rollout | `TRAINLOG_SYNC_FINALIZATION_AND_ROLLOUT_V1=PASS` (direct MTP, one authorized phone) | | Local Web | `TRAINLOG_WEB_V1=CONTRACT_FROZEN / IMPLEMENTATION_STARTED` | | Complete synchronization gap contract | `TRAINLOG_SYNC_GAP_CONTRACT_V1=CONTRACT_FROZEN / IMPLEMENTATION_IN_PROGRESS` | | Isolated synchronization test environment | `TRAINLOG_SYNC_TEST_ENV_V1=PASS/FROZEN` | diff --git a/docs/reviews/sync_rollout_v1_deployment.md b/docs/reviews/sync_rollout_v1_deployment.md new file mode 100644 index 0000000..8dd05ea --- /dev/null +++ b/docs/reviews/sync_rollout_v1_deployment.md @@ -0,0 +1,67 @@ +# Full-generation synchronization V1 private deployment record + +Date: 2026-09-17 + +Status: `TRAINLOG_SYNC_FINALIZATION_AND_ROLLOUT_V1=PASS` + +This record deliberately omits phone serials, peer IDs, generation IDs, +credential locations, user content, and private backup hashes. Complete causal +evidence is retained in the private rollout journal. + +## Installed set + +- Trainlog 0.1.2 development; desktop schema v21 and Android schema v20. +- Versioned relocatable desktop bundle behind stable user-bin symlinks. +- Android release-variant APK installed only through compatible signed updates; + the final private rollout version code is 6. +- Production direct-libmtp generation adapter with one explicitly paired peer. +- Loopback Web service and the user-session request daemon are active from the + same versioned installation. No live-checkout runtime helper is used. + +## Data and migration evidence + +- The original Android schema-v17 store was backed up through the signed bridge + UI and verified for manifest, digests, SQLite integrity, foreign keys and an + exact semantic match to the pre-update store. The real archive migrated on a + copy before live installation. +- A post-migration Android backup was also verified. The real source contained + no active draft, so draft restoration was correctly not applicable; no + synthetic draft was inserted. +- The desktop schema-v18 store was copied with SQLite's backup API, validated, + and migrated on an isolated copy before the live schema-v21 open. Historical + table values were preserved. +- Backups, failed generations, rejection ACKs and successful generation/ACK + evidence remain retained. No one-sided rollback was performed after causal + writes began. + +## Operational evidence + +- The actual foreground Android advertisement exposed the required persistent + identity and all five capabilities. +- Production libudev/libmtp discovery and object transfer completed on the + selected unlocked phone. +- Three final bidirectional conversations completed with a durable consumed ACK + on each peer and all eight required domains reported successful. +- A service/application restart and a second non-destructive exchange produced + no duplicate business data. Logical hashes for 23 desktop business tables + and 540 rows were identical before and after replay; integrity and foreign-key + checks passed. +- Android visibly returned to an enabled action and displayed synchronization + completion for both Android and PC. + +## Rollout repairs + +The real rollout exposed and closed four bounded defects: feedback idempotence +depended on the SQLite row representation; the desktop package omitted several +runtime exporters; Android accepted stale coordination filenames without +run/generation correlation; and its UI waited for a legacy receipt after the +generation coordinator had already completed. Regression tests cover each +affected boundary. + +## Remaining limits + +The phone must be connected, unlocked and in the foreground synchronization +flow. Retained outgoing generations remain subject to the explicit capacity of +eight per peer; evidence is never silently evicted. Drive was not configured or +tested. This private deployment does not publish 0.1.2, create a tag or release, +or alter the existing v0.1.1 release. diff --git a/docs/roadmap.md b/docs/roadmap.md index 194a2a2..bf34b97 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,9 +1,9 @@ # Roadmap -Before controlled rollout, complete and validate the physical libmtp generation -adapter, establish a legitimate installed-Android backup path, verify release -signing continuity and obtain explicit rollout approval. Do not enable generation -mode or advance `main` before those gates. +The controlled private rollout is complete for the paired daily installation: +physical libmtp, verified backups, signing continuity, migrations, correlated +ACKs, restart, and idempotent replay passed. Generation mode remains an +explicit per-installation opt-in; Drive is still unconfigured and unvalidated. This document owns future work. The implemented baseline is summarized in [current_state.md](current_state.md); completed narratives and evidence belong @@ -38,7 +38,7 @@ visualizations are implemented; the other four Web routes remain placeholders. ## Current cursor ```text -CURRENT_OPERATIONAL_CURSOR=TRAINLOG_SYNC_DEPLOYMENT_READINESS_V1 +CURRENT_OPERATIONAL_CURSOR=TRAINLOG_WEB_V1_NEXT_CONTRACT ``` The focused `TRAINLOG_SYNC_CAUSAL_DELETE_V1_CLOSEOUT` is complete before this @@ -47,9 +47,10 @@ cross-platform draft revision identity and resource-bound admission are closed. `TRAINLOG_SYNC_GENERATION_ACK_V1=PASS/FROZEN`: both platforms expose explicit coherent capture, immutable manifest publication, whole-generation transactional consumption, durable correlated ACK and restart/replay entry -points. The orchestrator, Web API and Web control are now complete behind an -explicit trusted opt-in. Automatic V3 selection remains unchanged. The next -boundary is deployment readiness; no rollout starts here. +points. The orchestrator, Web API and Web control are complete behind an +explicit trusted opt-in. The authorized private direct-MTP rollout passed on +real hardware; automatic V3 selection remains unchanged without that opt-in. +The next work returns to separately contracted Web surfaces. `TRAINLOG_SYNC_GAP_CONTRACT_V1=CONTRACT_FROZEN / IMPLEMENTATION_IN_PROGRESS` defines the complete-sync target and its bounded dependency order. diff --git a/docs/sync_exchange.md b/docs/sync_exchange.md index 4f41dc7..33c60c7 100644 --- a/docs/sync_exchange.md +++ b/docs/sync_exchange.md @@ -776,6 +776,19 @@ idempotently. Causal V1 operation bytes remain unchanged across first emission and retransmission because generation membership lives only in `sync_causal_publications`. +The foreground Android coordinator correlates both durable desktop ACKs and +desktop generation references by the active run (and the Android generation +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 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 +23 desktop business tables and 540 rows retained identical logical hashes. +Rejected pre-fix generations and their ACKs were retained as causal evidence. +No Drive transport was configured or claimed by this validation. + The generation MTP adapter resolves `Documents/Trainlog` through libudev and libmtp, selects one exact advertised peer/capability set across bounded devices and storages, and mirrors only bounded regular object names. It downloads to diff --git a/docs/sync_rollout_readiness.md b/docs/sync_rollout_readiness.md index 9b1f402..c3dfacb 100644 --- a/docs/sync_rollout_readiness.md +++ b/docs/sync_rollout_readiness.md @@ -1,6 +1,17 @@ # Full-generation sync rollout readiness -## Deployment-readiness candidate +## Operational rollout status + +`TRAINLOG_SYNC_FINALIZATION_AND_ROLLOUT_V1=PASS` on 2026-09-17 for the +authorized private daily installation. Verified real Android and desktop +backups were retained, migration copies passed before live updates, the signing +identity and increasing Android version-code chain were verified, and the +production libmtp adapter completed bidirectional manifest/ACK conversations. +Restart and idempotent replay also passed. Drive was not configured. No public +release or tag was created, and v0.1.1 was not modified. The sanitized evidence +record is [sync rollout V1 deployment](reviews/sync_rollout_v1_deployment.md). + +## Deployment-readiness contract The generation path remains disabled unless desktop configuration authorizes a specific persisted Android peer and Android contains the strict opt-in document @@ -10,12 +21,10 @@ bounded typed progress and its descendant process group. The foreground Android coordinator advertises its real peer identity, publishes manifest-last bytes, consumes the return generation and emits a durable correlated ACK. -The integrated proof uses the production generation adapter with only its -typed libudev/libmtp I/O callbacks replaced by an object-store double. This is -software evidence for selection, bounds, publication ordering and the complete -conversation, but not evidence for a particular phone's physical libmtp -behavior. Generation mode must remain disabled until that hardware gate and -the separately authorized rollout are complete. +The isolated proof still uses the production generation adapter with only its +typed libudev/libmtp I/O callbacks replaced by an object-store double. The +separate deployment record owns the physical-phone evidence; neither proof +generalizes pairing to another phone or enables generation mode by default. ### Candidate, backup and recovery @@ -54,12 +63,10 @@ the separately authorized rollout are complete. preserve pending generations, tombstones, finalizations and ACK ledgers; it must never trigger hidden eviction. -Actual rollout needs one separate approval for the signed APK, desktop bundle, -verified user backups, coordinated service quiescence, pairing, synthetic smoke -and non-destructive hardware smoke. Drive remains separate and untested here. - -This is a non-executed rollout checklist. The development branch implements the -path; the daily installation still uses V3. +The grouped rollout approval covered the signed APK, desktop bundle, verified +user backups, coordinated service quiescence, pairing, synthetic smoke and +non-destructive hardware smoke. Those steps are complete for the recorded +private installation. Drive remains separate and untested. The latest software-only candidate set was rebuilt under the private root `/home/fy59/.cache/trainlog/sync-rollout-candidate-v1.NEoMDx` from source commit @@ -106,5 +113,6 @@ operator diagnosis; this tranche adds no tombstone or evidence garbage collection. A migrated database is recovered from its verified backup, never by assuming an older binary reverses its migration. -Physical MTP, actual Drive configuration, service coordination, installed APK, -main merge and deployment are intentionally not performed here. +The recorded private installation completed physical MTP, service coordination +and APK/desktop deployment. Actual Drive configuration remains untested; the +eight-generation admission bound and foreground-phone requirement remain. diff --git a/docs/tests.md b/docs/tests.md index e1b3a27..436ac90 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -1361,3 +1361,17 @@ SQLite value type and value before restore, migrates through the production repository owner, and compares that complete historical shape afterward. The draft assertion follows the archived state instead of requiring the synthetic fixture's sample draft. + +## Private full-generation rollout validation + +The authorized 2026-09-17 rollout added regression coverage for production +failures found only after installation: feedback import under `sqlite3.Row`, +the complete exporter inventory of the relocatable package, stale Android ACK +and generation-reference correlation, and the completed-generation UI state. +The real direct-libmtp smoke then completed three bidirectional conversations +on the paired phone. Restart and replay preserved identical logical hashes for +23 desktop business tables and 540 rows; SQLite integrity and foreign-key +checks passed, both outgoing desktop generations were acknowledged, and the +Android UI displayed completion. The private journal retains exact IDs and +hashes. Drive and `connectedDebugAndroidTest` were not run; the personal phone +was used only for non-destructive install, backup and manual sync validation.