What data Transit keeps, for how long, how it is backed up and which guarded commands repair each kind of failure.

Reference Value
Subject and boundary Retention defaults, backups and restore proof, guarded recovery actions, replay and repair commands, and credential rotation for retained data. Day-to-day monitoring is on ‣.
Verified source settings.py, recovery.py, backups.py, restore-backup-proof.sh, cli.py at main 9733eb26d92533f56cdc8bc46b81b93fbb5987c8, checked November 10, 2026.
Support state Implemented commands. Defaults are source values; a deployment can override them through environment variables. Every mutation below is an operator action against production and needs the owner's explicit approval.

Retention defaults

Data Default Setting
Silver static datasets 1 current dataset STATIC_DATASET_RETENTION_COUNT
Bronze static, realtime and i3 objects 30 days BRONZE_STATIC_RETENTION_DAYS, BRONZE_REALTIME_RETENTION_DAYS, BRONZE_I3_RETENTION_DAYS
Silver realtime 1 day SILVER_REALTIME_RETENTION_DAYS
Silver closed i3 alert history 90 days SILVER_I3_CLOSED_RETENTION_DAYS
Gold detail facts 14 days GOLD_FACT_RETENTION_DAYS
Gold warm rollups 730 days GOLD_WARM_ROLLUP_RETENTION_DAYS
Logical database backups 7 copies BACKUP_RETENTION_COUNT

Longer reporting horizons come from warm rollups, not facts. Because Silver realtime expires before Gold, some repairs first need a bounded Silver restore from Bronze. A retained aggregate does not guarantee access to the raw inputs needed for a correction. A retention change must update Settings, .env.example, Compose defaults and tests together.

uv run transit-ops retention-proof-report stm --report-path retention-proof.json writes a non-destructive proof. Exit 1 means a dry-run section or static-feed validation is unavailable or invalid. Pruning runs continuously in the pruner service (Silver, Gold) and in the Warm workflow's retention job (i3, warm rollups, Bronze).

Backups and restore proof

scripts/backup-postgres.sh runs backup-database in a one-off worker container from host cron. The cron entry lives on the host, outside the repository; the repository records only its expected daily 09:30 UTC run, in the verify-backup-freshness help text of cli.py, so the schedule and crontab owner are a documentation gap here. The script streams a pg_dump (zstd:3) to the Bronze bucket under backups/postgres. Table data for silver.rt_trip_update_stop_times is excluded by default. list-backups, download-latest-backup and verify-backup-freshness read the backup set; the hourly freshness-probe job runs the last one and opens an alert issue on failure.

bash scripts/restore-backup-proof.sh restores the newest backup into a throwaway local PostgreSQL 16 cluster and checks recorded revision, critical data, exclusions, PostGIS and durability settings.

Setting Default Purpose
RESTORE_WORKDIR /tmp/transit-restore-proof Must not exist; created privately
PG_BIN /usr/lib/postgresql/16/bin PostgreSQL 16 binaries with PostGIS
RESTORE_PORT, RESTORE_JOBS 55434, 4 Socket port and parallel restore jobs
RESTORE_DUMP_FILE unset Use a local dump; no download is required
RESTORE_MIN_FREE_GB 30 Free space required
RESTORE_EXPECTED_REVISION unset Defaults to the repository's Alembic head
KEEP_RESTORE_WORKDIR 0 1 keeps the cluster for tests/test_restore_proof_real_db.py

The script reports download, restore, smoke and total seconds. A successful drill proves that backup under those host conditions; it does not establish production recovery time.

Content-section readability

The document's HTML transform injects the shared v0.39.1 boot script, with its CSP hash supplied by the pinned package. Server HTML contains readable section bodies. On pages with at least two eligible sections and the bulk control, normal initialization applies sections-choice or the first-visit collapsed state.

If app code fails or stalls during initialization, boot recovery reveals pending sections on script/runtime errors, unhandled rejections or the five-second deadline. It clears pending closed/inert presentation, hides/disables incomplete bulk controls and marks the fallback so delayed initialization honors readable content. Recovery does not write or clear the saved bulk choice. With JavaScript unavailable, the server bodies provide readable content.

This path concerns section markup, separate from service-worker caches and database recovery. Inspect section-body visibility and focus/accessibility state when diagnosing it. Source support and the live commit receipt do not prove a failure scenario on every device.

Browser shell and offline recovery

The service worker caches shell assets and fonts; navigation remains network-first, with cached /offline used only when the network fetch fails. Its policy bypasses transit data and Range requests, so clearing this shell cache neither repairs published snapshots nor provides offline transit data.

The kill switch is /sw-kill.json. With disabled: true, page registration unregisters existing service workers, deletes the origin's caches and skips registration. The worker checks at activation, on CHECK_KILL and on navigation at most once per five minutes; when disabled it deletes caches, attempts unregister and sends SW_KILLED to clients. Offline clients cannot observe a new flag until they reconnect. Cache deletion and unregister are separate best-effort browser operations, not an instantaneous fleet-wide rollback.

The tracked flag at this revision is disabled: false. A kill-switch change and deployment belong to a separate operator packet; none is performed here. Verify the served flag, registration state, cache removal and network navigation on a connected affected client before claiming recovery. This browser-shell mechanism does not change database retention or restore data.

Choose the recovery that matches the failure