Files
FreeCADWasmDev/tools/repair_continuation_checkpoint.py
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

74 lines
2.8 KiB
Python

#!/usr/bin/env python3
"""Repair a stale continuation checkpoint from the authoritative task ledger.
Only the generated checkpoint projection is changed. Task statuses, counts and
the active ledger entry are never modified by this tool.
"""
from __future__ import annotations
import argparse
import json
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
STATE = ROOT / "docs/current/task-state.json"
CHECKPOINT = ROOT / "docs/current/continuation-state.json"
MODULE_BATCH = ROOT / "docs/current/module-batch-manifest.json"
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--quiet", action="store_true")
args = parser.parse_args()
state = json.loads(STATE.read_text(encoding="utf-8"))
checkpoint = json.loads(CHECKPOINT.read_text(encoding="utf-8"))
active = state.get("active_task")
counts = state.get("counts", {})
statuses = state.get("tasks", {})
if not active or counts.get("in_progress") != 1 or statuses.get(active) != "in_progress":
if not args.quiet:
print("CHECKPOINT_REPAIR_NOT_APPLICABLE: ledger has no single in_progress active task")
return 2
previous = checkpoint.get("activeTask")
changed = False
if previous != active:
checkpoint["activeTask"] = active
changed = True
batch = None
try:
batch = json.loads(MODULE_BATCH.read_text(encoding="utf-8"))
except (FileNotFoundError, json.JSONDecodeError):
batch = None
previous_batch_id = checkpoint.get("batchId")
if isinstance(batch, dict) and batch.get("batchId") and previous_batch_id != batch.get("batchId"):
checkpoint["batchManifest"] = "docs/current/module-batch-manifest.json"
checkpoint["batchId"] = batch.get("batchId")
checkpoint["batchSelection"] = batch.get("selected")
changed = True
if not changed:
if not args.quiet:
print(f"CHECKPOINT_ALREADY_ALIGNED: active={active}")
return 2
checkpoint["phase"] = "CONTINUE"
checkpoint["lastCheckpoint"] = "CONTINUE"
checkpoint["lastTransition"] = datetime.now(timezone.utc).isoformat()
checkpoint["checkpointRepair"] = {
"reason": "ledger_or_batch_projection_mismatch",
"previousActiveTask": previous,
"repairedActiveTask": active,
"previousBatchId": previous_batch_id,
"repairedBatchId": checkpoint.get("batchId"),
"repairedAt": datetime.now(timezone.utc).isoformat(),
}
temporary = CHECKPOINT.with_suffix(".repair.tmp")
temporary.write_text(json.dumps(checkpoint, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
temporary.replace(CHECKPOINT)
print(f"CHECKPOINT_REPAIRED: previous={previous} active={active}")
return 0
if __name__ == "__main__":
raise SystemExit(main())