cto/tools/validate_cto_child.py
2026-05-31 23:09:33 -04:00

1235 lines
63 KiB
Python

#!/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-STAGE3-COPIED-REPO-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-STAGE3-COPIED-REPO-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-BUILD-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-BUILD-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-DECISION-PACKET-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-DECISION-PACKET-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-DECISION-RECORD.md",
".sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION.openai-codex-gpt-5.5.json",
".sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION.qwen-local-qwen3.6-35b-a3b.json",
".sot/03-PROTOCOLS/CTO-CASE-SPARK-ENDPOINT-CONFIG-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-SPARK-ENDPOINT-CONFIG-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-AGENT-PROTOCOL-BLOCKER.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_STAGE3_PRD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"Stage 3 must prove the next narrow behavior",
"copied local repository fixture only",
"CTO_HARNESS_ALLOW_CASE=1",
"CTO_HARNESS_CASE_STAGE=3",
"Source repository HEAD and status are recorded before and after Case execution.",
"Source repository after-proof matches before-proof.",
"Copied fixture starts clean",
"Copied fixture ends clean",
"source_repository_mutated: false",
"dirty-starting-tree",
"dirty-ending-tree",
"artifact-write-failure",
"Stage 3 does not authorize sandbox, owned-repo, default backend, WebUI Runtime, or Core promotion behavior.",
]
REQUIRED_STAGE3_ISSUE_IDS = [
"CTO-WORK-033",
"CTO-WORK-034",
]
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 <task-file>",
"ca session <repo-path> --task <task-file>",
"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 <task-file>` 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",
]
REQUIRED_PROVIDER_BUILD_PRD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"no durable admitted `ca` executable exists",
"Node `v20.19.5`, no local `bun` executable",
"no `dist/ca`, no PATH `ca`",
"https://github.com/workos/case.git",
"7959ac917cdeb0983b4aaa20bb9f42021747fed8",
"discovery evidence only",
"durable WorkOS Case `ca` executable",
"source pin and SHA-256 digest",
"CTO_HARNESS_CASE_BIN",
"bun run build:binary",
"dist/ca",
"unrelated npm `case` package",
"ca run --task <task-file> --mode unattended",
"allowed paths, forbidden actions, verification command, and evidence expectations",
"Missing Bun blocks before build; it does not degrade to warning.",
"missing credentials",
"Stage 2 with `CTO_HARNESS_CASE_BIN=<admitted-ca>` produces a pass report only through real Case execution.",
"Current Hermes source admission status remains `not_admitted` until the provider build report is recorded.",
"Same-run fake baseline comparison remains required",
"report.json",
"report.md",
"events.normalized.jsonl",
"trace.jsonl",
"patch.diff",
"test.log",
"backend raw logs",
"artifact digests",
"freshness proof",
"source_admission_status",
"case_process_started",
"backend_exit_code",
"allowed_writes_passed",
"changed_files",
"blockers",
"No Cortex Core, Case source, vendor source, or Target Repository file is mutated by admission.",
"harness/evals/health.sh --json",
"Stage 2 moves from provider-unavailable blocked status to a real Case pass report",
"9811f870af2f85616e359d42ba70566c9af08ca20d8660456929a56ec761513f",
"20260531T233721Z-r1-string-slugify-1814067",
"CTO-WORK-016` remains blocked because no real Case Stage 2 pass report exists",
"CTO-WORK-017 - Case Provider Timeout Fail-Closed Route",
"CTO_HARNESS_CASE_TIMEOUT_SECONDS",
"backend/provider-timeout.txt",
"provider_timeout_fail_closed",
"d23c492 Fail closed on Case provider timeout",
"anthropic",
"claude-sonnet-4-6",
"20260531T234205Z-r1-string-slugify-1834617/report.json",
"CTO_HARNESS_CASE_MODEL_PROVIDER",
"CTO_HARNESS_CASE_MODEL",
"backend/provider-model-not-admitted.txt",
"model_provider_gate_blocks",
"4500082 Gate Case execution on admitted model",
]
REQUIRED_PROVIDER_BUILD_ISSUE_IDS = [
"CTO-WORK-015",
"CTO-WORK-016",
"CTO-WORK-017",
"CTO-WORK-018",
]
REQUIRED_MODEL_PROVIDER_ADMISSION_PRD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"CTO-WORK-018",
"anthropic",
"claude-sonnet-4-6",
"unadmitted external model path",
"explicit admitted provider/model pair",
"credential source class",
"allowed network class",
"admission timestamp",
"CTO_HARNESS_CASE_MODEL_PROVIDER",
"CTO_HARNESS_CASE_MODEL",
"backend/provider-model-not-admitted.txt",
"unadmitted provider/model blocks before `case_process_started`",
"models.default",
"CASE_DATA_DIR/config.json",
"ca run --task <task-file> --mode unattended",
"case_model_provider",
"case_model",
"case_model_admission_status",
"case_process_started",
"allowed_writes_passed",
"changed_files",
"blockers",
"Fake remains the default validation lane.",
"Same-run fake baseline comparison remains required.",
"No secrets appear in task file, argv, report, trace, backend logs, SOT, or commits.",
"4500082 Gate Case execution on admitted model",
"model_provider_gate_blocks",
"f39d8ab Require admitted Case model pair",
"CTO_HARNESS_CASE_MODEL_ADMISSION_FILE",
"Env provider/model is now a requested pair, not admission authority.",
"The admission JSON is the authority for real Case Stage 2 model admission.",
"admitted",
"missing_admission",
"mismatch",
"invalid_admission",
"not_admitted",
"report.md",
"Case stdout/stderr",
"20260531T235421Z-r1-string-slugify-1875638",
"20260531T235448Z-r1-string-slugify-1876884",
"`CTO-WORK-020` remains blocked because no real provider/model has been approved and no real Case Stage 2 pass report exists.",
"Decision Record Template For CTO-WORK-020",
"`decision_status`: `not_decided`, `external_provider_approved`, or `local_provider_required`.",
"`provider_class`: `external_anthropic`, `external_openai_codex`, or `local_case_compatible`.",
"`provider`: exact provider string, or empty while blocked.",
"`model`: exact model string, or empty while blocked.",
"`approval_source`: JP approval reference or governed Core route reference.",
"`credential_source_class`: credential class only; no secret value.",
"`allowed_network_class`: allowed network class for this provider.",
"`review_trigger`: expiry, date, or condition that forces review.",
"`evidence_sources`: references to existing admission/build evidence, not copied runtime evidence.",
"`effect`: `CTO-WORK-020 remains blocked until admitted provider/model and real Stage 2 pass report exist`.",
"`not_decided`: no provider/model may run.",
"`local_provider_required`: no external provider may run; create a Case-compatible local provider route first.",
"`external_provider_approved`: may proceed only when the approval source, credential source class, allowed network class, and admission JSON are recorded.",
]
REQUIRED_MODEL_PROVIDER_ADMISSION_ISSUE_IDS = [
"CTO-WORK-019",
"CTO-WORK-020",
"CTO-WORK-027",
"CTO-WORK-029",
]
REQUIRED_MODEL_PROVIDER_ADMISSION_ISSUE_PHRASES = [
"f39d8ab Require admitted Case model pair",
"`f39d8ab` proves admission gating implementation only; it is not a real Case Stage 2 pass.",
"CTO_HARNESS_CASE_MODEL_ADMISSION_FILE",
"admission JSON is the authority",
"Missing admission blocks before `case_process_started`.",
"Mismatched admission blocks before `case_process_started`.",
"case_model_provider",
"case_model",
"case_model_admission_status",
"admitted",
"missing_admission",
"mismatch",
"invalid_admission",
"not_admitted",
"report.md",
"Case stdout/stderr",
"20260531T235421Z-r1-string-slugify-1875638",
"20260531T235448Z-r1-string-slugify-1876884",
"`CTO-WORK-020` remains blocked until a provider/model is explicitly approved and real Case Stage 2 produces a pass report.",
"CTO-WORK-020 Decision Record Template",
"This template belongs to `CTO-WORK-020`; it is not a new provider approval.",
"`decision_status`: `not_decided`, `external_provider_approved`, or `local_provider_required`.",
"`provider_class`: `external_anthropic`, `external_openai_codex`, or `local_case_compatible`.",
"`provider`: exact provider string, or empty while blocked.",
"`model`: exact model string, or empty while blocked.",
"`approval_source`: JP approval reference or governed Core route reference.",
"`credential_source_class`: credential class only; no secret value.",
"`allowed_network_class`: allowed network class for this provider.",
"`review_trigger`: expiry, date, or condition that forces review.",
"`evidence_sources`: references to existing admission/build evidence, not copied runtime evidence.",
"`effect`: `CTO-WORK-020 remains blocked until admitted provider/model and real Stage 2 pass report exist`.",
"CTO-WORK-027 - OpenAI Codex Model Admission JSON",
"Admission file path is `.sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION.openai-codex-gpt-5.5.json`.",
"Admission JSON has `status`: `admitted`.",
"Admission JSON has `provider`: `openai-codex`.",
"Admission JSON has `model`: `gpt-5.5`.",
"Admission JSON has `credential_source_class`: `hermes-openai-codex-oauth-and-local-vllm-config`.",
"Admission JSON has `allowed_network_class`: `codex-oauth-hosted-model-plus-local-vllm-fallback`.",
"Admission JSON has `approval_source`: `JP chat approval on 2026-05-31`.",
"Admission JSON contains no secret keys or secret values.",
"Fallback to `openai-codex` / `gpt-5.5` remains explicit decision-record context and must be represented in runtime evidence before it may count as a Case provider/model path.",
"`CTO-WORK-020` remains blocked until real Case Stage 2 produces a Harness Evidence Interface pass report using this admission file.",
"Real Case Stage 2 command must set `CTO_HARNESS_CASE_MODEL_ADMISSION_FILE` to this admission JSON path.",
]
REQUIRED_OPENAI_CODEX_ADMISSION_JSON = {
"status": "admitted",
"provider": "openai-codex",
"model": "gpt-5.5",
"credential_source_class": "hermes-openai-codex-oauth-and-local-vllm-config",
"allowed_network_class": "codex-oauth-hosted-model-plus-local-vllm-fallback",
"approval_source": "JP chat approval on 2026-05-31",
}
REQUIRED_QWEN_LOCAL_ADMISSION_JSON = {
"status": "admitted",
"provider": "qwen-local",
"model": "qwen3.6-35b-a3b",
"credential_source_class": "pi-models-json-local-provider-no-secret",
"allowed_network_class": "local-tailscale-vllm-spark1",
"approval_source": "JP chat approval on 2026-05-31",
}
REQUIRED_LOCAL_PROVIDER_ROUTE_PRD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"`CTO-WORK-020` remains blocked until the selected local Qwen provider path produces real Case Stage 2 pass evidence.",
"`decision_status=local_provider_required`",
"local_case_compatible",
"CTO-WORK-020` admission JSON gate as authority",
"CTO_HARNESS_CASE_MODEL_ADMISSION_FILE",
"CTO_HARNESS_CASE_MODEL_PROVIDER",
"CTO_HARNESS_CASE_MODEL",
"no external provider fallback",
"missing local adapter config to block before `case_process_started`",
"admission JSON mismatch to block before `case_process_started`",
"`decision_status != local_provider_required` to block route execution",
"No Target Repository path exposure.",
"Do not approve a local provider.",
"Do not implement a provider adapter.",
"Do not admit a provider/model.",
"Do not approve Anthropic or any external provider.",
"Do not run real Case Stage 2.",
"case_model_provider",
"case_model",
"case_model_admission_status",
"anthropic",
"claude-sonnet-4-6",
"same-run fake baseline comparison required",
"Harness Evidence Interface",
]
REQUIRED_LOCAL_PROVIDER_ROUTE_ISSUE_IDS = [
"CTO-WORK-021",
"CTO-WORK-022",
]
REQUIRED_LOCAL_PROVIDER_ROUTE_ISSUE_PHRASES = [
"Status: validated.",
"`decision_status=local_provider_required`",
"local_case_compatible",
"Uses `CTO-WORK-020` admission JSON gate as authority instead of redefining admission.",
"CTO_HARNESS_CASE_MODEL_ADMISSION_FILE",
"no external fallback to `anthropic` or `claude-sonnet-4-6`",
"negative gates for missing local adapter config, admission JSON mismatch, and `decision_status != local_provider_required`",
"Completion of this route does not admit a provider/model and does not change `CTO-WORK-020` status.",
"Keeps `CTO-WORK-020` blocked until admitted provider/model and real Case Stage 2 pass evidence exist.",
"Does not approve or implement any provider.",
"Provider/model admission remains owned by `CTO-WORK-020`.",
"Missing local adapter config blocks before `case_process_started`.",
"Admission JSON mismatch blocks before `case_process_started`.",
"External provider fallback blocks before `case_process_started`.",
"Harness report proves `case_model_provider`, `case_model`, and `case_model_admission_status`.",
"Real Case Stage 2 produces a pass report only through the Harness Evidence Interface.",
]
REQUIRED_PROVIDER_DECISION_PACKET_PRD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"`CTO-WORK-020` is blocked by a provider policy decision.",
"`external_provider_approved`",
"`local_provider_required`",
"`local_provider_required` as the current selected state",
"does not approve a provider/model",
"does not approve or admit any provider/model",
"is not Stage 2 pass evidence",
"structured decision record using only `not_decided`, `external_provider_approved`, or `local_provider_required`",
"Reference existing evidence paths and commits; do not copy runtime evidence into the packet.",
"Keep `CTO-WORK-020` as the admission authority.",
"CTO_HARNESS_CASE_MODEL_ADMISSION_FILE",
"exact provider/model, approval source, credential source class, allowed network class, review trigger, and evidence expectations",
"no secret value in SOT, task file, argv, report, trace, backend logs, generated config, or commit",
"`CTO-WORK-022` blocked until explicit local provider config is supplied and real Case Stage 2 pass evidence exists",
"real Case Stage 2 blocked unless a provider/model is admitted and a pass report exists through the Harness Evidence Interface",
"no Target Repository path may be inspected or copied",
"`provider_class`: `external_anthropic`",
"`provider_class`: `external_anthropic` or `external_openai_codex`.",
"`openai-codex` with model `gpt-5.5` may be recorded as the primary approved external provider only when the approval source, credential source class, allowed network class, review trigger, and admission JSON are recorded.",
"`vllm` with model `qwen3.6-35b-a3b` may be recorded as an explicit fallback only when fallback use is represented in admission evidence and does not hide provider/model switching.",
"Packet permits provider class `external_openai_codex` only as a decision branch, not as admission or Stage 2 proof.",
"`provider_class`: `local_case_compatible`",
"No external fallback to `anthropic` or `claude-sonnet-4-6` is allowed.",
"Missing local adapter config blocks before `case_process_started`.",
"Admission JSON mismatch blocks before `case_process_started`.",
]
REQUIRED_PROVIDER_DECISION_PACKET_ISSUE_IDS = [
"CTO-WORK-023",
"CTO-WORK-024",
"CTO-WORK-025",
"CTO-WORK-026",
]
REQUIRED_PROVIDER_DECISION_PACKET_ISSUE_PHRASES = [
"Status: validated.",
"`local_provider_required` is current selected state",
"`external_provider_approved`",
"`local_provider_required`",
"does not approve or admit any provider/model",
"Says it is not Stage 2 pass evidence.",
"Requires a structured decision record using only `not_decided`, `external_provider_approved`, or `local_provider_required`.",
"References existing evidence paths and commits instead of copying runtime evidence.",
"Keeps `CTO-WORK-020` as provider/model admission authority.",
"Keeps `CTO_HARNESS_CASE_MODEL_ADMISSION_FILE` as execution admission gate.",
"Requires exact provider/model, approval source, credential source class, allowed network class, review trigger, and evidence expectations before admission.",
"Requires no secrets in SOT, task file, argv, report, trace, backend logs, generated config, or commits.",
"States `CTO-WORK-022` stays blocked until explicit local provider config and real Case Stage 2 pass evidence exist.",
"States real Case Stage 2 remains blocked until admitted provider/model and Harness Evidence Interface pass report exist.",
"States no Target Repository path may be inspected or copied.",
"Decision record selects exactly one branch: `external_provider_approved` or `local_provider_required`.",
"Decision record is structured and uses only `not_decided`, `external_provider_approved`, or `local_provider_required`.",
"Decision record references existing evidence paths and commits instead of copying runtime evidence.",
"`CTO-WORK-020` remains blocked until admitted provider/model and real Stage 2 pass report exist.",
"`CTO-WORK-022` remains blocked until explicit local provider config and real Case Stage 2 pass evidence exist.",
"Real Case Stage 2 remains blocked unless `CTO_HARNESS_CASE_MODEL_ADMISSION_FILE` exists and matches `CTO_HARNESS_CASE_MODEL_PROVIDER` and `CTO_HARNESS_CASE_MODEL`.",
"Decision record has `decision_status`: `not_decided`.",
"Provider class, provider, model, approval source, credential source class, allowed network class, and review trigger remain empty while blocked.",
"Record says `not_decided` means no provider/model may run.",
"Record says it is not provider/model admission, not Stage 2 pass evidence, and not approval for external or local provider use.",
"Record says `CTO-WORK-024` remains blocked because this record does not select `external_provider_approved` or `local_provider_required`.",
"Record says only JP or a governed Core route may change it away from `not_decided`.",
"Record allows only `external_provider_approved` or `local_provider_required` as future non-`not_decided` values.",
"Record keeps `CTO-WORK-020` as provider/model admission authority.",
"Record keeps `CTO_HARNESS_CASE_MODEL_ADMISSION_FILE` as execution admission gate.",
"Record keeps `CTO-WORK-024` blocked while `decision_status=not_decided`.",
"Record keeps `CTO-WORK-022` blocked unless `decision_status=local_provider_required`.",
"Record keeps real Case Stage 2 blocked until admitted provider/model and Harness Evidence Interface pass report exist.",
"Status: validated.",
"Record JP approval of the local Qwen primary provider decision branch for the current Hermes model stack.",
"Decision record has `decision_status`: `local_provider_required`.",
"Decision record has `provider_class`: `local_case_compatible`.",
"Decision record has `provider`: `qwen-local`.",
"Decision record has `model`: `qwen3.6-35b-a3b`.",
"Decision record has `fallback_provider`: `openai-codex`.",
"Decision record has `fallback_model`: `gpt-5.5`.",
"Decision record has `credential_source_class`: `pi-models-json-local-provider-no-secret-plus-codex-oauth-fallback`; no secret value.",
"Decision record has `allowed_network_class`: `local-tailscale-vllm-spark1-plus-codex-oauth-fallback`.",
"Decision record references Hermes model policy and local Hermes config as evidence sources without copying secrets.",
"Record says `CTO-WORK-024` is resolved by selecting `local_provider_required`.",
"Record keeps `CTO-WORK-020` blocked until admission JSON and real Stage 2 pass evidence exist.",
"Record keeps `CTO-WORK-022` blocked until explicit local provider config and real Case Stage 2 pass evidence exist.",
"Record requires fallback to `openai-codex` with `gpt-5.5` to be explicit in admission evidence before it may count as a Case provider/model path.",
]
REQUIRED_PROVIDER_DECISION_RECORD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"`decision_status`: `local_provider_required`.",
"`provider_class`: `local_case_compatible`.",
"`provider`: `qwen-local`.",
"`model`: `qwen3.6-35b-a3b`.",
"`fallback_provider`: `openai-codex`.",
"`fallback_model`: `gpt-5.5`.",
"`approval_source`: JP chat approval on 2026-05-31.",
"`credential_source_class`: `pi-models-json-local-provider-no-secret-plus-codex-oauth-fallback`; no secret value.",
"`allowed_network_class`: `local-tailscale-vllm-spark1-plus-codex-oauth-fallback`.",
"`review_trigger`: before real Case Stage 2 admission JSON is written, before any credential source change, and before any default/fallback model change.",
"/home/svrnty/workspaces/hermes/scripts/apply-hermes-model-policy.py",
"/home/svrnty/.hermes/config.yaml",
"`effect`: `CTO-WORK-020 remains blocked until admitted provider/model and real Stage 2 pass report exist`.",
"`local_provider_required` means JP approved the provider decision branch for the existing Hermes model stack: `qwen-local` with model `qwen3.6-35b-a3b` as primary, and `openai-codex` with model `gpt-5.5` as fallback.",
"This record is not provider/model admission and is not Stage 2 pass evidence.",
"`CTO-WORK-024` is resolved by this record selecting `local_provider_required`.",
"Previous state:",
"`decision_status`: `not_decided`.",
"`not_decided` means no provider/model may run.",
"Only JP or a governed Core route may change this record away from `local_provider_required`.",
"Allowed future values remain `external_provider_approved` or `local_provider_required`.",
"No secret value may appear in SOT, task file, argv, report, trace, backend logs, generated config, or commit.",
"No Target Repository path may be inspected or copied.",
"`CTO-WORK-020` remains provider/model admission authority.",
"`CTO_HARNESS_CASE_MODEL_ADMISSION_FILE` remains execution admission gate.",
"`CTO-WORK-022` remains blocked until explicit local provider config is supplied and real Case Stage 2 pass evidence exists.",
"Real Case Stage 2 remains blocked until admitted provider/model and Harness Evidence Interface pass report exist.",
"Fallback to `openai-codex` with `gpt-5.5` must be explicit in admission evidence before it may count as a Case provider/model path.",
"Existing evidence paths and commits are referenced only; runtime evidence is not copied into this record.",
]
REQUIRED_SPARK_ENDPOINT_CONFIG_PRD_PHRASES = [
"Local planning SOT only. Not a Core Protocol. Not active Core authority.",
"`qwen-local` / `qwen3.6-35b-a3b` is now the selected primary Case provider policy",
"CTO_HARNESS_CASE_LOCAL_BASE_URL",
"missing. The harness correctly blocks before `case_process_started`",
"Treat the endpoint value as runtime config, not SOT content.",
"Do not store endpoint secrets or credential values in SOT, argv, task file, backend logs, report, trace, generated config, or commit.",
"Require missing endpoint config to write `backend/provider-local-config-unavailable.txt`.",
"Keep `CTO-WORK-020`, `CTO-WORK-016`, `CTO-WORK-022`, and Stage 2 blocked until real pass evidence exists.",
"endpoint presence is not Stage 2 pass evidence",
"configured endpoint alone does not validate `CTO-WORK-016`, `CTO-WORK-020`, `CTO-WORK-022`, or `CTO-WORK-028`",
"no Target Repository path may be inspected or copied",
"Harness Evidence Interface",
"same-run fake baseline comparison required",
]
REQUIRED_SPARK_ENDPOINT_CONFIG_ISSUE_PHRASES = [
"CTO-WORK-030 - Spark Local Provider Endpoint Config",
"Status: validated.",
"CTO_HARNESS_CASE_LOCAL_BASE_URL",
"Missing endpoint config blocks before `case_process_started`.",
"Missing endpoint config writes `backend/provider-local-config-unavailable.txt`.",
"Endpoint values are not written to SOT, task file, argv, backend logs, report, trace, generated config, or commit.",
"Harness report proves `case_model_provider`: `qwen-local`.",
"Harness report proves `case_model`: `qwen3.6-35b-a3b`.",
"Harness report proves `case_model_admission_status`: `admitted`.",
"Harness report proves no fallback to `anthropic` or `claude-sonnet-4-6`.",
"Real Case Stage 2 pass evidence exists only through the Harness Evidence Interface.",
"A configured endpoint alone does not validate `CTO-WORK-016`, `CTO-WORK-020`, `CTO-WORK-022`, or `CTO-WORK-028`.",
"No Target Repository path may be inspected or copied.",
"Same-run fake baseline comparison remains required for any pass claim.",
"`CTO-WORK-016` remains blocked until real Case Stage 2 pass evidence exists.",
"`CTO-WORK-022` remains blocked until explicit endpoint config and real Case Stage 2 pass evidence exist.",
"Non-secret readiness check on 2026-06-01 showed `CTO_HARNESS_CASE_LOCAL_BASE_URL=missing`.",
]
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}")
spark_endpoint_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-SPARK-ENDPOINT-CONFIG-PRD.md"
if spark_endpoint_prd.is_file():
text = spark_endpoint_prd.read_text(encoding="utf-8")
for phrase in REQUIRED_SPARK_ENDPOINT_CONFIG_PRD_PHRASES:
checked.append(f"spark_endpoint_config_prd_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_spark_endpoint_config_prd_phrase:{phrase}")
spark_endpoint_issues = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-SPARK-ENDPOINT-CONFIG-ISSUES.md"
if spark_endpoint_issues.is_file():
text = spark_endpoint_issues.read_text(encoding="utf-8")
for phrase in REQUIRED_SPARK_ENDPOINT_CONFIG_ISSUE_PHRASES:
checked.append(f"spark_endpoint_config_issue_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_spark_endpoint_config_issue_phrase:{phrase}")
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}")
stage3_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-STAGE3-COPIED-REPO-PRD.md"
if stage3_prd.is_file():
text = stage3_prd.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("stage3_prd_missing_not_promoted_frontmatter")
for phrase in REQUIRED_STAGE3_PRD_PHRASES:
checked.append(f"stage3_prd_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_stage3_prd_phrase:{phrase}")
stage3_issues = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-STAGE3-COPIED-REPO-ISSUES.md"
if stage3_issues.is_file():
text = stage3_issues.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("stage3_issues_missing_not_promoted_frontmatter")
if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text:
errors.append("stage3_issues_missing_local_planning_notice")
for issue_id in REQUIRED_STAGE3_ISSUE_IDS:
checked.append(f"stage3_issue_id:{issue_id}")
if issue_id not in text:
errors.append(f"missing_stage3_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}")
provider_build_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-BUILD-PRD.md"
if provider_build_prd.is_file():
text = provider_build_prd.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("provider_build_prd_missing_not_promoted_frontmatter")
for phrase in REQUIRED_PROVIDER_BUILD_PRD_PHRASES:
checked.append(f"provider_build_prd_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_provider_build_prd_phrase:{phrase}")
provider_build_issues = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-BUILD-ISSUES.md"
if provider_build_issues.is_file():
text = provider_build_issues.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("provider_build_issues_missing_not_promoted_frontmatter")
if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text:
errors.append("provider_build_issues_missing_local_planning_notice")
for issue_id in REQUIRED_PROVIDER_BUILD_ISSUE_IDS:
checked.append(f"provider_build_issue_id:{issue_id}")
if issue_id not in text:
errors.append(f"missing_provider_build_issue_id:{issue_id}")
model_provider_admission_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION-PRD.md"
if model_provider_admission_prd.is_file():
text = model_provider_admission_prd.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("model_provider_admission_prd_missing_not_promoted_frontmatter")
for phrase in REQUIRED_MODEL_PROVIDER_ADMISSION_PRD_PHRASES:
checked.append(f"model_provider_admission_prd_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_model_provider_admission_prd_phrase:{phrase}")
model_provider_admission_issues = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION-ISSUES.md"
if model_provider_admission_issues.is_file():
text = model_provider_admission_issues.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("model_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("model_provider_admission_issues_missing_local_planning_notice")
for issue_id in REQUIRED_MODEL_PROVIDER_ADMISSION_ISSUE_IDS:
checked.append(f"model_provider_admission_issue_id:{issue_id}")
if issue_id not in text:
errors.append(f"missing_model_provider_admission_issue_id:{issue_id}")
for phrase in REQUIRED_MODEL_PROVIDER_ADMISSION_ISSUE_PHRASES:
checked.append(f"model_provider_admission_issue_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_model_provider_admission_issue_phrase:{phrase}")
openai_codex_admission = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION.openai-codex-gpt-5.5.json"
if openai_codex_admission.is_file():
checked.append("openai_codex_admission_json:parse")
try:
payload = json.loads(openai_codex_admission.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
errors.append(f"openai_codex_admission_invalid_json:{exc}")
payload = {}
if not isinstance(payload, dict):
errors.append("openai_codex_admission_must_be_object")
payload = {}
for key, expected in REQUIRED_OPENAI_CODEX_ADMISSION_JSON.items():
checked.append(f"openai_codex_admission_json:{key}")
if payload.get(key) != expected:
errors.append(f"openai_codex_admission_mismatch:{key}:expected_{expected}:actual_{payload.get(key)}")
for key in ["admission_timestamp", "review_trigger"]:
checked.append(f"openai_codex_admission_json:{key}")
if not isinstance(payload.get(key), str) or not payload.get(key):
errors.append(f"openai_codex_admission_missing:{key}")
for key in payload:
checked.append(f"openai_codex_admission_json_secret_key:{key}")
if key.lower() in {"api_key", "apikey", "access_token", "token", "secret", "password", "credential_value"}:
errors.append(f"openai_codex_admission_forbidden_secret_key:{key}")
qwen_local_admission = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION.qwen-local-qwen3.6-35b-a3b.json"
if qwen_local_admission.is_file():
checked.append("qwen_local_admission_json:parse")
try:
payload = json.loads(qwen_local_admission.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
errors.append(f"qwen_local_admission_invalid_json:{exc}")
payload = {}
if not isinstance(payload, dict):
errors.append("qwen_local_admission_must_be_object")
payload = {}
for key, expected in REQUIRED_QWEN_LOCAL_ADMISSION_JSON.items():
checked.append(f"qwen_local_admission_json:{key}")
if payload.get(key) != expected:
errors.append(f"qwen_local_admission_mismatch:{key}:expected_{expected}:actual_{payload.get(key)}")
for key in ["admission_timestamp", "review_trigger"]:
checked.append(f"qwen_local_admission_json:{key}")
if not isinstance(payload.get(key), str) or not payload.get(key):
errors.append(f"qwen_local_admission_missing:{key}")
for key in payload:
checked.append(f"qwen_local_admission_json_secret_key:{key}")
if key.lower() in {"api_key", "apikey", "access_token", "token", "secret", "password", "credential_value"}:
errors.append(f"qwen_local_admission_forbidden_secret_key:{key}")
local_provider_route_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md"
if local_provider_route_prd.is_file():
text = local_provider_route_prd.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("local_provider_route_prd_missing_not_promoted_frontmatter")
for phrase in REQUIRED_LOCAL_PROVIDER_ROUTE_PRD_PHRASES:
checked.append(f"local_provider_route_prd_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_local_provider_route_prd_phrase:{phrase}")
local_provider_route_issues = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md"
if local_provider_route_issues.is_file():
text = local_provider_route_issues.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("local_provider_route_issues_missing_not_promoted_frontmatter")
if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text:
errors.append("local_provider_route_issues_missing_local_planning_notice")
for issue_id in REQUIRED_LOCAL_PROVIDER_ROUTE_ISSUE_IDS:
checked.append(f"local_provider_route_issue_id:{issue_id}")
if issue_id not in text:
errors.append(f"missing_local_provider_route_issue_id:{issue_id}")
for phrase in REQUIRED_LOCAL_PROVIDER_ROUTE_ISSUE_PHRASES:
checked.append(f"local_provider_route_issue_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_local_provider_route_issue_phrase:{phrase}")
provider_decision_packet_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-DECISION-PACKET-PRD.md"
if provider_decision_packet_prd.is_file():
text = provider_decision_packet_prd.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("provider_decision_packet_prd_missing_not_promoted_frontmatter")
for phrase in REQUIRED_PROVIDER_DECISION_PACKET_PRD_PHRASES:
checked.append(f"provider_decision_packet_prd_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_provider_decision_packet_prd_phrase:{phrase}")
provider_decision_packet_issues = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-DECISION-PACKET-ISSUES.md"
if provider_decision_packet_issues.is_file():
text = provider_decision_packet_issues.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("provider_decision_packet_issues_missing_not_promoted_frontmatter")
if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text:
errors.append("provider_decision_packet_issues_missing_local_planning_notice")
for issue_id in REQUIRED_PROVIDER_DECISION_PACKET_ISSUE_IDS:
checked.append(f"provider_decision_packet_issue_id:{issue_id}")
if issue_id not in text:
errors.append(f"missing_provider_decision_packet_issue_id:{issue_id}")
for phrase in REQUIRED_PROVIDER_DECISION_PACKET_ISSUE_PHRASES:
checked.append(f"provider_decision_packet_issue_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_provider_decision_packet_issue_phrase:{phrase}")
provider_decision_record = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-DECISION-RECORD.md"
if provider_decision_record.is_file():
text = provider_decision_record.read_text(encoding="utf-8")
if "core_promotion_status: not-promoted" not in text:
errors.append("provider_decision_record_missing_not_promoted_frontmatter")
for phrase in REQUIRED_PROVIDER_DECISION_RECORD_PHRASES:
checked.append(f"provider_decision_record_phrase:{phrase}")
if phrase not in text:
errors.append(f"missing_provider_decision_record_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}")
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_STAGE3_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}")
for issue_id in REQUIRED_PROVIDER_BUILD_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_MODEL_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}")
for issue_id in REQUIRED_LOCAL_PROVIDER_ROUTE_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_DECISION_PACKET_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": "validated",
"CTO-WORK-013": "validated",
"CTO-WORK-014": "validated",
"CTO-WORK-015": "validated",
"CTO-WORK-016": "validated",
"CTO-WORK-017": "validated",
"CTO-WORK-018": "validated",
"CTO-WORK-019": "validated",
"CTO-WORK-020": "validated",
"CTO-WORK-021": "validated",
"CTO-WORK-022": "validated",
"CTO-WORK-023": "validated",
"CTO-WORK-024": "validated",
"CTO-WORK-025": "validated",
"CTO-WORK-026": "validated",
"CTO-WORK-027": "validated",
"CTO-WORK-029": "validated",
"CTO-WORK-030": "validated",
"CTO-WORK-033": "validated",
"CTO-WORK-034": "blocked",
}
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-STAGE3-COPIED-REPO-PRD.md" not in text:
errors.append("workboard_missing_stage3_prd_source")
if "CTO-CASE-STAGE3-COPIED-REPO-ISSUES.md" not in text:
errors.append("workboard_missing_stage3_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")
if "CTO-CASE-PROVIDER-BUILD-PRD.md" not in text:
errors.append("workboard_missing_provider_build_prd_source")
if "CTO-CASE-PROVIDER-BUILD-ISSUES.md" not in text:
errors.append("workboard_missing_provider_build_issues_source")
if "CTO-CASE-MODEL-PROVIDER-ADMISSION-PRD.md" not in text:
errors.append("workboard_missing_model_provider_admission_prd_source")
if "CTO-CASE-MODEL-PROVIDER-ADMISSION-ISSUES.md" not in text:
errors.append("workboard_missing_model_provider_admission_issues_source")
if "CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md" not in text:
errors.append("workboard_missing_local_provider_route_prd_source")
if "CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md" not in text:
errors.append("workboard_missing_local_provider_route_issues_source")
if "CTO-CASE-PROVIDER-DECISION-PACKET-PRD.md" not in text:
errors.append("workboard_missing_provider_decision_packet_prd_source")
if "CTO-CASE-PROVIDER-DECISION-PACKET-ISSUES.md" not in text:
errors.append("workboard_missing_provider_decision_packet_issues_source")
if "CTO-CASE-PROVIDER-DECISION-RECORD.md" not in text:
errors.append("workboard_missing_provider_decision_record_source")
if "CTO-CASE-MODEL-PROVIDER-ADMISSION.openai-codex-gpt-5.5.json" not in text:
errors.append("workboard_missing_openai_codex_admission_json_source")
if "CTO-CASE-MODEL-PROVIDER-ADMISSION.qwen-local-qwen3.6-35b-a3b.json" not in text:
errors.append("workboard_missing_qwen_local_admission_json_source")
if "CTO-CASE-SPARK-ENDPOINT-CONFIG-ISSUES.md" not in text:
errors.append("workboard_missing_spark_endpoint_config_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())