"""Run the opt-in CH1 driver/body-CAN front-end HIL suite.""" from __future__ import annotations import argparse import json import os import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SRC = ROOT / "src" SEAT_SRC = ROOT / "domains" / "seat" / "src" for source in (SRC, SEAT_SRC): if str(source) not in sys.path: sys.path.insert(0, str(source)) from cognitive_agent.config_loader import load_local_env # noqa: E402 from cognitive_agent.infrastructure.can.hardware import VehicleCanSettings # noqa: E402 from cognitive_agent.testing.ch1_hil import ( # noqa: E402 Ch1HilRunner, JsonApiClient, load_suite, observe_stationary_ch1, require_explicit_hil_arm, suite_cases, suite_rejections, validate_ui_contract, ) DEFAULT_SUITE = ROOT / "tests" / "fixtures" / "ch1_vehicle_frontend_hil_suite.json" DEFAULT_OUTPUT = ROOT / "artifacts" / "hil" / "ch1_vehicle_frontend_hil_latest.json" def passive_reader(token: str | None): """Build one fresh observer that opens CH1 only and never transmits.""" settings = VehicleCanSettings.from_env(ROOT) settings.authorize(token) if settings.channel != 1 or settings.required_channel != 1: raise RuntimeError("passive preflight refused a non-CH1 channel") def read() -> dict: bridge = settings.bridge([settings.channel_config()]) try: bus = bridge.channel_bus(1) return observe_stationary_ch1(bus, timeout_seconds=5.0) finally: bridge.close() return read def offline_validate(suite_path: Path) -> int: suite = load_suite(suite_path) validate_ui_contract( "self_orchestration", (ROOT / "apps" / "web-console" / "app.js").read_text(encoding="utf-8"), ) validate_ui_contract( "self_extension", (ROOT / "apps" / "web-console" / "self-extension.js").read_text( encoding="utf-8" ), ) counts = { module: { "total": len(suite_cases(suite, module)), "physical": sum( item.get("hil", True) for item in suite_cases(suite, module) ), "contract_only": sum( not item.get("hil", True) for item in suite_cases(suite, module) ), "offline_rejections": len(suite_rejections(suite, module)), } for module in ("self_orchestration", "self_extension") } print(json.dumps({"status": "validated_offline", "cases": counts}, ensure_ascii=False)) return 0 def main() -> int: parser = argparse.ArgumentParser( description="CH1-only driver/body-CAN front-end HIL verification" ) parser.add_argument("--suite", type=Path, default=DEFAULT_SUITE) parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT) parser.add_argument("--base-url", default="http://127.0.0.1:8000") parser.add_argument("--offline-validate", action="store_true") parser.add_argument( "--confirm", default="", help="Live mode requires the exact text CH1_DRIVER_ONLY.", ) args = parser.parse_args() if args.offline_validate: return offline_validate(args.suite) # Loading the repository launch environment does not arm HIL by itself; # the dedicated environment and exact CLI confirmation are both mandatory. load_local_env(ROOT / ".env", override=True) require_explicit_hil_arm(os.environ, confirmation=args.confirm) suite = load_suite(args.suite) token = os.getenv("COGNITIVE_AGENT_HARDWARE_APPROVAL_TOKEN") or None client_id = os.getenv("COGNITIVE_AGENT_CH1_HIL_CLIENT_ID") or None cookie = os.getenv("COGNITIVE_AGENT_CH1_HIL_COOKIE") or None api = JsonApiClient(args.base_url, cookie=cookie) reader = passive_reader(token) runner = Ch1HilRunner( suite, api, reader, confirmation=args.confirm, approval_token=token, hardware_client_id=client_id, ) report = runner.run() args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text( json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", ) print(json.dumps(report["summary"], ensure_ascii=False)) print(str(args.output.resolve())) return 0 if report["summary"]["failed"] == 0 else 1 if __name__ == "__main__": raise SystemExit(main())