188 lines
11 KiB
Markdown
188 lines
11 KiB
Markdown
# Generation capacity recovery V1
|
|
|
|
## Cause and preserved boundary
|
|
|
|
The 2026-11-10 private desktop incident reached its unchanged limit of 16:
|
|
14 `waiting_acknowledgement` generations plus two acknowledged recovery
|
|
members. Recovery retrieved 32 authentic Android ACKs, none for those 14.
|
|
The desktop worker always captured a new generation after inbound consumption,
|
|
even after a previous conversation had interrupted publication or ACK handling.
|
|
Later successful siblings advanced from the same acknowledged parent while
|
|
old pending branches continued consuming admission. The desktop admission SQL
|
|
also omitted the acknowledged-sibling exclusion already documented and used
|
|
by Android. Archiving acknowledged generations alone cannot repair this state.
|
|
|
|
The incident consumed an Android generation before desktop capture failed.
|
|
That inbound commit remains durable; the run is failed, never successful.
|
|
The retained Android `peer_capacity_exhausted` error has a different run ID
|
|
from this incident and is historical evidence, not proof of current saturation.
|
|
|
|
## Recovery invariant
|
|
|
|
A pending branch may leave active admission only if a distinct sibling has the
|
|
same producer, consumer and parent (including a null root), is acknowledged,
|
|
and owns a consumed `sqlite-commit-full` ACK matching its exact original run,
|
|
peer identities and manifest SHA-256. Archived siblings remain valid proof.
|
|
Neither elapsed time nor ACK absence proves non-consumption. All generation
|
|
rows, manifests, artifacts, hashes, causal relationships and memberships remain
|
|
unchanged. No sibling ACK advances the pending branch's domain publication
|
|
state. Its own authentic late ACK remains accepted and replay-protected.
|
|
|
|
The worker resumes the unique unresolved branch using verified immutable
|
|
bytes. Its mutable reference uses the current conversation run while the
|
|
manifest and ACK use their original run. ACK selection additionally correlates
|
|
the generation ID and manifest digest; the production validator still checks
|
|
all ACK fields. Multiple unresolved branches fail closed. The limit remains
|
|
16 and no schema or frozen exchange format changes.
|
|
|
|
## Private copy validation
|
|
|
|
The existing backup and live database both passed SQLite `quick_check`.
|
|
A fresh SQLite backup, complete owned/transport directory copies, table-count
|
|
inventory and reproduction evidence are retained privately under:
|
|
|
|
`~/.local/share/trainlog/backups/capacity-recovery-20261110T181125/`
|
|
|
|
The original source reproduced `generation retention capacity exhausted` on a
|
|
separate backup. The corrected predicate identifies 13 superseded branches,
|
|
leaving three active members: two acknowledged and one unresolved. All 14
|
|
pending immutable generations passed manifest and artifact verification. The
|
|
one unresolved generation was successfully republished byte-for-byte on the
|
|
copy. A current complete production capture then succeeded, including Programs
|
|
V2 and Sleep. Fingerprints covered 56 non-sync tables: the only capture change
|
|
was the expected Sleep generation-membership insertion. Session, Program,
|
|
body, Sleep facts, heart-rate and Cardio values remained unchanged.
|
|
|
|
No personal payload or database is committed as a fixture.
|
|
|
|
## Automated validation
|
|
|
|
- C17 strict-warning desktop build, including the embedded Web frontend: pass.
|
|
- `test_sync_generation_exchange.py`: 21 tests pass, including new capacity,
|
|
exact-evidence rejection, late ACK, immutable replay, corruption rejection,
|
|
divergent pending branches, committed inbound data surviving outbound
|
|
saturation/restart, and archival regressions.
|
|
- Full Meson suite with Web enabled: 113/114 pass. The remaining failure is
|
|
`tui_workflows`, `tui/tests/test_tui_workflows.c:1680`, asserting three
|
|
Dashboard performance points in a dated fixture. Its C sources and binary
|
|
inputs are unchanged by this Python-only correction; this is an existing
|
|
baseline limitation, not claimed as a passing test.
|
|
- JSON catalog/schema validation and import-contract validation: pass.
|
|
- Changed C/H format check: pass (no changed C/H files).
|
|
- No C implementation changed, so a new C sanitizer checkpoint is not required.
|
|
|
|
The first full-suite configuration lacked installed Web dependencies and
|
|
failed the deployment-package test. After `npm ci` and Web-enabled rebuild,
|
|
that test passed. No production warning policy was weakened.
|
|
|
|
## Local deployment and rollback
|
|
|
|
The deployed helper directory is separate from development and previous
|
|
rollouts:
|
|
|
|
`~/.local/share/trainlog/rollouts/sync-capacity-recovery-v1-292bcc8/tools/`
|
|
|
|
It copies the daily Web rollout's tools and reference catalog with only the two
|
|
corrected helpers replaced; a SHA-256 inventory is retained beside it. Both user services use
|
|
`90-capacity-recovery.conf` drop-ins. Existing desktop binaries, Web assets and
|
|
transport adapters remain in their previous rollouts. Services were stopped
|
|
for a fresh coherent predeployment backup and restarted after configuration
|
|
publication. A private `rollback-services.sh` removes only these drop-ins and
|
|
restarts the previous services; it does not roll back business data or delete
|
|
any backup or generation evidence.
|
|
|
|
The initial deployment attempt showed that the daily Web shell launcher
|
|
unconditionally overwrites `TRAINLOG_SYNC_TOOLS_DIR`. The resulting first
|
|
controlled attempt still used the old helpers and failed after inbound commit.
|
|
Its failure evidence is retained. The corrected drop-ins bypass that wrapper
|
|
using its same underlying binary and explicit adapter paths. The sync daemon
|
|
uses the isolated tools and an explicit orchestrator path. Actual `/proc`
|
|
environment and command lines verified both paths after restart. No previous
|
|
rollout files were edited.
|
|
|
|
A second attempt received a current Android generation but exposed a missing
|
|
reference catalog in the isolated deployment, before its import transaction.
|
|
The original catalog was copied into the isolated package. The deployed
|
|
consumer then accepted that exact Android generation on a fresh database copy,
|
|
and all 14 production capture participants exported successfully using that
|
|
same deployed package on the copy. Its private test ACK was never published to
|
|
the phone. The failed attempt remains recorded as failed.
|
|
|
|
## Physical validation
|
|
|
|
The Android-triggered recovery run
|
|
`sy_f9f0f9eb-e804-4149-a438-755ce0f3fdac` completed over Bluetooth on
|
|
2026-11-10. It consumed Android generation
|
|
`gen_5f1d5c2c-d87c-4f35-9ca1-2ea3254c65c1` and replayed the exact pending
|
|
desktop generation `gen_cf95dd3b-6fff-4791-9101-e0eceb24ee7d`. Android returned
|
|
its authentic original-run consumed ACK; the desktop ledger corroborated both
|
|
halves. The active count is three and the 13 superseded pending branches
|
|
remain retained. This proves historical recovery, not publication of current
|
|
PC edits.
|
|
|
|
After the initial deployment faults were repaired, a Web waiter and the
|
|
phone's new explicit conversation had incompatible freshness baselines. The
|
|
stale waiting orchestrator was sent SIGTERM, recorded `interrupted`, released
|
|
its owned worker and lock, and preserved evidence. The Android-triggered daemon
|
|
then completed the recovery. A concurrent Web attempt correctly failed the
|
|
common lock instead of starting a second engine. A later Web waiter was also
|
|
interrupted before import so the remaining controlled validations could be
|
|
conducted through the phone's explicit trigger and daemon ledger alone.
|
|
|
|
Before current-snapshot convergence, the returned Android snapshot contained
|
|
31 sessions, 7 body observations and 44 exercises. Desktop had 46 exercises,
|
|
including the two requested new ones; their actual Android return remains a
|
|
separate convergence check. All 5,817 pre-existing owned immutable files were
|
|
verified unchanged. The live non-sync table comparison found only Sleep
|
|
publication validation/acknowledgement timestamp updates, with no change to
|
|
business values or revision identities.
|
|
No Android APK or app data has been changed. ADB exposes no connected device;
|
|
the paired Bluetooth device is connected. The transport advertisement includes
|
|
manifest/ACK/archive/recovery V1, history V4 and Programs V1/V2 capabilities.
|
|
An advertisement is protocol evidence, not proof of the installed APK version.
|
|
|
|
The current-snapshot run `sy_d18e8160-2917-458f-a1ce-3b3c58927a1b`
|
|
completed in both directions at 17:26:45 UTC. Its outbound
|
|
`gen_27f564c0-155b-41ba-8906-768894235499` has an authentic Android consumed
|
|
ACK. The user also confirmed completion without error on the phone. Comparing
|
|
all 56 non-sync tables against the predeployment backup found no business-value
|
|
or revision changes or deleted keys: only validation/ACK timestamps and 11 new
|
|
Sleep generation-membership rows changed. Existing sessions, Programs and
|
|
planning, body data, Sleep facts, heart-rate and Cardio tables were unchanged.
|
|
|
|
The distinct idempotence run `sy_97e963d7-189f-4c44-b49d-bf339b14347d`
|
|
also completed in both directions, with outgoing
|
|
`gen_283f98e0-13fe-4def-ae9d-ad5b10f3063f`. Both current outgoing manifests
|
|
contain Programs V2 and Sleep and have exact authentic consumed ACKs; each
|
|
inbound generation has a committed consumed ledger row. The user confirmed
|
|
that this attempt entered progress and completed, and that both requested
|
|
exercises are visible in Android. A received Android history artifact also
|
|
contains both names, 46 exercises, 31 sessions and 7 body observations; all
|
|
three stable-ID sets equal the canonical desktop sets.
|
|
|
|
The final 56-table comparison against the snapshot taken before idempotence
|
|
found no change to business values or revisions. Expected synchronization
|
|
metadata changes were limited to Sleep validation/ACK timestamps, 11 additional
|
|
Sleep generation-membership rows, and two body-zone synchronization markers
|
|
for the two newly propagated exercises. Existing body-zone rows were retained.
|
|
No session, set, Program, body, Sleep fact, heart-rate sample or Cardio row was
|
|
deleted or duplicated. Desktop retains 517 sets, 6 Programs, 98 Program
|
|
sessions, 23 execution links, 17 Sleep entries, 19 heart-rate captures and
|
|
93,903 samples plus 93,903 RR intervals. SQLite `quick_check` remains `ok`.
|
|
All 13 historical pending generations still validate from their immutable
|
|
files, and no unresolved unsuperseded desktop generation remains. The active
|
|
window is three after capture (the normal next archive pass returns it to two);
|
|
the unchanged admission limit is 16.
|
|
|
|
Private proof owners include `final-convergence.json`, `android-roundtrip.json`,
|
|
the three completed-run reports and their authentic ACK files, coherent
|
|
predeployment/before-idempotence/final SQLite backups, copied immutable trees,
|
|
validation logs, installed-file digests and rollback instructions. The Web's
|
|
separate last waiter remains truthfully `interrupted`; the Android-triggered
|
|
service ledger owns the successful controlled runs. No success status was
|
|
fabricated or copied into a different conversation's history.
|
|
|
|
`TRAINLOG_SYNC_GENERATION_CAPACITY_RECOVERY_V1=PASS` applies to this correction,
|
|
its deployment and the controlled bidirectional convergence/idempotence checks.
|
|
It does not claim the unrelated baseline TUI test passes. No Android APK,
|
|
identity, app data, database schema, or remote Git repository was changed.
|