Backup heartbeat scan evidence¶
Frozen task: a57e1842-4a4d-43c2-b3f6-68533b19fc31 version 2.
Execution: ea056610-f06e-4ab1-909d-3c2f9a4d1e24.
Repository: h8v6/heyaira; local branch: heyaira/2f64e433.
Starting commit: bd997e94134e5d3ec543cf26472f4392dd819131.
Implementation¶
The reader validates all three complete listings first. Up to 16 manifests
use the existing serial path; larger inventories use one rclone copy call
with --files-from-raw, --no-traverse, and 16 concurrent transfers. Only
listed manifests are fetched, never encrypted backup objects. The existing
command timeout also applies to the entire batch. Every expected local file
must exist and pass the existing manifest validation before the scan can be
cached.
This retains ordering by the recorded UTC creation time and backup UUID, duplicate identity/conflict checks, and exclusion of deleting copies. Object names and modification times are not reliable ordering evidence after retention promotion. The cache timestamp now comes from the monotonic clock after the scan finishes, including successful scans with no covered marker.
Files changed: src/heyaira/backup_runtime.py,
tests/test_backup_runtime.py, and this evidence file.
Deterministic regression: fail before, pass after¶
The new test was run before changing runtime code, with HEAD still at the starting commit above (only the test additions were present):
PYTHONPATH=src python -m pytest -q -p no:cacheprovider tests/test_backup_runtime.py::test_large_retained_poll_bounds_downloads_and_caches_from_scan_completion
AssertionError: first poll: 2000 download calls, 400.0 modelled seconds; two polls: 4000 calls
assert 2000 == 1
1 failed in 1.39s
After the fix, the same test passes. The fixture contains 2,000 retained backups distributed across rolling, daily and monthly. Transfers cost a modelled 200 ms, with no sleeps: 125 waves of 16 transfers take 25 seconds, versus the 300-second heartbeat threshold. There is one download command. An immediate second poll and another 299 seconds after completion make no additional downloads. At 300 seconds after completion, one new batch runs.
Additional regressions exercise timestamp ordering with offset timestamps, duplicate identities, deleting copies, and a missing file in a batch. A failed batch is not cached; its next successful poll retries the inventory.
Checks¶
PYTHONPATH=src python -m pytest -q -p no:cacheprovider tests/test_backup_runtime.py
39 passed in 10.94s
PYTHONPATH=src python -m pytest -q -p no:cacheprovider
494 passed, 278 skipped in 99.16s (0:01:39)
git diff --check
exit 0 (no output)
All 15 original test functions in tests/test_backup_runtime.py are unchanged
(confirmed by comparing their ASTs with bd997e9, including parametrized
cases). Only the large-listing runner fixture gained support for batched
copies; its existing assertions still check all 2,000 retrieved manifests.
The existing tier, deleting, incomplete/truncated listing and conflicting
duplicate tests pass unchanged.
The full suite has no failures. Database-backed tests are skipped without isolated PostgreSQL configuration and remain for CI. Real R2 transfer latency and live PostgreSQL were not tested; the latency evidence is deterministic modelling, and subprocess listing coverage passes in the focused suite.
History and handoff¶
The result adds a new local commit on top of the starting commit. Ancestry
verification: git merge-base --is-ancestor bd997e9 HEAD (exit 0).
No existing commits were amended, rebased or reset. No push, PR, merge,
installation, deployment or production backup mutation was performed.
The final commit SHA and receipt are recorded through task_result;
independent workflow verification remains the next step.