Add CTO Case Stage 2 artificial fixture PRD

This commit is contained in:
Svrnty
2026-05-31 19:14:07 -04:00
parent 4fe2e1092e
commit 64a0d3f2e9
5 changed files with 315 additions and 9 deletions
+97
View File
@@ -4,6 +4,7 @@
from __future__ import annotations
import json
import re
from pathlib import Path
@@ -25,6 +26,8 @@ REQUIRED_FILES = [
"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",
]
REQUIRED_BRIEF_PHRASES = [
@@ -209,6 +212,52 @@ REQUIRED_STAGE1_ISSUE_IDS = [
"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",
]
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] = []
@@ -328,6 +377,28 @@ def main() -> int:
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}")
board = ROOT / "WORKBOARD.yaml"
if board.is_file():
text = board.read_text(encoding="utf-8")
@@ -339,6 +410,28 @@ def main() -> int:
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}")
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": "candidate",
"CTO-WORK-012": "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:
@@ -355,6 +448,10 @@ def main() -> int:
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")
payload = {
"ok": not errors,