One zip: the full database as JSON, the five CSVs, and every photo and voice memo. The JSON is the copy you restore from — the CSVs are views generated from it.
⬇ latch-bundle.zip ≈ {{ est.total_bytes|filesizeformat }}
⬇ data only, no media ≈ {{ est.db_bytes|filesizeformat }}
⚠️ {{ est.media_missing }} media row{{ 's' if est.media_missing != 1 }} ha{{ 've' if est.media_missing != 1 else 's' }} no file on disk. They are skipped and named in the archive's MANIFEST.txt rather than failing the whole export.
{% endif %}The zip is streamed, so the browser cannot show a progress bar for it — that is expected, not a stall. Sizes here are measured, not guessed.
| ⬇ latch.json | Every table, verbatim. The restore-shaped copy — the only authoritative one. |
| ⬇ daily.csv | One row per day, gaps filled with zeros. The one to open in Numbers. |
| ⬇ events.csv | One row per event, undone ones kept and marked. The whole log, flat. |
| ⬇ sessions.csv | One row per lock, with the timer recomputed: added, frozen, elapsed. |
| ⬇ entries.csv | Reflections and check-ins, with the five scores in their own columns. |
| ⬇ assignments.csv | Every training assignment: assigned, due, verified or failed. |
| ⬇ kit.csv | One row per thing you own, with its specs and its derived numbers — bouts, hours, cost per bout. An empty cell was never measured. |
| ⬇ bouts.csv | Every bout of play or wear: what was on, how long, whether you were caged, how it ended, and the answers you gave. |
CSVs carry a UTF-8 BOM so Excel does not mangle accented text — in Python,
open them with encoding='utf-8-sig'. Each timestamp appears twice: the epoch
column is the record, the *_local column is the one a spreadsheet reads as a date.
An empty score cell means no check-in was taken; it does not mean zero.
Your Pup ID for arriving on your own new box: your key sealed under your passphrase, your papers, the kit and the photos you marked 🧳 (re-encoded, no location) — no log, no reflections. 🔴 It holds your sealed key: never hand it to anyone, not a Handler, not a pack. It needs a passphrase set on your Pup ID page. The zip above carries the sealed key too, when there is one.
This file is an unencrypted copy of every reflection and check-in. It never leaves this box unless you carry it. Nothing here is shareable — the share layer (P6) uses a separate, redacted export.
{#- 🔴 SCOPED to the export: the box as a whole may reach out (a calendar feed, a pack, an AI — the footer below says which), so an unscoped "zero outbound calls" here contradicted it. #}This file is built on this box when you ask for it, and stored nowhere — building it makes no outbound call.