cto/tools/validate_cto_child.py
2026-05-31 18:53:12 -04:00

278 lines
10 KiB
Python

#!/usr/bin/env python3
"""Validate the child-local Cortex OS CTO workspace."""
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
REQUIRED_FILES = [
"AGENTS.md",
"README.md",
"WORKBOARD.yaml",
"CONTEXT.md",
"sot/00-START/CTO-WORKSPACE-INTENT.md",
"sot/03-PROTOCOLS/CTO-CASE-BACKEND-BRIEF.md",
"sot/03-PROTOCOLS/CTO-CASE-CANDIDATE-BACKEND-PRD.md",
"sot/03-PROTOCOLS/CTO-CASE-CANDIDATE-BACKEND-ISSUES.md",
"sot/03-PROTOCOLS/CTO-HARNESS-EVIDENCE-INTERFACE-CONTRACT.md",
"sot/03-PROTOCOLS/CTO-CASE-SOURCE-ADMISSION-RECORD.md",
"sot/03-PROTOCOLS/CTO-CASE-ADAPTER-CONTRACT.md",
"sot/03-PROTOCOLS/CTO-CASE-FAILURE-FIXTURE-MATRIX.md",
]
REQUIRED_BRIEF_PHRASES = [
"Cortex governs.",
"Hermes controls.",
"Case executes.",
"Harness proves.",
"Core promotes only through SOT route.",
"Case is the candidate CTO execution backend, not the CTO authority layer.",
"This brief is child-local planning.",
]
REQUIRED_PRD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"Case Candidate Backend",
"Harness Evidence Interface",
"Case may recommend; CTO Harness records; Hermes or operator approval is the only human approval signal.",
"Candidate Cortex Work Packet is an unpromoted term.",
"Staged Proof Gates",
"Source Admission Requirements",
"Failure-Mode Matrix",
"Fake remains the default validation lane.",
]
FORBIDDEN_PRD_PHRASES = [
"Case should be the default real-repo execution backend",
"Case is the default real-repo execution backend",
]
REQUIRED_ISSUE_IDS = [
"CTO-WORK-003",
"CTO-WORK-004",
"CTO-WORK-005",
"CTO-WORK-006",
"CTO-WORK-007",
"CTO-WORK-008",
]
REQUIRED_EVIDENCE_INTERFACE_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"This contract does not authorize Runtime behavior",
"The Harness Evidence Interface is the only accepted proof surface for backend comparison.",
"report.json",
"events.normalized.jsonl",
"patch.diff",
"test.log",
"trace.jsonl",
"artifact_digests",
"SHA-256",
"run_started_at",
"run_finished_at",
"backend_exit_code",
"allowed_writes_passed",
"approval.requested",
"approval.granted",
"approval.denied",
"Case may recommend. Case must not approve itself.",
"No merge, push, deploy, close, or real-repo mutation is allowed without explicit task-contract permission.",
"fail closed",
]
REQUIRED_SOURCE_ADMISSION_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"This record does not authorize Runtime behavior",
"https://github.com/workos/case.git",
"7959ac917cdeb0983b4aaa20bb9f42021747fed8",
"2026-05-31",
"git clone --depth 1 https://github.com/workos/case.git",
"License status is unresolved.",
"package private: true",
"Status: not admitted for execution.",
"Current allowed execution mode: planning-only.",
"do not mutate the Case repository",
"do not vendor Case source into Cortex OS Core",
"No moving branch reference may be used as proof without a pinned commit or tag.",
]
REQUIRED_ADAPTER_CONTRACT_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"This contract does not authorize Runtime behavior",
"register backend id `case` as a gated engine before execution",
"require the harness to accept `--engine case` only when explicitly enabled",
"prevent a parallel runner path outside the existing harness seam",
"`case` must be disabled by default.",
"No missing gate may degrade to a warning. Missing gate means blocked.",
"Adapter Input Contract",
"Adapter Output Contract",
"CTO Eligibility Decision",
"`selected_backend`",
"`denied_backends`",
"`required_gates`",
"`missing_gates`",
"`allowed_mutation_mode`",
"Case must not create or override the Eligibility Decision.",
"Case may recommend. Case must not approve itself or select its own authority.",
"This contract deliberately does not create `case-engine.sh`.",
]
REQUIRED_FAILURE_FIXTURE_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"This matrix does not authorize Runtime behavior",
"This matrix is planning-only and does not run Case.",
"no-diff",
"disallowed-file",
"failed-tests",
"missing-test-command",
"missing-event",
"reviewer-reject",
"approval-denied",
"timeout",
"dirty-starting-tree",
"dirty-ending-tree",
"artifact-write-failure",
"provider-unavailable",
"`no_diff`",
"`disallowed_file_change`",
"`verification_failed`",
"`missing_test_command`",
"`missing_required_event`",
"`reviewer_rejected`",
"`approval_denied`",
"`dirty_starting_tree`",
"`dirty_ending_tree`",
"`artifact_write_failure`",
"`provider_unavailable`",
"report.json",
"events.normalized.jsonl",
"patch.diff",
"test.log",
"trace.jsonl",
"artifact_digests",
"freshness proof",
"fail closed",
]
def main() -> int:
checked: list[str] = []
errors: list[str] = []
for rel in REQUIRED_FILES:
path = ROOT / rel
checked.append(rel)
if not path.is_file():
errors.append(f"missing_required_file:{rel}")
brief = ROOT / "sot/03-PROTOCOLS/CTO-CASE-BACKEND-BRIEF.md"
if brief.is_file():
text = brief.read_text(encoding="utf-8")
for phrase in REQUIRED_BRIEF_PHRASES:
checked.append(f"brief_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_brief_phrase:{phrase}")
if "core_promotion_status: not-promoted" not in text:
errors.append("brief_missing_not_promoted_frontmatter")
prd = ROOT / "sot/03-PROTOCOLS/CTO-CASE-CANDIDATE-BACKEND-PRD.md"
if prd.is_file():
text = prd.read_text(encoding="utf-8")
for phrase in REQUIRED_PRD_PHRASES:
checked.append(f"prd_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_prd_phrase:{phrase}")
for phrase in FORBIDDEN_PRD_PHRASES:
checked.append(f"prd_forbidden_phrase:{phrase}")
if phrase in text:
errors.append(f"forbidden_prd_phrase:{phrase}")
if "core_promotion_status: not-promoted" not in text:
errors.append("prd_missing_not_promoted_frontmatter")
issues = ROOT / "sot/03-PROTOCOLS/CTO-CASE-CANDIDATE-BACKEND-ISSUES.md"
if issues.is_file():
text = issues.read_text(encoding="utf-8")
if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text:
errors.append("issues_missing_local_planning_notice")
if "core_promotion_status: not-promoted" not in text:
errors.append("issues_missing_not_promoted_frontmatter")
for issue_id in REQUIRED_ISSUE_IDS:
checked.append(f"issue_id:{issue_id}")
if issue_id not in text:
errors.append(f"missing_issue_id:{issue_id}")
evidence_interface = ROOT / "sot/03-PROTOCOLS/CTO-HARNESS-EVIDENCE-INTERFACE-CONTRACT.md"
if evidence_interface.is_file():
text = evidence_interface.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("evidence_interface_missing_not_promoted_frontmatter")
for phrase in REQUIRED_EVIDENCE_INTERFACE_PHRASES:
checked.append(f"evidence_interface_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_evidence_interface_phrase:{phrase}")
source_admission = ROOT / "sot/03-PROTOCOLS/CTO-CASE-SOURCE-ADMISSION-RECORD.md"
if source_admission.is_file():
text = source_admission.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("source_admission_missing_not_promoted_frontmatter")
for phrase in REQUIRED_SOURCE_ADMISSION_PHRASES:
checked.append(f"source_admission_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_source_admission_phrase:{phrase}")
adapter_contract = ROOT / "sot/03-PROTOCOLS/CTO-CASE-ADAPTER-CONTRACT.md"
if adapter_contract.is_file():
text = adapter_contract.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("adapter_contract_missing_not_promoted_frontmatter")
for phrase in REQUIRED_ADAPTER_CONTRACT_PHRASES:
checked.append(f"adapter_contract_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_adapter_contract_phrase:{phrase}")
failure_matrix = ROOT / "sot/03-PROTOCOLS/CTO-CASE-FAILURE-FIXTURE-MATRIX.md"
if failure_matrix.is_file():
text = failure_matrix.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("failure_matrix_missing_not_promoted_frontmatter")
for phrase in REQUIRED_FAILURE_FIXTURE_PHRASES:
checked.append(f"failure_matrix_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_failure_matrix_phrase:{phrase}")
board = ROOT / "WORKBOARD.yaml"
if board.is_file():
text = board.read_text(encoding="utf-8")
for issue_id in ["CTO-WORK-002", *REQUIRED_ISSUE_IDS]:
checked.append(f"workboard_id:{issue_id}")
if issue_id not in text:
errors.append(f"missing_workboard_id:{issue_id}")
if "CTO-HARNESS-EVIDENCE-INTERFACE-CONTRACT.md" not in text:
errors.append("workboard_missing_evidence_interface_contract_source")
if "CTO-WORK-004" in text and "status: validated" not in text:
errors.append("workboard_cto_work_004_not_validated")
if "CTO-CASE-SOURCE-ADMISSION-RECORD.md" not in text:
errors.append("workboard_missing_source_admission_record_source")
if "CTO-CASE-ADAPTER-CONTRACT.md" not in text:
errors.append("workboard_missing_adapter_contract_source")
if "CTO-CASE-FAILURE-FIXTURE-MATRIX.md" not in text:
errors.append("workboard_missing_failure_matrix_source")
payload = {
"ok": not errors,
"validator": "cto-child-v1",
"checked": checked,
"errors": errors,
"warnings": [],
}
print(json.dumps(payload, indent=2, sort_keys=True))
return 0 if not errors else 1
if __name__ == "__main__":
raise SystemExit(main())