The import screen already states what it restored, and the migration notice
restated the same count, so the on-screen notice read as two stacked sentences
saying one thing. The notice now only describes the upgrade, and a unit test
fails if it starts restating the restored count again.
A backup is the person's own record and has to keep working as the AI fields evolve.
- Export stamps schema version 2 and carries the confirmed logs plus the training
contribution receipts, including withdrawn tombstones; both are written through an
allowlist so unknown keys and credentials never leave the device.
- Import accepts version 1 and 2. A version 1 file is upgraded, the notice names the
version it came from, and entries that predate provenance stay null instead of being
given a source they never recorded.
- A file from a newer Timmy is refused with an update instruction, malformed, oversized
and over-limit files fail closed, and a refused import leaves the ledger unchanged.
- A log saved from a confirmed or corrected AI suggestion records its provenance
(source, suggested visible fields, model, confirmedAt) and the entry sheet states it.
- Service worker shell cache v5 -> v6 so installed clients actually receive the change.
Evidence: tests/portability.test.js (7 unit cases), tests/portability.acceptance.mjs
(real browser: v1 upgrade, future refusal with unchanged ledger, provenance recorded,
export v2, round trip), release demo scenes with on-camera caption proof, and the
release builder gate portable_backup_restore.
Refs #35