Prepare governed S1 offsite upload
All checks were successful
CI Smoke / source-contract (push) Successful in 11s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02994-7685-7940-bf34-3555b8256018
This commit is contained in:
codex 2026-08-23 14:11:00 +02:00
parent 2c92b97f37
commit d0a5a27926
11 changed files with 844 additions and 11 deletions

View file

@ -250,11 +250,33 @@ def plan_prune(spec_path: Path, output_dir: Path | None) -> dict[str, Any]:
retention["keep_complete_bundles"],
retention["max_total_bytes"],
)
missing_evidence: list[str] = []
if declaration["offsite"]["required_before_prune"]:
from s1_offsite import OffsiteError, validate_prune_receipt
receipt_root = Path(declaration["offsite"]["receipt_root"])
for candidate in candidates:
try:
validate_prune_receipt(
candidate,
spec_path,
receipt_root / f"{candidate.name}.offsite.json",
)
except (OffsiteError, OSError):
missing_evidence.append(candidate.name)
blocked = bool(missing_evidence)
return {
"approval": _prune_approval(root, candidates) if candidates else None,
"approval": _prune_approval(root, candidates) if candidates and not blocked else None,
"backup_root": str(root),
"candidates": [path.name for path in candidates],
"status": "approval-required" if candidates else "nothing-to-prune",
"missing_offsite_evidence": missing_evidence,
"status": (
"blocked-missing-offsite-evidence"
if blocked
else "approval-required"
if candidates
else "nothing-to-prune"
),
}
@ -262,6 +284,8 @@ def apply_prune(spec_path: Path, output_dir: Path | None, approval: str) -> dict
plan = plan_prune(spec_path, output_dir)
if not plan["candidates"]:
return plan
if plan["missing_offsite_evidence"]:
raise BackupError("prune requires a passing off-site receipt for every candidate")
if approval != plan["approval"]:
raise BackupError("prune approval does not match the current exact candidate set")
root = Path(plan["backup_root"])