Document history deletion private rollout

This commit is contained in:
fy59 2026-09-19 07:20:26 +02:00
parent a8c50a9512
commit 4ad7ccc9c0
5 changed files with 106 additions and 7 deletions

View file

@ -10,7 +10,11 @@
revision-guarded, atomic and replay-safe. Retained Program-execution
generations cannot resurrect a causally deleted session, and Web errors now
distinguish stale, absent, invalid and internal failures without exposing
database details.
database details. The private rollout additionally fixed complete-generation
dominance for occurrence equipment companions and made bounded ACK recovery
prioritize recent terminal evidence. Two correlated direct-MTP exchanges,
component restart and exact replay of a retained pre-deletion generation
preserved the single tombstone without duplication or resurrection.
- Added the Program execution flow. Android schema v25 can start or resume one
Program session through the existing durable singleton, preserves stable

View file

@ -83,7 +83,7 @@ parallel implementation of its rules.
| Web Sessions deletion and Programs V1 | `TRAINLOG_WEB_SESSIONS_DELETE_AND_PROGRAMS_V1=PASS` (private grouped rollout validated) |
| Programs presentation, Android projection, and deletion | `TRAINLOG_PROGRAMS_PRESENTATION_ANDROID_DELETE_V1=PASS` (private coordinated deployment and restart/replay validated) |
| Program execution flow | `TRAINLOG_PROGRAM_EXECUTION_FLOW_V1=PASS` (private coordinated deployment, real execution, correlated ACK, restart, replay, and deletion validated) |
| Web history deletion incident | `TRAINLOG_HISTORY_DELETE_HTTP500_FIX_V1=IMPLEMENTED` (Program-origin completed sessions use causal deletion and terminal execution provenance) |
| Web history deletion incident | `TRAINLOG_HISTORY_DELETE_HTTP500_FIX_V1=PASS` (private rollout, correlated full-generation exchanges, restart, retained-generation replay, and non-resurrection 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` |

View file

@ -57,3 +57,77 @@ The recovery envelope also republishes both consumed and rejected correlated
ACKs. This lets Android close an interrupted generation with the real durable
desktop rejection evidence and reclaim normal bounded capacity; no generation,
ACK, tombstone or archive is manually purged or synthesized.
## Controlled private rollout
The rollout source was advanced through bounded corrective commits to
`a8c50a9512d8754477a2491b73c0f9e0f92263bf`. The coordinated desktop archive is
`trainlog-0.1.2-a8c50a9-desktop-v28.tar.gz`, SHA-256
`e9e08b317fb97807987b8e027a072cc8235bd9ee6dff7d393df4acb8f04c8a46`.
Android code and schema were unchanged; the installed private application
remained `com.labfytools.trainlog`, versionCode 17, versionName 0.1.2, schema
25.
Before deployment, the real desktop v27 database was backed up as
`trainlog-desktop-v27.db`, SHA-256
`ffa4cd5c5fc832b4054ee6543ff89b74be7148b19ffb9af718aa0dfe787ab20a`.
The real Android product backup was
`trainlog-android-v25.tlbackup.zip`, SHA-256
`8d198dc5fb6ca5c410029342f0e3074d288dac844ce686e3a70782bdad9e8bce`.
A populated copy migration changed only `PRAGMA user_version` from 27 to 28:
all 47 business-table counts and canonical typed hashes were identical,
`integrity_check` was `ok`, and `foreign_key_check` was empty. The production
migration reached the same integrity state.
The real deletion used the Web HTTP command with the session's current causal
revision. It removed only
`se_6bb66f59-a6fb-4759-a75d-c1a79ea107e8`, created operation
`del_af8a82de-2825-45af-9f62-ec94cc61a556`, and retained exactly one deleted
causal state. Its Program execution provenance moved from `completed` to
terminal `deleted` while preserving the original observation timestamp. The
session detail then returned the bounded absent response and reload did not
restore it.
The first hardware exchange exposed two real recovery defects before a final
PASS. Generation `gen_42f8d681-373e-4f07-b08d-792a1e8e516d` was rejected
because the live Android snapshot reached the importer after its tombstone;
the subsequent generation `gen_c9d1fda8-8375-4d89-8c29-a5ae120c6c7d` proved
that the equipment-association companion required the same dominance rule.
Later retries reported `peer_capacity_exhausted`: a product backup showed four
older immutable Android generations still waiting for ACK. Their retained
manifests were processed by the production consumer and received genuine
correlated stale-lineage rejection ACKs. The recovery envelope then accepted
that exact terminal evidence. No ACK, tombstone, generation, archive or ledger
row was fabricated, deleted or edited manually.
The final post-correction exchange completed as run
`sy_b343619f-a1d2-4bea-a0af-c57aa5792aca`: Android generation
`gen_b2290cad-0554-46f9-bc30-0fbd0c8190e8` was consumed with
`sqlite-commit-full`, desktop generation
`gen_21d7efa0-bd97-4843-a0d6-111e94d669b4` was acknowledged, no capability was
missing, and `sessions_reconciled` was zero. The second exchange completed as
run `sy_58b38f82-a70c-48c3-834c-81436c687c8c`, with generations
`gen_65e4833c-5383-4374-b37f-d8add8a106e8` and
`gen_76e15f8a-1258-49f1-ac0e-b04fe9e6a8a5`, again with no missing capability
and zero reconciled sessions.
After both stores and the Web component were reopened, the Android product
backup `trainlog-android-postrestart-20260919.tlbackup.zip` had SHA-256
`7ae8f88c60bd44355c19c89e7996d8c71ec178c75aabff0979065a5a70936ed5`,
schema 25, `integrity_check=ok`, an empty foreign-key check, no disposable
session, and exactly one matching causal state and operation. Desktop remained
schema 28 with the same integrity results and terminal provenance. Canonical
hashes for every other session, occurrence, performed set, continuous result
and body observation were identical to both pre-rollout backups.
Finally, the retained pre-deletion generation
`gen_965fdf80-4412-41fb-9a46-28744a3e115b` was replayed through the production
consumer. It returned its byte-identical stored ACK; the before/after tuple was
unchanged (`target session=0`, `target operation=1`, `deleted provenance=1`,
`all sessions=9`). Real Firefox against the deployed C server passed at
1440x1000 and exactly 390x844 with no horizontal overflow. Evidence screenshots
are retained privately under
`~/.local/state/trainlog/history-delete-http500-fix-v1-web-evidence/`; their
SHA-256 values are respectively
`9c9fd42aa58b0818488ef9f8b3412abfb56e96ea3f9d30c8da2fcfe3da8c10f1` and
`70838305fe6d17485f3d5d80cf60e2639baf4ed87d148f4b55e4b6e8c25fdbca`.

View file

@ -830,13 +830,21 @@ than fabricating an ACK or discarding evidence.
Before Android captures for a negotiated `generation-archive-v1` conversation,
the desktop consumer publishes
`desktop-archive-acknowledgements-v1.json`. Its strictly correlated envelope
contains at most 32 exact consumed ACK documents already retained in the
desktop consumption ledger. This repairs the evidence gap left by older
contains at most 32 exact terminal consumed or rejected ACK documents already
retained in the desktop consumption ledger. The bounded window selects the
newest terminal evidence first, because older acknowledged generations are
normally already archived and must not starve interrupted recent
conversations. This repairs the evidence gap left by older
Android producers that advanced generation status without retaining the
received ACK. Android revalidates every document against its immutable local
generation and manifest before storing it; missing, mismatched, rejected, or
ambiguous evidence cannot make a generation archivable. The object is a
bounded coordination artifact, not a new ACK source.
generation and manifest before storing it. A consumed ACK makes its exact
generation archive-eligible; a rejected ACK closes the exact producer row but
does not make it an acknowledged archive candidate. Missing, mismatched, or
ambiguous evidence cannot advance any generation. Rejected ACKs created before
the cross-platform diagnostic canonicalization fix remain durable desktop
evidence but are omitted from the recovery envelope when Android cannot verify
their digest. The object is a bounded coordination artifact, not a new ACK
source.
If Android still cannot admit a generation, it durably publishes the
run-correlated `android-generation-error-v1.json` with
@ -852,6 +860,10 @@ helpers and the Android repository's outer transaction apply every business
row, causal state and the consumption/ACK record together. A late semantic
failure rolls back earlier writes and commits a separate bounded `rejected`
ACK; missing/incomplete transport input remains retryable and produces no ACK.
Within a complete causal envelope, a history occurrence and its equipment
association companion are both dominated when their owning session already has
a durable deletion state. Standalone history and association imports remain
strict and still reject unknown sessions or occurrences.
Lineage is scoped to the producer/consumer pair. Exact replay returns the
stored result; an accepted successor must name the last consumed generation as

View file

@ -170,6 +170,15 @@ npm run build
Release-oriented Meson builds must use `-Dweb=enabled`; Meson never provisions
or downloads npm dependencies.
The history-deletion regression suite also exercises a real Program-origin
completed session through the Core and HTTP command paths, including stale
revision, cancellation, injected transaction failure, exact request replay and
terminal execution provenance. Full-generation tests apply causal deletions
before older history and equipment-association companions, prove that
standalone imports remain strict, recover recent consumed and rejected ACKs
without letting an older bounded window starve active producer capacity, and
replay an already consumed generation without mutation.
`WEB_DASHBOARD_DATA_CONTRACT_V1` adds a standalone bounded Core test for empty
history, explicit unavailable domains, two observable sessions on one local
day, an unfinished session, continuous activity, MAX-only sessions, primary