Add Stage 5 target repository admission template

This commit is contained in:
Svrnty 2026-05-31 23:46:22 -04:00
parent 51977d36cd
commit f8a6d6873d
5 changed files with 163 additions and 1 deletions

View File

@ -55,7 +55,7 @@ Type: HITL
Status: blocked. 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. 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. 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 ## 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. 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.

View File

@ -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.

View File

@ -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-STAGE4-DISPOSABLE-SANDBOX-ISSUES.md
| |-- CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md | |-- CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-PRD.md
| |-- CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.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-PRD.md
| |-- CTO-CASE-PROVIDER-ADMISSION-ISSUES.md | |-- CTO-CASE-PROVIDER-ADMISSION-ISSUES.md
| |-- CTO-CASE-PROVIDER-BUILD-PRD.md | |-- CTO-CASE-PROVIDER-BUILD-PRD.md

View File

@ -190,3 +190,8 @@ items:
status: blocked status: blocked
source: .sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md source: .sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md
owner: jp 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: ""

View File

@ -34,6 +34,7 @@ REQUIRED_FILES = [
".sot/03-PROTOCOLS/CTO-CASE-STAGE4-DISPOSABLE-SANDBOX-ISSUES.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-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.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-PRD.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-ISSUES.md", ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-ISSUES.md",
".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-BUILD-PRD.md", ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-BUILD-PRD.md",
@ -332,6 +333,26 @@ REQUIRED_STAGE5_PRD_PHRASES = [
REQUIRED_STAGE5_ISSUE_IDS = [ REQUIRED_STAGE5_ISSUE_IDS = [
"CTO-WORK-037", "CTO-WORK-037",
"CTO-WORK-038", "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 = [ REQUIRED_PROVIDER_ADMISSION_PRD_PHRASES = [
@ -996,6 +1017,16 @@ def main() -> int:
if issue_id not in text: if issue_id not in text:
errors.append(f"missing_stage5_issue_id:{issue_id}") 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" provider_admission_prd = ROOT / ".sot/03-PROTOCOLS/CTO-CASE-PROVIDER-ADMISSION-PRD.md"
if provider_admission_prd.is_file(): if provider_admission_prd.is_file():
text = provider_admission_prd.read_text(encoding="utf-8") text = provider_admission_prd.read_text(encoding="utf-8")
@ -1254,6 +1285,7 @@ def main() -> int:
"CTO-WORK-036": "validated", "CTO-WORK-036": "validated",
"CTO-WORK-037": "validated", "CTO-WORK-037": "validated",
"CTO-WORK-038": "blocked", "CTO-WORK-038": "blocked",
"CTO-WORK-039": "validated",
} }
for issue_id, expected in expected_statuses.items(): for issue_id, expected in expected_statuses.items():
checked.append(f"workboard_status:{issue_id}:{expected}") checked.append(f"workboard_status:{issue_id}:{expected}")
@ -1292,6 +1324,8 @@ def main() -> int:
errors.append("workboard_missing_stage5_prd_source") errors.append("workboard_missing_stage5_prd_source")
if "CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md" not in text: if "CTO-CASE-STAGE5-OWNED-NONCRITICAL-REPO-ISSUES.md" not in text:
errors.append("workboard_missing_stage5_issues_source") 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: if "CTO-CASE-PROVIDER-ADMISSION-PRD.md" not in text:
errors.append("workboard_missing_provider_admission_prd_source") errors.append("workboard_missing_provider_admission_prd_source")
if "CTO-CASE-PROVIDER-ADMISSION-ISSUES.md" not in text: if "CTO-CASE-PROVIDER-ADMISSION-ISSUES.md" not in text: