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 index 746d817..93e2fab 100644 --- a/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md +++ b/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md @@ -55,7 +55,7 @@ Type: HITL Status: blocked. -Blocked by: CTO-WORK-037 and explicit JP selection or approval of an owned low-risk noncritical Target Repository. +Blocked by: CTO-WORK-037, CTO-WORK-039, 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. @@ -84,6 +84,34 @@ Validator: `python3 harness/runner/validate-case-stage5.py --harness-root harnes 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. + +### CTO-WORK-039 - Stage 5 Target Repository Admission Template + +Type: AFK + +Status: validated. + +Blocked by: CTO-WORK-037 + +User stories covered: CTO Case Candidate Backend PRD stories 4, 5, 7, 8, 9, 10, 11, 13. + +What to build: Define the validator-readable Target Repository admission template required before Stage 5 can execute against any owned noncritical repository. + +Acceptance criteria: + +- [x] Template states it does not admit any repository. +- [x] Template requires `admission_status`, `target_repository_path`, `repository_owner`, `ownership_evidence`, `risk_classification`, `noncritical_rationale`, `allowed_paths`, `forbidden_paths`, `forbidden_actions`, `approval_source`, `approval_timestamp`, `operator_outcome_required`, and `review_trigger`. +- [x] Template requires `risk_classification` to be `low_risk_noncritical`. +- [x] Template requires missing admission, missing ownership evidence, critical classification, empty allowed paths, missing forbidden actions, missing approval, and missing operator outcome requirement to block before `case_process_started`. +- [x] Template forbids treating the template as Case execution authority. +- [x] Local CTO validator checks the template artifact. + +Allowed files: CTO child workspace planning docs and local validator only. + +Validator: `python3 tools/validate_cto_child.py` + +Done evidence: template artifact, issue reference, validator JSON, 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-TARGET-REPOSITORY-ADMISSION-TEMPLATE.md b/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.md new file mode 100644 index 0000000..427094c --- /dev/null +++ b/.sot/03-PROTOCOLS/CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.md @@ -0,0 +1,94 @@ +--- +name: cto-case-stage5-target-repository-admission-template +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 Stage 5 Target Repository admission template. This template does not admit any repository. +--- + +# CTO Case Stage 5 Target Repository Admission Template + +Local planning SOT only. Not a Core Protocol. Not active Core authority. + +## Status + +This artifact is a template only. No Target Repository is admitted by this file. Stage 5 execution remains blocked until JP records a concrete admission record using this template and the Harness validates it. + +## Purpose + +Stage 5 needs a precise human decision before Case may touch an owned repository. This template converts that decision into validator-readable fields without storing secrets, credentials, or broad repository authority. + +## Required Admission Fields + +- `admission_status`: `admitted` or `not_admitted`. +- `target_repository_path`: absolute local path, recorded only in the concrete admission record. +- `repository_owner`: human or organization owner. +- `ownership_evidence`: compact reference proving JP controls or is authorized to mutate the repository. +- `risk_classification`: must be `low_risk_noncritical`. +- `noncritical_rationale`: why this repository is safe for Stage 5. +- `allowed_paths`: explicit file or directory paths Case may mutate. +- `forbidden_paths`: explicit paths Case must not mutate. +- `forbidden_actions`: must include push, merge, deploy, close, PR open, issue close, public publication, credential change, vendor-source mutation, and Cortex Core mutation. +- `approval_source`: JP approval reference. +- `approval_timestamp`: timestamp or date of approval. +- `operator_outcome_required`: must be `true`. +- `review_trigger`: condition that invalidates the admission. + +## Required Negative Gates + +- Missing admission record blocks before `case_process_started`. +- `admission_status != admitted` blocks before `case_process_started`. +- Missing ownership evidence blocks before `case_process_started`. +- `risk_classification != low_risk_noncritical` blocks before `case_process_started`. +- Empty `allowed_paths` blocks before `case_process_started`. +- Missing forbidden action blocks before `case_process_started`. +- Missing approval source blocks before `case_process_started`. +- Missing operator outcome requirement blocks before `case_process_started`. + +## Concrete Record Skeleton + +```json +{ + "admission_status": "not_admitted", + "target_repository_path": "", + "repository_owner": "", + "ownership_evidence": "", + "risk_classification": "", + "noncritical_rationale": "", + "allowed_paths": [], + "forbidden_paths": [], + "forbidden_actions": [ + "push", + "merge", + "deploy", + "close", + "pr_open", + "issue_close", + "public_publication", + "credential_change", + "vendor_source_mutation", + "cortex_core_mutation" + ], + "approval_source": "", + "approval_timestamp": "", + "operator_outcome_required": true, + "review_trigger": "" +} +``` + +## Non-Admission Rules + +- This template does not admit a Target Repository. +- This template does not authorize Case execution. +- This template does not authorize owned repository mutation. +- This template does not authorize default backend candidacy. +- This template does not authorize push, merge, deploy, close, PR open, issue close, or public publication. + +## Validator Expectation + +The local CTO validator must require this template before Stage 5 execution planning can proceed. Hermes Stage 5 implementation must later validate a concrete admission record separately. diff --git a/README.md b/README.md index 314b5ef..5fe61fa 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ This workspace is registered as a child-local planning workspace. Registration d | |-- 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-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.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 e5e94cd..92f8740 100644 --- a/WORKBOARD.yaml +++ b/WORKBOARD.yaml @@ -190,3 +190,8 @@ items: status: blocked source: .sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md owner: jp + - id: CTO-WORK-039 + title: Stage 5 Target Repository Admission Template + status: validated + source: .sot/03-PROTOCOLS/CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.md + owner: "" diff --git a/tools/validate_cto_child.py b/tools/validate_cto_child.py index 8058a87..d1416b7 100644 --- a/tools/validate_cto_child.py +++ b/tools/validate_cto_child.py @@ -34,6 +34,7 @@ REQUIRED_FILES = [ ".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-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.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", @@ -332,6 +333,26 @@ REQUIRED_STAGE5_PRD_PHRASES = [ REQUIRED_STAGE5_ISSUE_IDS = [ "CTO-WORK-037", "CTO-WORK-038", + "CTO-WORK-039", +] + +REQUIRED_STAGE5_TARGET_ADMISSION_TEMPLATE_PHRASES = [ + "Local planning SOT only. Not a Core Protocol. Not active Core authority.", + "This artifact is a template only. No Target Repository is admitted by this file.", + "Stage 5 execution remains blocked until JP records a concrete admission record", + "admission_status", + "target_repository_path", + "repository_owner", + "ownership_evidence", + "risk_classification", + "low_risk_noncritical", + "allowed_paths", + "forbidden_actions", + "approval_source", + "operator_outcome_required", + "Missing admission record blocks before `case_process_started`.", + "This template does not authorize Case execution.", + "This template does not authorize owned repository mutation.", ] REQUIRED_PROVIDER_ADMISSION_PRD_PHRASES = [ @@ -996,6 +1017,16 @@ def main() -> int: if issue_id not in text: errors.append(f"missing_stage5_issue_id:{issue_id}") + stage5_target_admission_template = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.md" + if stage5_target_admission_template.is_file(): + text = stage5_target_admission_template.read_text(encoding="utf-8") + if "core_promotion_status: not-promoted" not in text: + errors.append("stage5_target_admission_template_missing_not_promoted_frontmatter") + for phrase in REQUIRED_STAGE5_TARGET_ADMISSION_TEMPLATE_PHRASES: + checked.append(f"stage5_target_admission_template_phrase:{phrase}") + if phrase not in text: + errors.append(f"missing_stage5_target_admission_template_phrase:{phrase}") + 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") @@ -1254,6 +1285,7 @@ def main() -> int: "CTO-WORK-036": "validated", "CTO-WORK-037": "validated", "CTO-WORK-038": "blocked", + "CTO-WORK-039": "validated", } for issue_id, expected in expected_statuses.items(): checked.append(f"workboard_status:{issue_id}:{expected}") @@ -1292,6 +1324,8 @@ def main() -> int: 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-STAGE5-TARGET-REPOSITORY-ADMISSION-TEMPLATE.md" not in text: + errors.append("workboard_missing_stage5_target_admission_template_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: