#!/usr/bin/env python3 """Validate only the active task's context metadata and focused pointer. The normal path compares stat metadata first. The task-context checker is invoked only when an input is missing, changed, or lacks the required hash. """ from __future__ import annotations import argparse import json import subprocess from pathlib import Path from wbv2_runtime import ROOT, queue_pointer def stat_metadata(path: Path) -> tuple[int, str] | None: try: value = path.stat() except OSError: return None return value.st_size, str(value.st_mtime_ns) def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--task", help="task id; defaults to the authoritative queue pointer") args = parser.parse_args() task = args.task or queue_pointer().get("task") if not task: parser.error("queue has no current task") context_path = ROOT / "tests/golden" / task / "task-context.json" try: context = json.loads(context_path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError): context = {} metadata = context.get("inputMetadata") if isinstance(context, dict) else None unchanged = isinstance(metadata, dict) and bool(metadata) if unchanged: for relative, expected in metadata.items(): current = stat_metadata(ROOT / relative) if ( not isinstance(expected, dict) or current is None or current[0] != expected.get("bytes") or current[1] != expected.get("mtime_ns") or not isinstance(expected.get("sha256"), str) ): unchanged = False break if unchanged: print(f"incremental-context-ok task={task} context=REUSED metadata={len(metadata)}") return 0 command = ["node", "tools/web/check-task-context.mjs", "--task", task, "--write"] result = subprocess.run(command, cwd=ROOT, text=True, capture_output=True, check=False) output = result.stdout or result.stderr if output: print(output, end="" if output.endswith("\n") else "\n") if result.returncode: return result.returncode print(f"incremental-context-ok task={task} context=REFRESHED") return 0 if __name__ == "__main__": raise SystemExit(main())