Add CTO Case Stage 2 artificial fixture PRD
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user