From 51977d36cdcf0da6b9248d24dd395359740c12cf Mon Sep 17 00:00:00 2001 From: Svrnty Date: Sun, 31 May 2026 23:43:50 -0400 Subject: [PATCH] Add Case Stage 5 owned repo planning --- ...SE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md | 89 +++++++++++++++++ ...-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md | 95 +++++++++++++++++++ .../CTO-CASE-STAGED-PROOF-GATES.md | 7 ++ README.md | 2 + WORKBOARD.yaml | 10 ++ tools/validate_cto_child.py | 53 +++++++++++ 6 files changed, 256 insertions(+) create mode 100644 .sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md create mode 100644 .sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md diff --git a/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md b/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md new file mode 100644 index 0000000..746d817 --- /dev/null +++ b/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md @@ -0,0 +1,89 @@ +--- +name: cto-case-stage5-owned-noncritical-repo-issues +tier: local +status: draft +owner: jp +source: .sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md +created: 2026-06-01 +last_reviewed: 2026-06-01 +lifecycle_classification: planning +core_promotion_status: not-promoted +description: Child-local issue sequence for Stage 5 Case owned noncritical repository proof. +--- + +# CTO Case Stage 5 Owned Noncritical Repository Issues + +Local planning SOT only. Not a Core Protocol. Not active Core authority. + +## Issue Sequence + +### CTO-WORK-037 - Stage 5 Owned Noncritical Repo PRD + +Type: AFK + +Status: validated. + +Blocked by: CTO-WORK-036 + +User stories covered: CTO Case Candidate Backend PRD stories 4, 5, 7, 8, 9, 10, 11, 13. + +What to build: Define the Stage 5 owned noncritical repository proof before implementation starts. + +Acceptance criteria: + +- [x] PRD states Stage 5 allowed mutation scope is `explicitly owned low-risk repository only`. +- [x] PRD requires Stage 4 validation before Stage 5. +- [x] PRD requires `CTO_HARNESS_ALLOW_CASE=1` and `CTO_HARNESS_CASE_STAGE=5`. +- [x] PRD requires Target Repository ownership proof and noncritical classification. +- [x] PRD requires approval requested/granted/denied events before mutation. +- [x] PRD requires allowed paths and forbidden actions before mutation. +- [x] PRD separates operator acceptance or rejection from test pass. +- [x] PRD forbids push, merge, deploy, close, PR open, issue close, public publication, critical repository mutation, unowned repository mutation, Case source mutation, vendor source mutation, Hermes WebUI mutation, and Cortex Core mutation. +- [x] PRD requires full Harness Evidence Interface artifacts. +- [x] PRD requires approval-denied, unowned-repository, critical-repository, disallowed-file, dirty-starting-tree, dirty-ending-tree, failed-tests, timeout, provider-unavailable, and missing-operator-outcome failure fixtures. +- [x] Local CTO validator checks Stage 5 PRD and issue artifact. + +Allowed files: CTO child workspace planning docs and local validator only. + +Validator: `python3 tools/validate_cto_child.py` + +Done evidence: PRD, issue artifact, validator JSON, clean worktree, commit. + +### CTO-WORK-038 - Stage 5 Harness Owned Noncritical Repo Route + +Type: HITL + +Status: blocked. + +Blocked by: CTO-WORK-037 and explicit JP selection or approval of an owned low-risk noncritical Target Repository. + +User stories covered: CTO Case Candidate Backend PRD stories 4, 5, 7, 8, 9, 10, 11, 13. + +What to build: In `/home/svrnty/workspaces/hermes/cto/harness`, implement the Stage 5 owned noncritical repository route behind the existing `case` engine seam. + +Acceptance criteria: + +- [ ] `case` remains disabled by default. +- [ ] `CTO_HARNESS_ALLOW_CASE=1` remains required. +- [ ] `CTO_HARNESS_CASE_STAGE=5` is required before owned noncritical repository execution. +- [ ] Missing Stage 5 gate emits blocked evidence and does not run Case. +- [ ] Target Repository admission proof records owner, path, noncritical classification, allowed paths, forbidden actions, and approval source. +- [ ] Unowned or critical repository admission blocks before mutation. +- [ ] Approval denied blocks before mutation. +- [ ] Approval granted is recorded before mutation. +- [ ] Case mutates only allowed paths inside the admitted Target Repository. +- [ ] No push, merge, deploy, close, PR open, issue close, or public publication occurs by default. +- [ ] Operator acceptance or rejection is recorded after verification. +- [ ] Required artifacts include Target Repository admission proof, approval proof, allowed-path proof, forbidden-action proof, operator outcome, `report.json`, `report.md`, `events.normalized.jsonl`, `trace.jsonl`, `patch.diff`, `test.log`, backend logs, artifact digests, and freshness proof. +- [ ] Failure fixtures fail closed for approval denied, unowned repository, critical repository, disallowed file, dirty starting tree, dirty ending tree, failed tests, timeout, provider unavailable, and missing operator outcome. +- [ ] Fake remains the default validation lane and broad health remains green after focused Stage 5 validation. + +Allowed files: Hermes CTO harness engine, owned noncritical repo fixture admission records, focused Stage 5 validator, harness docs, and tests. WebUI, Core, Case source, vendor source, unowned repositories, critical repositories, production repositories, and external developer repositories are forbidden. + +Validator: `python3 harness/runner/validate-case-stage5.py --harness-root harness --json`, then `harness/evals/health.sh --json`. + +Done evidence: Stage 5 pass report, failure fixture reports, Target Repository admission proof, approval proof, allowed-path proof, forbidden-action proof, operator outcome, artifact digests, clean worktree, commit. + +## Granularity Check + +This is intentionally two slices: one planning route and one executable harness route. Stage 5 is not over-granular because it is the first proof involving an admitted owned repository and must separate repository ownership, approval, allowed paths, verification, and operator outcome before default candidacy. diff --git a/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md b/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md new file mode 100644 index 0000000..09b542e --- /dev/null +++ b/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md @@ -0,0 +1,95 @@ +--- +name: cto-case-stage5-owned-noncritical-repo-prd +tier: local +status: draft +owner: jp +source: .sot/03-PROTOCOLS/CTO-CASE-STAGED-PROOF-GATES.md +created: 2026-06-01 +last_reviewed: 2026-06-01 +lifecycle_classification: planning +core_promotion_status: not-promoted +description: Child-local PRD for Stage 5 Case owned noncritical repository proof. +--- + +# CTO Case Stage 5 Owned Noncritical Repository PRD + +Local planning SOT only. Not a Core Protocol. Not active Core authority. + +## Problem Statement + +Stage 4 proves Case can change a disposable sandbox repository after approval. The next proof must show whether Case can safely work in an explicitly owned, low-risk, noncritical repository without expanding authority, bypassing approval, or treating a green test run as operator acceptance. + +## Solution + +Add Stage 5 planning for an owned noncritical repository route behind the existing CTO Harness `case` seam. Stage 5 allowed mutation scope is `explicitly owned low-risk repository only`. Case may execute only when Stage 4 is validated, the Target Repository admission record proves ownership and noncritical status, JP approval is recorded, allowed paths are explicit, and the Harness records full evidence. + +## Scope + +- Define Stage 5 entry gates, non-goals, acceptance criteria, validation, risks, dependencies, and success definition. +- Require `CTO_HARNESS_ALLOW_CASE=1` and `CTO_HARNESS_CASE_STAGE=5` before owned repository execution. +- Require explicit Target Repository ownership proof and noncritical classification. +- Require allowed paths and forbidden actions before mutation. +- Require approval requested/granted/denied events before mutation. +- Require operator acceptance or rejection after the run. +- Require full Harness Evidence Interface artifacts. +- Keep fake as the default validation lane. + +## Non-Goals + +- Do not make Case the default backend. +- Do not authorize production, critical, customer, vendor, external developer, or unowned repository mutation. +- Do not authorize push, merge, deploy, close, PR open, public publication, or issue closure by default. +- Do not mutate Cortex Core, Hermes WebUI, Case source, vendor source, or external repositories. +- Do not treat test pass as operator acceptance. +- Do not promote child-local planning into Core. + +## User Stories + +1. As JP, I want Case tested in an owned noncritical repository, so that real-repo risk is proven before default candidacy. +2. As Cortex, I want ownership and noncritical classification recorded, so that execution never targets unknown repositories. +3. As Hermes, I want approval and replay evidence, so that every mutation is visible and reversible. +4. As CTO Harness, I want allowed paths and forbidden actions encoded before execution, so that Case cannot widen scope conversationally. +5. As an operator, I want post-run acceptance or rejection separated from test pass, so that proof and approval remain distinct. + +## Acceptance Criteria + +- [ ] Stage 5 requires Stage 4 validation evidence before execution. +- [ ] Stage 5 allowed mutation scope is `explicitly owned low-risk repository only`. +- [ ] `CTO_HARNESS_ALLOW_CASE=1` remains required. +- [ ] `CTO_HARNESS_CASE_STAGE=5` is required before owned noncritical repository execution. +- [ ] Missing Stage 5 gate emits blocked evidence and does not run Case. +- [ ] Target Repository admission records owner, repository path, noncritical classification, allowed paths, forbidden actions, and approval source. +- [ ] Approval denied blocks before mutation. +- [ ] Approval granted is recorded before mutation. +- [ ] Case mutates only allowed paths inside the admitted Target Repository. +- [ ] No push, merge, deploy, close, PR open, issue close, or public publication occurs by default. +- [ ] Operator acceptance or rejection is recorded after verification. +- [ ] Required artifacts include Target Repository admission proof, approval proof, allowed-path proof, forbidden-action proof, operator outcome, `report.json`, `report.md`, `events.normalized.jsonl`, `trace.jsonl`, `patch.diff`, `test.log`, backend logs, artifact digests, and freshness proof. +- [ ] Failure fixtures fail closed for approval denied, unowned repository, critical repository, disallowed file, dirty starting tree, dirty ending tree, failed tests, timeout, provider unavailable, and missing operator outcome. + +## Validation + +Planning validator: `python3 tools/validate_cto_child.py`. + +Implementation validator planned for Hermes: `python3 harness/runner/validate-case-stage5.py --harness-root harness --json`, then `harness/evals/health.sh --json` after focused Stage 5 validation passes. + +## Risks + +- Owned repository proof may be mistaken for default backend readiness. +- Operator acceptance may be blurred with test pass. +- Allowed paths may be too broad and hide real-repo risk. +- Local repository state may be dirty before execution. +- Provider instability may obscure Harness policy failures. + +## Dependencies + +- Stage 4 disposable sandbox proof is validated. +- Harness Evidence Interface contract remains active. +- Case source admission record remains current. +- Case adapter contract remains active. +- Failure fixture matrix remains active. +- JP selects or approves an owned low-risk noncritical Target Repository before execution. + +## Success Definition + +Stage 5 is successful when Case changes only approved paths inside an explicitly owned low-risk noncritical repository, records approval before mutation, records operator acceptance or rejection after verification, preserves Harness evidence, and fails closed for missing ownership, missing approval, disallowed paths, dirty repository state, provider failure, or missing operator outcome. diff --git a/.sot/03-PROTOCOLS/CTO-CASE-STAGED-PROOF-GATES.md b/.sot/03-PROTOCOLS/CTO-CASE-STAGED-PROOF-GATES.md index 7fa2298..4f43480 100644 --- a/.sot/03-PROTOCOLS/CTO-CASE-STAGED-PROOF-GATES.md +++ b/.sot/03-PROTOCOLS/CTO-CASE-STAGED-PROOF-GATES.md @@ -240,6 +240,8 @@ Promotion condition: ## Stage 5 - Owned Noncritical Repo +Status: planned. Execution remains blocked until `CTO-WORK-038` produces Harness Evidence Interface pass evidence after explicit JP selection or approval of an owned low-risk noncritical Target Repository. + Entry gates: - Stage 4 is validated. @@ -258,6 +260,11 @@ Required artifacts: - allowed paths and forbidden actions; - post-run operator acceptance or rejection. +Planning evidence: + +- Stage 5 PRD: `.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md`. +- Stage 5 issues: `.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md`. + Validator expectation: - mutation stays inside allowed paths; diff --git a/README.md b/README.md index 86ced06..314b5ef 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ This workspace is registered as a child-local planning workspace. Registration d | |-- CTO-CASE-STAGE3-COPIED-REPO-ISSUES.md | |-- CTO-CASE-STAGE4-DISPOSABLE-SANDBOX-PRD.md | |-- CTO-CASE-STAGE4-DISPOSABLE-SANDBOX-ISSUES.md +| |-- CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md +| |-- CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md | |-- CTO-CASE-PROVIDER-ADMISSION-PRD.md | |-- CTO-CASE-PROVIDER-ADMISSION-ISSUES.md | |-- CTO-CASE-PROVIDER-BUILD-PRD.md diff --git a/WORKBOARD.yaml b/WORKBOARD.yaml index a42d42b..e5e94cd 100644 --- a/WORKBOARD.yaml +++ b/WORKBOARD.yaml @@ -180,3 +180,13 @@ items: status: validated source: .sot/03-PROTOCOLS/CTO-CASE-STAGE4-DISPOSABLE-SANDBOX-ISSUES.md owner: "" + - id: CTO-WORK-037 + title: Stage 5 Owned Noncritical Repo PRD + status: validated + source: .sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md + owner: "" + - id: CTO-WORK-038 + title: Stage 5 Harness Owned Noncritical Repo Route + status: blocked + source: .sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md + owner: jp diff --git a/tools/validate_cto_child.py b/tools/validate_cto_child.py index 90b6420..8058a87 100644 --- a/tools/validate_cto_child.py +++ b/tools/validate_cto_child.py @@ -32,6 +32,8 @@ REQUIRED_FILES = [ ".sot/03-PROTOCOLS/CTO-CASE-STAGE3-COPIED-REPO-ISSUES.md", ".sot/03-PROTOCOLS/CTO-CASE-STAGE4-DISPOSABLE-SANDBOX-PRD.md", ".sot/03-PROTOCOLS/CTO-CASE-STAGE4-DISPOSABLE-SANDBOX-ISSUES.md", + ".sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md", + ".sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-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", @@ -313,6 +315,25 @@ REQUIRED_STAGE4_ISSUE_IDS = [ "CTO-WORK-036", ] +REQUIRED_STAGE5_PRD_PHRASES = [ + "Local planning SOT only. Not a Core Protocol. Not active Core authority.", + "Stage 5 allowed mutation scope is `explicitly owned low-risk repository only`.", + "CTO_HARNESS_ALLOW_CASE=1", + "CTO_HARNESS_CASE_STAGE=5", + "Target Repository ownership proof and noncritical classification", + "approval requested/granted/denied events before mutation", + "allowed paths and forbidden actions before mutation", + "Operator acceptance or rejection is recorded after verification.", + "No push, merge, deploy, close, PR open, issue close, or public publication occurs by default.", + "approval denied, unowned repository, critical repository, disallowed file, dirty starting tree, dirty ending tree, failed tests, timeout, provider unavailable, and missing operator outcome", + "Stage 5 is successful when Case changes only approved paths inside an explicitly owned low-risk noncritical repository", +] + +REQUIRED_STAGE5_ISSUE_IDS = [ + "CTO-WORK-037", + "CTO-WORK-038", +] + REQUIRED_PROVIDER_ADMISSION_PRD_PHRASES = [ "Local planning SOT only. Not a Core Protocol. Not active Core authority.", "https://github.com/workos/case.git", @@ -953,6 +974,28 @@ def main() -> int: if issue_id not in text: errors.append(f"missing_stage4_issue_id:{issue_id}") + stage5_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md" + if stage5_prd.is_file(): + text = stage5_prd.read_text(encoding="utf-8") + if "core_promotion_status: not-promoted" not in text: + errors.append("stage5_prd_missing_not_promoted_frontmatter") + for phrase in REQUIRED_STAGE5_PRD_PHRASES: + checked.append(f"stage5_prd_phrase:{phrase}") + if phrase not in text: + errors.append(f"missing_stage5_prd_phrase:{phrase}") + + stage5_issues = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md" + if stage5_issues.is_file(): + text = stage5_issues.read_text(encoding="utf-8") + if "core_promotion_status: not-promoted" not in text: + errors.append("stage5_issues_missing_not_promoted_frontmatter") + if "Local planning SOT only. Not a Core Protocol. Not active Core authority." not in text: + errors.append("stage5_issues_missing_local_planning_notice") + for issue_id in REQUIRED_STAGE5_ISSUE_IDS: + checked.append(f"stage5_issue_id:{issue_id}") + if issue_id not in text: + errors.append(f"missing_stage5_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") @@ -1152,6 +1195,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_STAGE5_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: @@ -1205,6 +1252,8 @@ def main() -> int: "CTO-WORK-034": "validated", "CTO-WORK-035": "validated", "CTO-WORK-036": "validated", + "CTO-WORK-037": "validated", + "CTO-WORK-038": "blocked", } for issue_id, expected in expected_statuses.items(): checked.append(f"workboard_status:{issue_id}:{expected}") @@ -1239,6 +1288,10 @@ def main() -> int: errors.append("workboard_missing_stage4_prd_source") if "CTO-CASE-STAGE4-DISPOSABLE-SANDBOX-ISSUES.md" not in text: errors.append("workboard_missing_stage4_issues_source") + if "CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md" not in text: + errors.append("workboard_missing_stage5_prd_source") + if "CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md" not in text: + errors.append("workboard_missing_stage5_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: