From 44ad43d9582fd7e956be204a816f1c5a6f0eea1e Mon Sep 17 00:00:00 2001 From: Svrnty Date: Sun, 31 May 2026 18:47:43 -0400 Subject: [PATCH] Add CTO Case adapter contract --- README.md | 3 +- WORKBOARD.yaml | 4 +- sot/03-PROTOCOLS/CTO-CASE-ADAPTER-CONTRACT.md | 155 ++++++++++++++++++ tools/validate_cto_child.py | 34 ++++ 4 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 sot/03-PROTOCOLS/CTO-CASE-ADAPTER-CONTRACT.md diff --git a/README.md b/README.md index a3ce725..62296fb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ This workspace is registered as a child-local planning workspace. Registration d | |-- CTO-CASE-CANDIDATE-BACKEND-PRD.md | |-- CTO-CASE-CANDIDATE-BACKEND-ISSUES.md | |-- CTO-HARNESS-EVIDENCE-INTERFACE-CONTRACT.md -| `-- CTO-CASE-SOURCE-ADMISSION-RECORD.md +| |-- CTO-CASE-SOURCE-ADMISSION-RECORD.md +| `-- CTO-CASE-ADAPTER-CONTRACT.md `-- tools/ `-- validate_cto_child.py ``` diff --git a/WORKBOARD.yaml b/WORKBOARD.yaml index 1556bf4..84852e3 100644 --- a/WORKBOARD.yaml +++ b/WORKBOARD.yaml @@ -26,8 +26,8 @@ items: owner: jp - id: CTO-WORK-006 title: Case Adapter Contract And Eligibility Decision - status: candidate - source: sot/03-PROTOCOLS/CTO-CASE-CANDIDATE-BACKEND-ISSUES.md + status: validated + source: sot/03-PROTOCOLS/CTO-CASE-ADAPTER-CONTRACT.md owner: jp - id: CTO-WORK-007 title: Case Failure Fixture Matrix diff --git a/sot/03-PROTOCOLS/CTO-CASE-ADAPTER-CONTRACT.md b/sot/03-PROTOCOLS/CTO-CASE-ADAPTER-CONTRACT.md new file mode 100644 index 0000000..0fde9ae --- /dev/null +++ b/sot/03-PROTOCOLS/CTO-CASE-ADAPTER-CONTRACT.md @@ -0,0 +1,155 @@ +--- +name: cto-case-adapter-contract +tier: local +status: draft +owner: jp +source: sot/03-PROTOCOLS/CTO-CASE-CANDIDATE-BACKEND-PRD.md +created: 2026-05-31 +last_reviewed: 2026-05-31 +lifecycle_classification: planning +core_promotion_status: not-promoted +description: Child-local contract for the future gated Case adapter and CTO Eligibility Decision. +--- + +# CTO Case Adapter Contract + +Local planning SOT only. Not a Core Protocol. Not active Core authority. + +## Purpose + +Define the future Case adapter seam and CTO Eligibility Decision before any executable Case integration exists. + +This contract keeps Case behind the CTO Harness seam. Case may become a backend adapter only after source admission, evidence interface conformance, explicit gating, and staged proof. + +## Non-Authority Notice + +This contract does not authorize Runtime behavior, WebUI Product behavior, Case execution, real-repo mutation, merge, deploy, push, close, vendor-source mutation, external developer repository mutation, or Core promotion. + +## Adapter Boundary + +The Case adapter must live behind the existing CTO Harness engine seam. + +Required boundary rules: + +- 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; +- keep Case lifecycle details behind the adapter unless a later contract promotes normalized events; +- emit the CTO Harness Evidence Interface, not raw Case success claims; +- default-deny all execution until explicit gates pass. + +## Gating Rule + +`case` must be disabled by default. + +Minimum future gates: + +- source admission is validated; +- license note is resolved; +- evidence interface contract is validated; +- adapter contract is validated; +- mutation mode is explicitly selected; +- operator approval is recorded when mutation mode requires approval; +- allowed paths and forbidden actions are provided by the task contract. + +No missing gate may degrade to a warning. Missing gate means blocked. + +## Adapter Input Contract + +The future adapter input must be derived from existing PRD, SOT Issue, task contract, and case contract language until Candidate Cortex Work Packet is promoted. + +Minimum input fields: + +| Field | Meaning | +| --- | --- | +| `task_id` | Stable task or issue identifier. | +| `target_repository` | Target Repository path or URL. | +| `authority_basis` | Local planning, Core route, or task contract reference. | +| `risk_class` | Risk class used for eligibility. | +| `allowed_paths` | Paths the backend may change. | +| `forbidden_actions` | Actions the backend must not perform. | +| `mutation_mode` | `none`, `copied-fixture`, `sandbox-repo`, `owned-noncritical-repo`, or `candidate-default`. | +| `approval_required` | Whether human approval is required before mutation. | +| `verification_commands` | Commands expected to prove the change. | +| `evidence_expectations` | Required artifacts and validation results. | + +## Adapter Output Contract + +The future adapter output must be the CTO Harness Evidence Interface. + +Minimum output: + +- `report.json`; +- `report.md`; +- `events.normalized.jsonl`; +- `patch.diff`; +- `test.log`; +- `trace.jsonl`; +- backend raw logs under `backend/`; +- pass, fail, or blocked status; +- blocker reasons for any fail-closed result. + +Raw Case lifecycle output is allowed only as backend raw logs unless normalized by this or a later contract. + +## CTO Eligibility Decision + +Before selecting Case or any backend, CTO must emit an Eligibility Decision. + +Required fields: + +| Field | Meaning | +| --- | --- | +| `decision_id` | Stable decision identifier. | +| `task_id` | Task or issue identifier. | +| `selected_backend` | Backend selected, or `none`. | +| `denied_backends` | Backends denied with reasons. | +| `risk_class` | Risk classification used for the decision. | +| `required_gates` | Gates that must pass before execution. | +| `passed_gates` | Gates already proven. | +| `missing_gates` | Gates that block execution. | +| `allowed_mutation_mode` | Maximum mutation mode allowed. | +| `approval_required` | Whether human approval is required. | +| `reasons` | Human-readable decision reasons. | +| `escalation_path` | JP, Core route, Hermes/operator, or blocked. | + +Case must not create or override the Eligibility Decision. Case may recommend, but CTO decides eligibility and the harness records evidence. + +## Backend Selection Rules + +Case is ineligible when: + +- source admission is not validated; +- license note is unresolved for the requested execution mode; +- Harness Evidence Interface cannot be produced; +- allowed paths are missing; +- forbidden actions are missing; +- approval is required but not granted; +- mutation mode exceeds the current staged proof gate; +- target repository ownership is unclear; +- starting worktree state is dirty when clean start is required. + +Case may be eligible only when every required gate is proven and the allowed mutation mode is no broader than the current staged proof gate. + +## Approval Rule + +Case may recommend. Case must not approve itself or select its own authority. + +Approval must be represented by normalized events: + +- `approval.requested`; +- `approval.granted`; +- `approval.denied`. + +No merge, push, deploy, close, or real-repo mutation is allowed without explicit task-contract permission. + +## Implementation Guard + +This contract deliberately does not create `case-engine.sh`. + +The first future implementation slice may create a no-op gated adapter only after the staged proof gate record exists. The no-op adapter must prove default-deny behavior before it can attempt artificial fixture execution. + +## Validation Expectations + +Current validation is planning-only and checks this contract exists. + +Later adapter validation must verify engine registration, explicit gate behavior, input shape, Eligibility Decision shape, output evidence shape, approval events, and fail-closed ineligibility. diff --git a/tools/validate_cto_child.py b/tools/validate_cto_child.py index dc05ff9..6fc4a66 100644 --- a/tools/validate_cto_child.py +++ b/tools/validate_cto_child.py @@ -20,6 +20,7 @@ REQUIRED_FILES = [ "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", ] REQUIRED_BRIEF_PHRASES = [ @@ -97,6 +98,27 @@ REQUIRED_SOURCE_ADMISSION_PHRASES = [ "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`.", +] + def main() -> int: checked: list[str] = [] @@ -164,6 +186,16 @@ def main() -> int: 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}") + board = ROOT / "WORKBOARD.yaml" if board.is_file(): text = board.read_text(encoding="utf-8") @@ -177,6 +209,8 @@ def main() -> int: 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") payload = { "ok": not errors,