From 6af4199ebc7c6ee97fce587e7f7f72bf62566871 Mon Sep 17 00:00:00 2001 From: Svrnty Date: Sun, 31 May 2026 20:04:33 -0400 Subject: [PATCH] Add Case local provider adapter route --- README.md | 4 +- WORKBOARD.yaml | 10 ++ .../CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md | 56 ++++++++++++ .../CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md | 77 ++++++++++++++++ tools/validate_cto_child.py | 91 +++++++++++++++++++ 5 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md create mode 100644 sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md diff --git a/README.md b/README.md index fab07df..0818c41 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,9 @@ This workspace is registered as a child-local planning workspace. Registration d | |-- CTO-CASE-PROVIDER-BUILD-PRD.md | |-- CTO-CASE-PROVIDER-BUILD-ISSUES.md | |-- CTO-CASE-MODEL-PROVIDER-ADMISSION-PRD.md -| `-- CTO-CASE-MODEL-PROVIDER-ADMISSION-ISSUES.md +| |-- CTO-CASE-MODEL-PROVIDER-ADMISSION-ISSUES.md +| |-- CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md +| `-- CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md `-- tools/ `-- validate_cto_child.py ``` diff --git a/WORKBOARD.yaml b/WORKBOARD.yaml index faecfd0..bceb368 100644 --- a/WORKBOARD.yaml +++ b/WORKBOARD.yaml @@ -100,3 +100,13 @@ items: status: blocked source: sot/03-PROTOCOLS/CTO-CASE-MODEL-PROVIDER-ADMISSION-ISSUES.md owner: jp + - id: CTO-WORK-021 + title: Case-Compatible Local Provider Adapter Route PRD + status: validated + source: sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md + owner: jp + - id: CTO-WORK-022 + title: Case-Compatible Local Provider Adapter Route + status: blocked + source: sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md + owner: jp diff --git a/sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md b/sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md new file mode 100644 index 0000000..4178b79 --- /dev/null +++ b/sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-ISSUES.md @@ -0,0 +1,56 @@ +--- +title: CTO Case Local Provider Route Issues +status: draft +lifecycle_classification: sot +owner: jp +created: 2026-05-31 +last_reviewed: 2026-05-31 +core_promotion_status: not-promoted +route: cto +--- + +# CTO Case Local Provider Route Issues + +Local planning SOT only. Not a Core Protocol. Not active Core authority. + +## CTO-WORK-021 - Case-Compatible Local Provider Adapter Route PRD + +Status: validated. + +Register the local-provider adapter route as the autonomous option if `CTO-WORK-020` is resolved with `decision_status=local_provider_required`. + +Acceptance: + +- States that this route applies only when `decision_status=local_provider_required`. +- Requires provider class `local_case_compatible`. +- Uses `CTO-WORK-020` admission JSON gate as authority instead of redefining admission. +- Requires `CTO_HARNESS_CASE_MODEL_ADMISSION_FILE`. +- Requires no external fallback to `anthropic` or `claude-sonnet-4-6`. +- Requires 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. + +## CTO-WORK-022 - Case-Compatible Local Provider Adapter Route + +Status: blocked. + +Build or supply one Case-compatible local provider adapter path only after the decision record selects `local_provider_required`. + +Acceptance: + +- Decision record has `decision_status=local_provider_required`. +- Provider class is `local_case_compatible`. +- 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`. +- Harness report proves no fallback to `anthropic` or `claude-sonnet-4-6`. +- No secret is written to SOT, argv, task file, backend logs, report, trace, generated config, or commit. +- Real Case Stage 2 produces a pass report only through the Harness Evidence Interface. + +Blocked by: + +- `CTO-WORK-020` decision record selecting `local_provider_required`. +- A Case-compatible local provider adapter implementation or supplied local provider endpoint. diff --git a/sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md b/sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md new file mode 100644 index 0000000..9e452cf --- /dev/null +++ b/sot/03-PROTOCOLS/CTO-CASE-LOCAL-PROVIDER-ROUTE-PRD.md @@ -0,0 +1,77 @@ +--- +title: CTO Case Local Provider Route PRD +status: draft +lifecycle_classification: sot +owner: jp +created: 2026-05-31 +last_reviewed: 2026-05-31 +core_promotion_status: not-promoted +route: cto +--- + +# CTO Case Local Provider Route PRD + +Local planning SOT only. Not a Core Protocol. Not active Core authority. + +## Problem Statement + +`CTO-WORK-020` remains blocked until a provider policy decision exists. If the decision is `local_provider_required`, Cortex CTO needs a narrow route for a Case-compatible local model provider before real Case Stage 2 can run without external provider approval. + +## Solution + +Define a child-local Case-compatible local provider adapter route. This route does not select a provider, does not implement a provider, and does not admit a provider/model. It uses the existing `CTO-WORK-020` admission JSON gate as authority. + +## Scope + +- Apply only when `decision_status=local_provider_required`. +- Require provider class `local_case_compatible` only through the `CTO-WORK-020` decision record. +- Require compatibility with WorkOS Case model configuration through the existing `CTO_HARNESS_CASE_MODEL_ADMISSION_FILE` gate. +- Require the existing Hermes admitted-pair gate to remain the execution gate. +- Require the adapter path to prove no external provider fallback. +- Require missing local adapter config to block before `case_process_started`. +- Require admission JSON mismatch to block before `case_process_started`. +- Require `decision_status != local_provider_required` to block route execution. +- Require Stage 2 to keep copied artificial fixture scope only. +- Require no Target Repository path exposure. +- No Target Repository path exposure. +- Require no secrets in SOT, argv, task file, report, trace, backend logs, generated config, or commits. + +## Non-Goals + +- 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. +- Do not create a provider marketplace or registry. +- Do not change Hermes runtime behavior from this route. +- Do not treat Case as CTO authority. + +## Acceptance Criteria + +- A local provider adapter route references the `CTO-WORK-020` decision record and admission JSON gate instead of redefining admission fields. +- Completion of this route does not admit a provider/model and does not change `CTO-WORK-020` status. +- The route states that `CTO-WORK-020` remains blocked until admitted provider/model and real Case Stage 2 pass evidence exist. +- The route requires proof that Case used the admitted local provider/model from `CTO-WORK-020` and did not fall back to `anthropic` or `claude-sonnet-4-6`. +- The route requires `case_model_provider`, `case_model`, and `case_model_admission_status` in report evidence. +- The route requires `CTO_HARNESS_CASE_MODEL_ADMISSION_FILE`, `CTO_HARNESS_CASE_MODEL_PROVIDER`, and `CTO_HARNESS_CASE_MODEL`. +- The route requires negative gates for missing local adapter config, admission JSON mismatch, and `decision_status != local_provider_required`. +- The route keeps fake as the default validation lane. +- The route keeps same-run fake baseline comparison required. + +## Validation + +- `python3 tools/validate_cto_child.py` validates this child-local route. +- Future Hermes focused validation must include `python3 harness/runner/validate-case-provider-adapter.py --harness-root harness --json`. +- Future real local provider validation must use the Harness Evidence Interface and copied artificial fixture Stage 2 only. + +## Risks And Dependencies + +- WorkOS Case may not support the intended local provider without additional adapter work. +- Local inference may still require credentials, endpoint configuration, or model serving state. +- Local model quality may fail Stage 2 even when the provider route is valid. +- A local provider route does not remove the need for an admission JSON and real pass report. + +## Success Definition + +If JP chooses `local_provider_required`, the next implementation route is explicit: build or supply one Case-compatible local provider adapter path, then use `CTO-WORK-020` to admit the exact provider/model pair before any real Case Stage 2 retry. diff --git a/tools/validate_cto_child.py b/tools/validate_cto_child.py index 53bd319..1ad042a 100644 --- a/tools/validate_cto_child.py +++ b/tools/validate_cto_child.py @@ -34,6 +34,8 @@ REQUIRED_FILES = [ "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", ] REQUIRED_BRIEF_PHRASES = [ @@ -451,6 +453,59 @@ REQUIRED_MODEL_PROVIDER_ADMISSION_ISSUE_PHRASES = [ "`effect`: `CTO-WORK-020 remains blocked until admitted provider/model and real Stage 2 pass report exist`.", ] +REQUIRED_LOCAL_PROVIDER_ROUTE_PRD_PHRASES = [ + "Local planning SOT only. Not a Core Protocol. Not active Core authority.", + "`CTO-WORK-020` remains blocked until a provider policy decision exists.", + "`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.", + "Status: blocked.", + "`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.", +] + def workboard_status(text: str, issue_id: str) -> str | None: pattern = rf"- id: {re.escape(issue_id)}\n(?: .+\n)*? status: ([^\n]+)" @@ -668,6 +723,32 @@ def main() -> int: if phrase not in text: errors.append(f"missing_model_provider_admission_issue_phrase:{phrase}") + 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}") + board = ROOT / "WORKBOARD.yaml" if board.is_file(): text = board.read_text(encoding="utf-8") @@ -695,6 +776,10 @@ 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_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}") expected_statuses = { "CTO-WORK-002": "validated", "CTO-WORK-003": "validated", @@ -715,6 +800,8 @@ def main() -> int: "CTO-WORK-018": "validated", "CTO-WORK-019": "validated", "CTO-WORK-020": "blocked", + "CTO-WORK-021": "validated", + "CTO-WORK-022": "blocked", } for issue_id, expected in expected_statuses.items(): checked.append(f"workboard_status:{issue_id}:{expected}") @@ -753,6 +840,10 @@ def main() -> int: 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") payload = { "ok": not errors,