feat(cache): add rebuild and provenance safeguards

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a023c0-a0a3-7c03-b395-5a0d2757214d
This commit is contained in:
tegwick 2026-08-21 23:23:03 +02:00
parent bf3f416b82
commit 5dc2f3cdf6
11 changed files with 2809 additions and 4 deletions

View file

@ -314,6 +314,24 @@ def main(argv: list[str] | None = None) -> int:
p_authority_route.add_argument("--domain-slug", default=None)
p_authority_route.add_argument("--claimed-owner", default=None)
p_cache = sub.add_parser("cache", help="Inspect and rebuild advisory repository caches")
cache_sub = p_cache.add_subparsers(dest="cache_command")
p_cache_status = cache_sub.add_parser("status", help="Report cache age and source drift")
p_cache_status.add_argument("--path", default=".")
p_cache_rebuild = cache_sub.add_parser("rebuild", help="Rebuild the local index from files")
p_cache_rebuild.add_argument("--path", default=".")
p_cache_rebuild.add_argument("--slug", default=None)
p_cache_export = cache_sub.add_parser(
"export-closed",
help="Export unbound closed State Hub records before cache replacement",
)
p_cache_export.add_argument(
"--api-base",
default=os.environ.get("STATE_HUB_API_BASE", "http://127.0.0.1:8000"),
)
p_cache_export.add_argument("--output", required=True)
p_cache_export.add_argument("--force", action="store_true")
args = parser.parse_args(argv)
if args.version or args.command in (None, "version"):
@ -687,6 +705,49 @@ def main(argv: list[str] | None = None) -> int:
print(json.dumps({"ok": True, **result}, indent=2))
return 0
if args.command == "cache":
if not args.cache_command:
p_cache.print_help()
return 2
from repo_manager.cache import cache_status, fetch_closed_provenance
if args.cache_command == "status":
result = cache_status(Path(args.path))
elif args.cache_command == "rebuild":
from repo_manager.index_store import save_index
from repo_manager.observe import observe_repository
snapshot, index = observe_repository(Path(args.path), slug=args.slug)
index_path = save_index(index)
result = {
"ok": True,
"rebuilt": True,
"index_path": str(index_path),
"record_count": snapshot["index"]["record_count"],
"cache": cache_status(Path(args.path)),
}
else:
output = Path(args.output)
if output.exists() and not args.force:
print(
json.dumps(
{"ok": False, "error": f"output exists: {output}; use --force to replace"},
indent=2,
)
)
return 1
try:
result = fetch_closed_provenance(args.api_base)
except (OSError, TypeError, ValueError) as exc:
print(json.dumps({"ok": False, "error": str(exc)}, indent=2))
return 1
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
result = {key: value for key, value in result.items() if key != "rows"}
result["output"] = str(output)
print(json.dumps(result, indent=2))
return 0 if result.get("ok") else 1
parser.print_help()
return 0