#!/usr/bin/env python3 """ check_sentinel_contract_parity.py Ensures Sentinel v1 contracts (docs) and verifier implementation stay aligned: - Every FailureCode is referenced by the verifier implementation. - Every FailureCode is referenced by the contract matrix. - The contract matrix does not reference unknown E_/W_ codes. Usage: python3 tools/check_sentinel_contract_parity.py """ from __future__ import annotations import re import sys from pathlib import Path from sentinel_failure_codes import FailureCode, WarningCode REPO_ROOT = Path(__file__).resolve().parents[1] VERIFIER_PATH = REPO_ROOT / "tools" / "vm_verify_sentinel_bundle.py" CONTRACT_MATRIX_PATH = REPO_ROOT / "spec" / "SENTINEL_V1_CONTRACT_MATRIX.md" SEMANTICS_PATH = REPO_ROOT / "spec" / "SENTINEL_FAILURE_CODE_SEMANTICS.md" def _read_text(path: Path) -> str: return path.read_text(encoding="utf-8") def main() -> int: errors: list[str] = [] verifier = _read_text(VERIFIER_PATH) matrix = _read_text(CONTRACT_MATRIX_PATH) semantics = _read_text(SEMANTICS_PATH) known_failure_values = {c.value for c in FailureCode} known_warning_values = {c.value for c in WarningCode} # 1) Every FailureCode is referenced by the verifier code. for code in FailureCode: needle = f"FailureCode.{code.name}" if needle not in verifier: errors.append(f"Verifier does not reference {needle} ({code.value})") # 1b) Every WarningCode is referenced by the verifier code. for code in WarningCode: needle = f"WarningCode.{code.name}" if needle not in verifier: errors.append(f"Verifier does not reference {needle} ({code.value})") # 2) Every FailureCode value appears in the contract matrix. for code in FailureCode: if code.value not in matrix: errors.append( f"Contract matrix does not reference failure code {code.value}" ) # 2b) Every WarningCode value appears in the contract matrix. for code in WarningCode: if code.value not in matrix: errors.append( f"Contract matrix does not reference warning code {code.value}" ) # 3) Contract matrix does not contain unknown E_/W_ codes. referenced_failures = set(re.findall(r"\bE_[A-Z_]+\b", matrix)) referenced_warnings = set(re.findall(r"\bW_[A-Z_]+\b", matrix)) unknown_failures = sorted(referenced_failures - known_failure_values) unknown_warnings = sorted(referenced_warnings - known_warning_values) if unknown_failures: errors.append( "Contract matrix references unknown failure codes: " + ", ".join(unknown_failures) ) if unknown_warnings: errors.append( "Contract matrix references unknown warning codes: " + ", ".join(unknown_warnings) ) # 4) Semantics doc must cover all codes. for code in FailureCode: if code.value not in semantics: errors.append(f"Failure code semantics doc does not reference {code.value}") for code in WarningCode: if code.value not in semantics: errors.append(f"Warning code semantics doc does not reference {code.value}") # 5) Semantics doc does not contain unknown E_/W_ codes. referenced_failures = set(re.findall(r"\bE_[A-Z_]+\b", semantics)) referenced_warnings = set(re.findall(r"\bW_[A-Z_]+\b", semantics)) unknown_failures = sorted(referenced_failures - known_failure_values) unknown_warnings = sorted(referenced_warnings - known_warning_values) if unknown_failures: errors.append( "Failure code semantics doc references unknown failure codes: " + ", ".join(unknown_failures) ) if unknown_warnings: errors.append( "Failure code semantics doc references unknown warning codes: " + ", ".join(unknown_warnings) ) if errors: for e in errors: print(f"[FAIL] {e}", file=sys.stderr) return 1 print("[OK] Sentinel contract parity verified") return 0 if __name__ == "__main__": raise SystemExit(main())