#!/usr/bin/env python3 """Create a private, read-only preflight report for the tjwater_v2 burst suite.""" from __future__ import annotations import argparse import asyncio import json import os import sys import traceback from datetime import datetime, timezone from pathlib import Path from uuid import uuid4 def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "--suite", type=Path, default=Path("resources/benchmarks/tjwater-v2-burst.json"), help="versioned burst suite manifest", ) parser.add_argument("--case", action="append", default=[], help="case ID to inspect; repeatable") parser.add_argument( "--output-root", type=Path, default=Path("data/benchmark/preflight"), help="private local artifact directory (default: ignored data/benchmark/preflight)", ) args = parser.parse_args() sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from scripts.benchmark.contracts import fingerprint, load_suite from scripts.benchmark.source import inspect_case, read_model, resolve_sources, source_identity, readonly_source try: suite = load_suite(args.suite) cases = suite.select(args.case) identity, routes = asyncio.run(resolve_sources(suite)) with readonly_source(routes["biz_data"]) as biz_connection: biz_source = source_identity(biz_connection, routes["biz_data"]) model = read_model(biz_connection, cases) with readonly_source(routes["iot_data"]) as iot_connection: iot_source = source_identity(iot_connection, routes["iot_data"]) case_results = [inspect_case(iot_connection, suite, case, model) for case in cases] content_fingerprint = fingerprint({ "suite": suite.model_dump(mode="json"), "source_routes": { "biz_data": biz_source["route_sha256"], "iot_data": iot_source["route_sha256"], }, "model": model, "cases": [{ "case_id": result["case_id"], "window_sha256": result["window_sha256"], "topology_reference": result["topology_reference"], "data_candidate_available": result["data_candidate_available"], "blockers": result["blockers"], } for result in case_results], }) report = { "report_version": "burst-preflight@1", "status": "preflight_complete", "readiness": "preflight_only; isolated runtime and Agent execution are not verified", "created_at": datetime.now(timezone.utc), "project": identity, "sources": {"biz_data": biz_source, "iot_data": iot_source}, "suite_id": suite.suite_id, "suite_version": suite.version, "content_fingerprint_sha256": content_fingerprint, "source_effect": "read-only transactions; no source database writes requested", "cases": case_results, "limitations": [ "preflight does not execute Agent, work-order, SCADA replay worker, or MCP tools", "SCADA event data requiring generation remains blocked until produced in an isolated dataset", "this report is not a frozen evaluation database snapshot", "numeric reference outputs and approved equivalent candidate groups still require review", ], } stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ") output_dir = args.output_root / f"{suite.suite_id}-{stamp}-{uuid4().hex[:8]}" output_dir.mkdir(parents=True, mode=0o700) os.chmod(output_dir, 0o700) output_file = output_dir / "preflight.json" output_file.write_text( json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True, default=str) + "\n", encoding="utf-8", ) os.chmod(output_file, 0o600) except Exception as exc: # Driver exceptions can include connection details; never echo them into CI logs. frames = traceback.extract_tb(exc.__traceback__) location = frames[-1] if frames else None suffix = f" at {location.filename}:{location.lineno}" if location else "" print(f"benchmark preflight failed ({type(exc).__name__}){suffix}", file=sys.stderr) return 1 work_order_candidates = sum(bool(case["variants"][0]["data_candidate_available"]) for case in case_results) scada_candidates = sum(bool(case["variants"][1]["data_candidate_available"]) for case in case_results) print( f"preflight complete: {work_order_candidates}/{len(case_results)} WO and " f"{scada_candidates}/{len(case_results)} SCADA data candidates; report: {output_file}" ) return 0 if __name__ == "__main__": raise SystemExit(main())