#!/usr/bin/env python3 """Schedule bounded failure review alongside the owning module's business.""" import argparse import hashlib import json from datetime import datetime, timezone from failure_reconciliation import ROOT, synchronize, write, read from scheduler_progress import cooling_ids, retry_details def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--module") options = parser.parse_args() ledger = synchronize() rows = [row for row in ledger["records"].values() if row["status"] == "pending" and (options.module is None or options.module in row["modules"])] for row in rows: owner = options.module or next((module for module in row["modules"] if module != "Shared"), "Web") row["queueModule"] = owner row["queueId"] = f"failure:{owner}:{row['key']}" cooling = cooling_ids(candidates={row["queueId"] for row in rows}) deferred = {row["queueId"] for row in rows if row["queueId"] in cooling} pending = [row for row in rows if row["queueId"] not in cooling] output = ROOT / "docs/current/module-batch-manifest.json" if not pending: payload = {"schema": "freecad-web-module-business-batch/v1", "status": "no_ready_batch", "records": [], "strategy": "module-business-first-deferred-validation", **retry_details(deferred)} else: pending.sort(key=lambda row: (row["queueModule"], row["legacyValidation"], row["category"], row["key"])) module = pending[0]["queueModule"] selected = [row for row in pending if row["queueModule"] == module][:4] ids = [row["queueId"] for row in selected] identity = "|".join([module, "failure-reconciliation", "failure-reconciliation", *ids]) payload = {"schema": "freecad-web-module-business-batch/v1", "status": "ready", "strategy": "module-business-first-deferred-validation", "taskId": read(ROOT / "docs/current/task-state.json").get("active_task"), "batchId": hashlib.sha256(identity.encode()).hexdigest()[:24], "minimumRecords": 1, "singletonFallback": len(ids) == 1, "selected": {"module": module, "tier": "failure-reconciliation", "family": "failure-reconciliation", "recordCount": len(ids)}, "records": [[row["queueId"], row["category"], "pending", "tools/failure_reconciliation.py", 1] for row in selected], "failureKeys": [row["key"] for row in selected], "queue": []} payload["generatedAt"] = datetime.now(timezone.utc).isoformat() write(output, payload) print(json.dumps({"status": payload["status"], "selected": payload.get("selected"), "pendingFailures": len(rows)}, ensure_ascii=False)) return 0 if __name__ == "__main__": raise SystemExit(main())