#!/usr/bin/env python3 """Validate the child-local Cortex OS CTO workspace.""" from __future__ import annotations import json import re 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", "sot/03-PROTOCOLS/CTO-CASE-STAGED-PROOF-GATES.md", "sot/03-PROTOCOLS/CTO-CASE-STAGE1-GATED-ENGINE-PRD.md", "sot/03-PROTOCOLS/CTO-CASE-STAGE1-GATED-ENGINE-ISSUES.md", "sot/03-PROTOCOLS/CTO-CASE-STAGE2-ARTIFICIAL-FIXTURE-PRD.md", "sot/03-PROTOCOLS/CTO-CASE-STAGE2-ARTIFICIAL-FIXTURE-ISSUES.md", "sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-PRD.md", "sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-ISSUES.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", ] REQUIRED_STAGED_PROOF_PHRASES = [ "Local planning SOT only. Not a Core Protocol. Not active Core authority.", "Default status is earned, not assumed.", "Stages must be completed in order.", "Missing evidence means blocked, not partially accepted.", "Stage 1 - Gated Case Engine", "Stage 2 - Artificial Fixture", "Stage 3 - Copied Repo Fixture", "Stage 4 - Disposable Sandbox Repo", "Stage 5 - Owned Noncritical Repo", "Stage 6 - Candidate Default", "Allowed mutation scope: none.", "Allowed mutation scope: copied artificial case only.", "Allowed mutation scope: copied local repository fixture only.", "Allowed mutation scope: disposable repository only.", "Allowed mutation scope: explicitly owned low-risk repository only.", "Allowed mutation scope: scoped real-repo use only.", "fake, Codex, and Pi where applicable", "Case matches or beats existing lanes on report shape", "Case matches or beats existing lanes on failure closure", "Any future implementation must start with Stage 1", "must not skip to real-repo execution", ] REQUIRED_STAGE1_PRD_PHRASES = [ "Local planning SOT only. Not a Core Protocol. Not active Core authority.", "Stage 1 must prove only the smallest safe executable behavior", "no-op gated `case` backend path", "It does not run Case", "Stage 1 keeps allowed mutation scope as `none`.", "`case` is disabled by default.", "Missing gate produces blocked status, not warning.", "CTO_HARNESS_ALLOW_CASE=1", "backend.gate.blocked", "case_process_started: false", "source_admission_status: not_admitted", "backend/case-gate.log", "Stage 1 gate runs before case workspace copy", "No files under harness source checkout, target repo, Case source, vendor source, or Cortex Core are changed by the Stage 1 run.", "fake remains the default validation lane", "/home/svrnty/workspaces/hermes/cto/harness", "Stage 1 does not make Case executable", ] REQUIRED_STAGE1_ISSUE_IDS = [ "CTO-WORK-009", "CTO-WORK-010", ] REQUIRED_STAGE2_PRD_PHRASES = [ "Local planning SOT only. Not a Core Protocol. Not active Core authority.", "Stage 2 must prove only one narrow executable behavior", "copied artificial fixture", "Stage 2 allowed mutation scope is `copied artificial case only`.", "CTO_HARNESS_ALLOW_CASE=1", "CTO_HARNESS_CASE_STAGE=2", "Missing Stage 2 gate means blocked, not warning.", "runtime_workspace_root", "run_artifact_dir", "Fake remains the default validation lane.", "No Target Repository path is inspected or copied.", "task contract contains no Target Repository path", "source_admission_status: not_admitted", "allowed_writes_passed", "report.md", "backend raw logs under `backend/`", "backend: case", "case_process_started", "changed_files", "blockers", "artifact digests", "freshness proof", "same-run fake baseline", "no diff", "disallowed file", "failed tests", "missing test command", "missing required event", "provider unavailable", "python3 harness/runner/validate-case-stage2.py --harness-root harness --json", "python3 harness/runner/validate-case-stage1.py --harness-root harness --json", "Stage 2 does not authorize copied repo, sandbox repo, owned repo, default backend, WebUI product, or Core promotion behavior.", ] REQUIRED_STAGE2_ISSUE_IDS = [ "CTO-WORK-011", "CTO-WORK-012", ] REQUIRED_PROVIDER_ADMISSION_PRD_PHRASES = [ "Local planning SOT only. Not a Core Protocol. Not active Core authority.", "https://github.com/workos/case.git", "7959ac917cdeb0983b4aaa20bb9f42021747fed8", "Package status: `private: true`.", "Public npm package `case` is not WorkOS Case.", "Case CLI binary name is `ca`", "Case setup requires Bun.", "bun run build:binary", "dist/ca", "ca run --task ", "ca session --task ", "CTO_HARNESS_CASE_BIN", "WorkOS Case expects a task file and a Case command shape, not an arbitrary prompt string.", "The provider path must be explicit and durable", "The adapter must not pass the task brief as a raw positional prompt.", "The task file must contain no Target Repository path for Stage 2.", "Missing Bun, missing `dist/ca`, wrong commit, wrong command shape, or wrong task file means blocked.", "Case may execute only inside the Harness Evidence Interface.", "Case may recommend. Case must not approve itself.", "Stage 2 pass report exists only after a real `ca run --task ` execution.", "Fake remains the default validation lane.", "Do not install or use the unrelated npm `case` package.", "Do not treat Case as CTO authority.", ] REQUIRED_PROVIDER_ADMISSION_ISSUE_IDS = [ "CTO-WORK-013", "CTO-WORK-014", ] def workboard_status(text: str, issue_id: str) -> str | None: pattern = rf"- id: {re.escape(issue_id)}\n(?: .+\n)*? status: ([^\n]+)" match = re.search(pattern, text) return match.group(1).strip() if match else None 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}") staged_proof = ROOT / "sot/03-PROTOCOLS/CTO-CASE-STAGED-PROOF-GATES.md" if staged_proof.is_file(): text = staged_proof.read_text(encoding="utf-8") if "core_promotion_status: not-promoted" not in text: errors.append("staged_proof_missing_not_promoted_frontmatter") for phrase in REQUIRED_STAGED_PROOF_PHRASES: checked.append(f"staged_proof_phrase:{phrase}") if phrase not in text: errors.append(f"missing_staged_proof_phrase:{phrase}") stage1_prd = ROOT / "sot/03-PROTOCOLS/CTO-CASE-STAGE1-GATED-ENGINE-PRD.md" if stage1_prd.is_file(): text = stage1_prd.read_text(encoding="utf-8") if "core_promotion_status: not-promoted" not in text: errors.append("stage1_prd_missing_not_promoted_frontmatter") for phrase in REQUIRED_STAGE1_PRD_PHRASES: checked.append(f"stage1_prd_phrase:{phrase}") if phrase not in text: errors.append(f"missing_stage1_prd_phrase:{phrase}") stage1_issues = ROOT / "sot/03-PROTOCOLS/CTO-CASE-STAGE1-GATED-ENGINE-ISSUES.md" if stage1_issues.is_file(): text = stage1_issues.read_text(encoding="utf-8") if "core_promotion_status: not-promoted" not in text: errors.append("stage1_issues_missing_not_promoted_frontmatter") if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text: errors.append("stage1_issues_missing_local_planning_notice") for issue_id in REQUIRED_STAGE1_ISSUE_IDS: checked.append(f"stage1_issue_id:{issue_id}") if issue_id not in text: errors.append(f"missing_stage1_issue_id:{issue_id}") stage2_prd = ROOT / "sot/03-PROTOCOLS/CTO-CASE-STAGE2-ARTIFICIAL-FIXTURE-PRD.md" if stage2_prd.is_file(): text = stage2_prd.read_text(encoding="utf-8") if "core_promotion_status: not-promoted" not in text: errors.append("stage2_prd_missing_not_promoted_frontmatter") for phrase in REQUIRED_STAGE2_PRD_PHRASES: checked.append(f"stage2_prd_phrase:{phrase}") if phrase not in text: errors.append(f"missing_stage2_prd_phrase:{phrase}") stage2_issues = ROOT / "sot/03-PROTOCOLS/CTO-CASE-STAGE2-ARTIFICIAL-FIXTURE-ISSUES.md" if stage2_issues.is_file(): text = stage2_issues.read_text(encoding="utf-8") if "core_promotion_status: not-promoted" not in text: errors.append("stage2_issues_missing_not_promoted_frontmatter") if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text: errors.append("stage2_issues_missing_local_planning_notice") for issue_id in REQUIRED_STAGE2_ISSUE_IDS: checked.append(f"stage2_issue_id:{issue_id}") if issue_id not in text: errors.append(f"missing_stage2_issue_id:{issue_id}") provider_admission_prd = ROOT / "sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-PRD.md" if provider_admission_prd.is_file(): text = provider_admission_prd.read_text(encoding="utf-8") if "core_promotion_status: not-promoted" not in text: errors.append("provider_admission_prd_missing_not_promoted_frontmatter") for phrase in REQUIRED_PROVIDER_ADMISSION_PRD_PHRASES: checked.append(f"provider_admission_prd_phrase:{phrase}") if phrase not in text: errors.append(f"missing_provider_admission_prd_phrase:{phrase}") provider_admission_issues = ROOT / "sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-ISSUES.md" if provider_admission_issues.is_file(): text = provider_admission_issues.read_text(encoding="utf-8") if "core_promotion_status: not-promoted" not in text: errors.append("provider_admission_issues_missing_not_promoted_frontmatter") if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text: errors.append("provider_admission_issues_missing_local_planning_notice") for issue_id in REQUIRED_PROVIDER_ADMISSION_ISSUE_IDS: checked.append(f"provider_admission_issue_id:{issue_id}") if issue_id not in text: errors.append(f"missing_provider_admission_issue_id:{issue_id}") 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}") for issue_id in REQUIRED_STAGE1_ISSUE_IDS: checked.append(f"workboard_id:{issue_id}") if issue_id not in text: errors.append(f"missing_workboard_id:{issue_id}") for issue_id in REQUIRED_STAGE2_ISSUE_IDS: checked.append(f"workboard_id:{issue_id}") if issue_id not in text: errors.append(f"missing_workboard_id:{issue_id}") for issue_id in REQUIRED_PROVIDER_ADMISSION_ISSUE_IDS: checked.append(f"workboard_id:{issue_id}") if issue_id not in text: errors.append(f"missing_workboard_id:{issue_id}") expected_statuses = { "CTO-WORK-002": "validated", "CTO-WORK-003": "validated", "CTO-WORK-004": "validated", "CTO-WORK-005": "validated", "CTO-WORK-006": "validated", "CTO-WORK-007": "validated", "CTO-WORK-008": "validated", "CTO-WORK-009": "validated", "CTO-WORK-010": "validated", "CTO-WORK-011": "validated", "CTO-WORK-012": "blocked", "CTO-WORK-013": "validated", "CTO-WORK-014": "validated", } for issue_id, expected in expected_statuses.items(): checked.append(f"workboard_status:{issue_id}:{expected}") actual = workboard_status(text, issue_id) if actual != expected: errors.append(f"workboard_status_mismatch:{issue_id}:expected_{expected}:actual_{actual}") 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") if "CTO-CASE-STAGED-PROOF-GATES.md" not in text: errors.append("workboard_missing_staged_proof_gates_source") if "CTO-CASE-STAGE1-GATED-ENGINE-PRD.md" not in text: errors.append("workboard_missing_stage1_prd_source") if "CTO-CASE-STAGE1-GATED-ENGINE-ISSUES.md" not in text: errors.append("workboard_missing_stage1_issues_source") if "CTO-CASE-STAGE2-ARTIFICIAL-FIXTURE-PRD.md" not in text: errors.append("workboard_missing_stage2_prd_source") if "CTO-CASE-STAGE2-ARTIFICIAL-FIXTURE-ISSUES.md" not in text: errors.append("workboard_missing_stage2_issues_source") if "CTO-CASE-PROVIDER-ADMISSION-PRD.md" not in text: errors.append("workboard_missing_provider_admission_prd_source") if "CTO-CASE-PROVIDER-ADMISSION-ISSUES.md" not in text: errors.append("workboard_missing_provider_admission_issues_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())