NODEDC_1C/scripts/check_address_wave1_batch1_...

195 lines
6.9 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import datetime as dt
import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any
REPO_ROOT = Path(__file__).resolve().parents[1]
@dataclass
class CheckItem:
name: str
status: str
details: str
def read_json(path: Path) -> dict[str, Any] | list[Any] | None:
try:
return json.loads(path.read_text(encoding="utf-8"))
except Exception:
return None
def check_file_exists(path: Path, name: str) -> CheckItem:
if path.exists():
return CheckItem(name=name, status="PASS", details=str(path))
return CheckItem(name=name, status="FAIL", details=f"missing: {path}")
def check_stress_baseline(path: Path) -> CheckItem:
payload = read_json(path)
if not isinstance(payload, dict):
return CheckItem("baseline_stress_102", "FAIL", f"invalid_json: {path}")
totals = payload.get("totals")
if not isinstance(totals, dict):
return CheckItem("baseline_stress_102", "FAIL", "totals_missing")
total = int(totals.get("questions_total", -1))
strict = int(totals.get("strict_pass_count", -1))
route = int(totals.get("route_pass_count", -1))
if total == 102 and strict == 102 and route == 102:
return CheckItem(
"baseline_stress_102",
"PASS",
f"strict={strict}/{total}, route={route}/{total}",
)
return CheckItem(
"baseline_stress_102",
"FAIL",
f"expected 102/102, got strict={strict}/{total}, route={route}/{total}",
)
def check_followup_baseline(path: Path) -> CheckItem:
payload = read_json(path)
if not isinstance(payload, dict):
return CheckItem("baseline_followup_25", "FAIL", f"invalid_json: {path}")
totals = payload.get("totals")
if not isinstance(totals, dict):
return CheckItem("baseline_followup_25", "FAIL", "totals_missing")
total = int(totals.get("questions_total", -1))
strict = int(totals.get("strict_pass_count", -1))
route = int(totals.get("route_pass_count", -1))
if total == 25 and strict == 25 and route == 25:
return CheckItem(
"baseline_followup_25",
"PASS",
f"strict={strict}/{total}, route={route}/{total}",
)
return CheckItem(
"baseline_followup_25",
"FAIL",
f"expected 25/25, got strict={strict}/{total}, route={route}/{total}",
)
def check_nightly(path: Path) -> CheckItem:
payload = read_json(path)
if not isinstance(payload, dict):
return CheckItem("nightly_regression_green", "FAIL", f"invalid_json: {path}")
overall_ok = bool(payload.get("overall_ok"))
packs = payload.get("packs")
if not isinstance(packs, list):
return CheckItem("nightly_regression_green", "FAIL", "packs_missing")
bad = []
for pack in packs:
if not isinstance(pack, dict):
continue
name = str(pack.get("pack") or "unknown")
if not bool(pack.get("runner_ok")) or not bool(pack.get("validator_ok")) or not bool(pack.get("comparator_ok")):
bad.append(name)
if overall_ok and not bad:
return CheckItem("nightly_regression_green", "PASS", f"overall_ok=true, packs={len(packs)}")
return CheckItem("nightly_regression_green", "FAIL", f"overall_ok={overall_ok}, failed_packs={bad}")
def compute_ready(items: list[CheckItem]) -> bool:
return all(item.status == "PASS" for item in items)
def write_report(path: Path, items: list[CheckItem], ready: bool) -> None:
now = dt.datetime.now().astimezone().isoformat(timespec="seconds")
lines: list[str] = []
lines.append("# Wave-1 Batch-1 Readiness Report")
lines.append("")
lines.append(f"- Generated at: `{now}`")
lines.append(f"- Decision: **{'READY_FOR_PHASE_A' if ready else 'NOT_READY'}**")
lines.append("")
lines.append("## Checks")
for item in items:
mark = "PASS" if item.status == "PASS" else "FAIL"
lines.append(f"- `{item.name}`: **{mark}** — {item.details}")
lines.append("")
lines.append("## Next Action")
if ready:
lines.append("- Start/continue Phase A for Batch-1 (domain card + acceptance set + implementation backlog).")
else:
lines.append("- Fix failed items above before coding Batch-1 runtime intents.")
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
def main() -> int:
parser = argparse.ArgumentParser(description="Check readiness for Step-4 Wave-1 Batch-1.")
parser.add_argument(
"--out",
default=str(
REPO_ROOT
/ "docs"
/ "ADDRESS"
/ "address_query"
/ "wave1_batch1_readiness_report_2026-04-02.md"
),
)
args = parser.parse_args()
path_global = REPO_ROOT / "docs" / "ADDRESS" / "address_query" / "global_execution_checklist_v1.md"
path_step0 = REPO_ROOT / "docs" / "ADDRESS" / "address_query" / "step0_closeout_2026-04-02.md"
path_plan = REPO_ROOT / "docs" / "ADDRESS" / "address_query" / "domain_expansion_implementation_plan_v1.md"
path_general = REPO_ROOT / "docs" / "ADDRESS" / "address_query" / "general_domain_questions_analysis_plan_v1_2026-04-02.md"
path_probe = REPO_ROOT / "docs" / "ADDRESS" / "address_query" / "management_route_probe_report_g1_2026-04-02.md"
path_complex = REPO_ROOT / "docs" / "ADDRESS" / "address_query" / "complex_questions_status_and_reuse_map_2026-04-02.md"
path_stress = (
REPO_ROOT
/ "docs"
/ "ADDRESS"
/ "runs"
/ "2026-04-02_Address_Slang_Live_Stress_2026-04-02_12-57-27"
/ "run_summary.json"
)
path_followup = (
REPO_ROOT
/ "docs"
/ "ADDRESS"
/ "runs"
/ "2026-04-02_Address_Followup_Context_Chains_2026-04-02_19-15-Run5"
/ "run_summary.json"
)
path_nightly = (
REPO_ROOT
/ "docs"
/ "ADDRESS"
/ "runs"
/ "2026-04-02_Address_Nightly_Regression_2026-04-02_17-35-00"
/ "nightly_summary.json"
)
checks = [
check_file_exists(path_global, "master_checklist_exists"),
check_file_exists(path_step0, "step0_closeout_exists"),
check_file_exists(path_plan, "step4_plan_exists"),
check_file_exists(path_general, "general_domain_analysis_exists"),
check_file_exists(path_probe, "group1_probe_report_exists"),
check_file_exists(path_complex, "complex_status_map_exists"),
check_stress_baseline(path_stress),
check_followup_baseline(path_followup),
check_nightly(path_nightly),
]
ready = compute_ready(checks)
out_path = Path(args.out)
write_report(out_path, checks, ready)
print(f"[ok] readiness_report={out_path}")
print(f"[ok] decision={'READY_FOR_PHASE_A' if ready else 'NOT_READY'}")
return 0
if __name__ == "__main__":
raise SystemExit(main())