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
A worker that answers /v1/models has not necessarily loaded its weights, so the app
was offering an AI control that could only fail after the upload. Readiness now
passes only once the pinned model is loaded, and the not-loaded state reaches manual
Bristol entry in one tap. Verified against the real pinned llama.cpp build: it serves
503 while loading and the gate reports the distinct not-loaded state.
Adds the reproducible container recipe (digest-pinned bases, pinned llama.cpp commit,
hash-verified read-only weights, unprivileged, loopback-only publish), one shared
post-load readiness gate used by the host bootstrap and the image healthcheck, and a
target-GPU benchmark that refuses to write a receipt it did not measure.
Refs #15
Two defects found inspecting the first demonstration of this release:
- A caption stayed on screen until the next one replaced it, so the
delete-data caption was still displayed over the home view after the
navigation. Captions now fade and remove at the end of their stated
duration, so no caption outlives the screen it describes.
- The contact sheet used a fixed 1/2 fps, so a 88s demo only showed its
first 24s in the review sheet. The sheet rate is now derived from the
probed duration and a missing sheet fails the build.
A documentation-only release previously recorded a demo captioned
'FEATURE DEMO', which implied a shipped feature that did not exist. The
demo now renders the builder-supplied release delta as its second
caption, and the builder refuses to publish unless the demo's own
machine-readable caption receipt proves that statement reached the
screen and every required feature caption did too.
The recording also shows the byte-bearing controls the photo data-flow
threat model governs (consent-gated upload, portable export, delete all
local data) using the app's real selectors, so a docs-only release
demonstrates the nearest real user-visible effect instead of inventing
UI.