-
Timmy daily-2026-10-29 — operator backup, restore, and runbook
Pre-ReleaseQuality gates / quality (push) Canceled after 0sreleased this
2026-10-29 12:46:43 +00:00 | 16 commits to main since this releasePrerelease for review — tag
daily-2026-10-29on commit65a0258bba891a99b0d827fa67b79b36bb70dd11(America/New_York release date 2026-10-29, built 2026-10-29T12:35:27Z).What changed
Operator backup, restore, and production runbook (issue #39, PR #90). The corpus could ingest a consented sample, record its provenance, survive a withdrawal, and publish a card about itself — but nobody could take a copy of the records away, and no operator could bring them back. This release adds both, plus the page that says how.
scripts/operator_backup.py—backuparchives only records:manifest.jsonl(provenance and withdrawal tombstones) and the derived images it points at. Model weights, transient inference images, secrets, logs, symlinks, and oversize files are refused by name, and every skipped path is written into the manifest with its reason. An omission is an auditable decision, not silence.- Every stored member carries a SHA-256, and the archive is reproducible — sorted members, zeroed mtime/uid/gid,
gzipmtime 0 — so two backups of unchanged records are byte-identical. restorefails closed. It verifies every digest, rejects absolute, traversal, link, and unlisted members, refuses a non-empty target, and only then writes. Afterwards it recountsmanifest.jsonland refuses if the counts differ, so a lost tombstone cannot restore quietly.docs/PRODUCTION-RUNBOOK.md— the real topology, the network boundaries (the app's ownHOSTdefault is0.0.0.0; the deployment setsHOST=127.0.0.1from the mode-600 env template; the worker refuses a non-loopback publish), the four secrets and their rotation, retention, and both rollback paths. Its own test parses every documentedpython3 scripts/...command and checks each flag against the real CLI help, so the runbook cannot drift from the tools.- Release gates —
scripts/build_release.pynow runs the 11-case backup suite and the 9-case runbook suite before a release may exist, and requires four new on-camera captions. - Demo — an
OPERATOR BACKUPcard drawn from a real run: the real ingest and revoke commands build a throwaway corpus, one contribution is withdrawn, four decoy files are planted (weight shard, transient upload, env file, log), then the realbackup,verify, andrestorerun and every value on the card is read back from them.
Scope note, stated plainly: the operator backup is a command line, not a screen in the app. This release does not imply a UI. The app holds no server-side journal of its own, so there is no server copy to back up — the recording says so on screen rather than inventing one.
Not closed by this release. PR #90 deliberately does not close #39. Acceptance criterion 3 is "rollback procedure is exercised on staging": the rollback code path is exercised by
tests/staging-deploy.test.pyagainst a rootless fixture, but the live drill on the private staging host is a human gate under #53 and was not run. The runbook states exactly that.Completed ticket / PR
- Issue #39 — Define production topology, secrets, backup, and rollback runbook (open; two of three acceptance criteria delivered, the third is the #53 human gate).
- PR #90
Operator backup, restore, and production runbook (#39)— merged as65a0258after diff review: 9 files, +1170/−4, text and code only (no binaries, model weights, real medical imagery, or secrets; the env file is a credential-free example template), linked to a non-human-gate issue (area/privacy,area/release,priority/P0,type/ops— nohuman-gatelabel). - Pre-merge verification on the PR head
48f0f56:npm test230/230, backup 11/11, runbook 9/9, corpus 8/8, review 21/21, dataset-card 14/14,check:syntax,check:diff— all green before the merge was issued.
Gates — 28/28 passed
npm test230/230; backup-restore 11/11; production-runbook 9/9; corpus manifest 8/8; corpus review 21/21; dataset card 14/14; calibration harness 19/19; mobile green path; photo-first acceptance; sleek Hermes chat; manual fallback + draft recovery; provisional suggestion state; hard-stool follow-up; vision corpus refusal; abstention quality gate; worker container receipts; worker post-load readiness; longitudinal pattern summary; grounded chat citations; training contribution consent; production backup restore; production runbook commands; portable backup restore; dependency audit (0 high); syntax (node/bash/python); secret scan; forbidden artifacts; demo H.264 720×1280 probe; complete MP4 decode; release delta verified painted on camera (91/91 captions, minimum bottom padding 14px, delta caption 9 lines / 139px / padBottom 15).Build note: the first gated build of this release ran without
TIMMY_RELEASE_DELTAset, so the manifest carried the builder's fallback string "Verified rebuild of the current user-visible feature path — no new feature is claimed." That claim is false for this commit, so the build was moved to_superseded-2026-10-29-65a0258bba89-false-no-new-feature-deltaand never published; the whole gated build was re-run end to end with the real delta and passed 28/28. No gate was skipped, loosened, or interpreted away.Operating note:
timmy-app.serviceoccupies127.0.0.1:4173, the port the gated build binds. Production was stopped for the build and restored by atrap-guarded script on both paths; it reportedactiveand/api/healthz200 within two polls after each run. The build refuses to start over a live listener and hash-compares served files against the tree under test.Artifacts
- source archive
timmy-talking-turd-2026-10-29-65a0258bba89.tar.gz— 343,940 bytes — sha256560f0fb46d499d26eb5ef29edd463fedd244c497f896323ad28336cadec71b2a - demo video
timmy-talking-turd-2026-10-29-65a0258bba89-demo.mp4— 27,064,343 bytes — H.264 720×1280 yuv420p, 25 fps, 425.24 s — sha2560ef579708a7b59d828798f80750f72a519d2ff4eabd16e2c458572c07bfa205c
Model / profile
Recorded against the real app running from the built commit with
TIMMY_VISION_ENABLED=false; vision replies replay the committed synthetic corpus through the app's real analysis path. TheOPERATOR BACKUPcard is a realscripts/operator_backup.pyrun over a corpus built on camera by the real ingest and revoke commands from CC0 synthetic fixtures — no model backed anything up or verified anything here, and the card says so on screen. No live model inference appears in the video and no real photo is used anywhere.Demonstrated on camera
OPERATOR BACKUP— subtitlecommand line, not app UI — real run, synthetic corpusCOMMAND python3 scripts/operator_backup.py backup --source srv-timmy-corpusSTORED 2 members · …jpg + manifest.jsonlRECORDS samples 2 · tombstones 1 · active 1— the withdrawal is carried, not droppedREFUSED model-weights 1 · transient-inference 1/REFUSED secret 1 · log 1REASON every skipped path is named in the manifest, not silently droppedDIGEST sha256 e646e7a8066d… · reproducible (sorted, mtime 0)VERIFY ok · 2 members re-hashed against the manifestRESTORE ok · samples 2 · tombstones 1 · active 1/MANIFEST returned byte-for-byte, tombstone includedSERVER the app holds no journal of its own — there is no server copy to back up
Known accuracy limitation
Open-weight VLM acceptance is proven; Bristol accuracy is not clinically validated. The calibration receipt still reports
BLOCKEDbecause no candidate model clears every gate (issue #31). This release publishes a survivable copy of the record, not a measured classifier. User confirmation remains mandatory everywhere: photo analysis may suggest visible Bristol form, broad color, and image quality only, and never symptoms or a diagnosis. Visible color is not blood.Downloads