Files
company-haness/docs/superpowers/plans/2026-07-13-p3-unified-role-method-contract.md
T

504 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 통합 P3 (A 구조 인프라 + B 계약 강화) Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 에이전트 절차를 (A) 카드→skill로 분리하고 (B) 실행 가능한 업무 계약(Contract v2)으로 강화한다. 하나의 브랜치·하나의 Contract v2·하나의 최종 cutover. 75역할 wave 이행, 참조 profile all-active.
**Architecture:** `role-working-methods/`(파일분리 SoT, Contract v2 다중 profile) → `gen_method_skills.py`(v1/v2 dual) → method-skill → 카드 skills. 런타임: context-package `method-selection``method_contracts.py`(공용 policy engine)가 프로필 해석·handoff·execution 검증. 강제: validate_report(step-results 증명) + spawn/transition 2지점 handoff gate + activation registry(trusted CLI).
**Tech Stack:** Python 3(stdlib+PyYAML), 기존 하네스 hook 패턴. 테스트=standalone `check()`(pytest 아님), `run_all.py` 자동발견.
**Specs:** `docs/superpowers/specs/2026-07-13-p3-prompt-skill-separation-design.md`(A), `docs/superpowers/specs/2026-07-13-p3b-role-method-contract-design.md`(B v2.1). B가 상위 — Phase 순서·계약 구조는 B spec 기준.
## Global Constraints
- **하나의 브랜치·최종 1회 cutover**: `feat/p3-prompt-skill-separation`. 카드/skill은 wave마다 재생성, 최종 cutover 1회. v1 flat은 브랜치 내부 migration용(최종 merge엔 없어도 됨).
- **품질 중립(A) vs 강화(B) 분리**: A(카드→skill 위치 이동)는 내용 불변. B(계약)는 내용 강화 — 단 wave·enforcement-status로 회귀 없이 점진.
- **공용 policy engine 단일 지점**: 정책 해석은 `method_contracts.py` 한 곳. 강제 시점만 3곳(context_package/subagent_register spawn, state_engine transition, validate_report). 별도 로직 복제 금지.
- **SoT/runtime 분리**: `role-working-methods/`는 방법론 SoT — runtime이 수정 금지. 활성화는 `method-contract-activations.yaml`(trusted CLI `activate_method_contract.py`만 write, guard_tools 강제).
- **자기신고 금지**: method-execution step-results는 artifact/evidence/receipt hash로 증명. completed step은 required-output 실존, skipped는 허용 skip-rule 일치.
- **machine vs judgment**: completion-gate·prohibited은 `enforcement: hard|warning|instructional`. machine-check 연결만 자동 Hard Fail, 자연어는 judgment/self-check(오탐 방지).
- **method-selection**: standard/heavy 필수(auto-infer 금지), light 유일후보만. 보고서 method-id == context-package 선택 method.
- **handoff = profile-to-profile edge**: from/to {role-id, method-id}·cardinality·schema-ref·required-state·binding·freshness. spawn·transition gate 동일 판정.
- **hash 규약**: `contract-sha256`=정규화 계약 YAML hash(skill md 아님). capability는 section-sha256. historical-valid(감사 유지) vs current-usable(현 active와 hash 일치해야 후속 입력).
- **enforcement-status**: draft(warning·trace만) / active(standard·heavy Hard Fail, 양쪽 active면 handoff hard gate) / retired(fallback 금지). draft→active는 golden+HUMAN acceptance.
- **불변 개수**: 에이전트 72·역할 75. 실행 환경: `CLAUDE_PROJECT_DIR="$PWD" ORGOS_WORKSPACE=_sandbox`. 커밋 trailer `Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>`. 커밋 전 `git checkout -- .claude/tests/fixtures/`.
## Phase 맵 (B spec §3)
| Phase | 산출(테스트 가능 단위) | 태스크 |
|---|---|---|
| **0** | auto-load probe → generated-dir 확정 | T0 |
| **1** | Contract v2 스키마 + 파일분리 + gate/artifact vocabulary | T1.1T1.3 |
| **2** | P3-A 인프라(registry·gen v1/v2·gen_agents·ref/orphan/drift) | T2.1T2.5 |
| **3** | method_contracts.py policy engine + method-selection + activation(CLI·hash) | T3.1T3.4 |
| **4** | Enforcement(validate_report·spawn gate·transition gate·debt) | T4.1T4.4 |
| **5** | 대표 역할 계약 + golden task + active 승격 | T5(템플릿)×대표군 |
| **6** | family wave 25 이행 | T6(wave 반복) |
| **7** | cutover(참조 profile all-active·debt 0·v1 제거·재생성) | T7 |
**Phase 04 = 계약 machinery(완전 코드).** 계약 0개여도 v1 fallback으로 green. **Phase 57 = 계약 authoring(반복 템플릿+게이트).**
---
## File Structure
**신설:**
- `org-os/00-role-registry/role-working-methods/{index.yaml, executive.yaml, product.yaml, design.yaml, architecture.yaml, engineering.yaml, platform-security-data.yaml, gtm-operations.yaml, consulting-documentation.yaml}` — 파일분리 SoT(v1 이행 + v2 계약).
- `org-os/00-role-registry/method-skill-registry.yaml` — role→method-skill 배선(A).
- `org-os/00-role-registry/method-contract-activations.yaml` — 활성화 registry.
- `org-os/06-agent-work/artifact-type-vocabulary.yaml` — artifact-type·handoff 어휘.
- `.claude/hooks/method_contracts.py` — 공용 policy engine.
- `.claude/hooks/gen_method_skills.py` — v1/v2 dual 렌더 + `--check`.
- `.claude/hooks/skill_refs.py` — skill 참조 헬퍼.
- `.claude/hooks/activate_method_contract.py` — activation trusted CLI.
- `.claude/schemas/method-execution.schema.json` — trace 스키마(공통 report additive).
- `.claude/skills/generated/<role>-method/SKILL.md` — 생성물.
- `.claude/tests/test_p3_infra.py`, `test_p3b_contracts.py`, `test_p3b_enforcement.py` — 강제기.
- `<ws>/state/method-contract-debt.jsonl` — debt event 원장(런타임 산출).
**개정:**
- `.claude/hooks/gen_agents.py`(spine+registry skills), `validate_report.py`(method-execution), `state_engine.py`(transition handoff gate), `context_package.py`+`subagent_register.py`(spawn gate·method-selection), `doctor.py`(P3 배선), `lint_refs.py`(skills 참조), `guard_tools.py`(activation write 차단).
- `.claude/skills/design-craft/SKILL.md`(capability-sections manifest), `CLAUDE.md`.
---
## Phase 0 — Baseline + skill auto-load probe (load-bearing)
### Task 0: auto-load probe → generated-dir 확정
**Files:** (임시 probe — 커밋 안 함)
런타임 동작 검증이라 pytest 아님 — controller가 live subagent로 실측.
- [ ] **Step 1: probe skill + agent 생성**
```bash
mkdir -p .claude/skills/generated/probe-method
printf -- '---\nname: probe-method\ndescription: Use when the user says PROBE-P3.\n---\n# Probe\nReply exactly: PROBE-LOADED-OK-7F3A\n' > .claude/skills/generated/probe-method/SKILL.md
printf -- '---\nname: probe-p3\ndescription: P3 phase-0 probe.\ntools: Read\nmodel: inherit\nskills: [probe-method]\n---\nprobe-method skill 지시를 따르세요.\n' > .claude/agents/probe-p3.md
```
- [ ] **Step 2: controller가 probe-p3 서브에이전트를 "PROBE-P3"로 dispatch.** sentinel `PROBE-LOADED-OK-7F3A` 반환 → 중첩 auto-load 확인.
- [ ] **Step 3: 레이아웃 확정 + 제거**
- 반환 O → `generated-dir: .claude/skills/generated`.
- 반환 X → flat 폴백 `generated-dir: .claude/skills`(이름 규약 `<role>-method`).
- ledger에 결과 기록. `rm -rf .claude/skills/generated/probe-method .claude/agents/probe-p3.md`.
- [ ] **Step 4: baseline 회귀 기준 기록**: `run_all.py` green·`doctor` OK·agents 72·roles 75를 ledger에 스냅샷.
---
## Phase 1 — Contract v2 스키마 + 파일분리 + vocabulary
### Task 1.1: role-working-methods 파일분리 + index (v1 이행)
**Files:**
- Create: `org-os/00-role-registry/role-working-methods/index.yaml` + 8 family 파일
- Test: `.claude/tests/test_p3_infra.py`
**Interfaces:**
- Produces: `load_role_methods()` 규약 — index.includes를 병합해 `{role-id: entry}` 반환. 중복/누락/미include=에러.
- [ ] **Step 1: 실패 테스트**
`.claude/tests/test_p3_infra.py`(신규, 헤더 + 첫 check):
```python
#!/usr/bin/env python3
"""P3 인프라 강제기 — standalone check(pytest 아님). exit 0=통과."""
import glob, importlib.util, os, sys, yaml
ROOT = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
REG = os.path.join(ROOT, "org-os", "00-role-registry")
RWM_DIR = os.path.join(REG, "role-working-methods")
passed = failed = 0
def check(name, ok):
global passed, failed
if ok: passed += 1; print(f" ✅ {name}")
else: failed += 1; print(f" ❌ {name}")
def load_role_methods():
idx = yaml.safe_load(open(os.path.join(RWM_DIR, "index.yaml")))["role-method-contracts"]
merged, srcs = {}, {}
for inc in idx["includes"]:
d = yaml.safe_load(open(os.path.join(RWM_DIR, inc))) or {}
for rid, entry in (d.get("role-working-methods") or {}).items():
assert rid not in merged, f"중복 role-id {rid} ({srcs.get(rid)} & {inc})"
merged[rid] = entry; srcs[rid] = inc
files_on_disk = {os.path.basename(p) for p in glob.glob(os.path.join(RWM_DIR, "*.yaml"))} - {"index.yaml"}
assert files_on_disk == set(idx["includes"]), f"미include/유령 파일: {files_on_disk ^ set(idx['includes'])}"
return merged
_rm = load_role_methods()
_fams = yaml.safe_load(open(os.path.join(REG, "capability-families.yaml")))["capability-families"]["families"]
_bound = set()
for f in _fams: _bound |= set(f["member-role-ids"])
check("파일분리 병합 75역할·중복0·미include0", set(_rm) == _bound and len(_rm) == 75)
```
- [ ] **Step 2: 실패 확인** — Run: `CLAUDE_PROJECT_DIR="$PWD" python3 .claude/tests/test_p3_infra.py` → FAIL(디렉터리 없음).
- [ ] **Step 3: 기존 `role-working-methods.yaml`을 family별로 분할**
`index.yaml`:
```yaml
role-method-contracts:
version: 2
includes: [executive.yaml, product.yaml, design.yaml, architecture.yaml, engineering.yaml, platform-security-data.yaml, gtm-operations.yaml, consulting-documentation.yaml]
```
분할 매핑(family→파일): executive=EXEC-*·OPS-ORCH·STR-ANALYST; product=PROD-*·UX-RESEARCHER·DATA-ANALYST; design=DES-*; architecture=ARCH-*; engineering=ENG-*; platform-security-data=INFRA-*·SRE·SEC-*·DATA-ENGINEER·DATA-BIGDATA·QA; gtm-operations=GTM-*·OPS-CH·OPS-CREW; consulting-documentation=CONSULT-*·DOC-*. 각 파일 최상위 키 `role-working-methods:` 아래 기존 v1 엔트리(working-method/key-frameworks/evidence-they-use/sources) 그대로 이동(내용 불변). 분할은 스크립트로:
```python
# scratchpad/split_rwm.py — 기존 단일 파일을 family별로 분할(1회)
import yaml, os
src = yaml.safe_load(open("org-os/00-role-registry/role-working-methods.yaml"))["role-working-methods"]
fams = yaml.safe_load(open("org-os/00-role-registry/capability-families.yaml"))["capability-families"]["families"]
GROUP = { # family-id -> 파일
**{f: "executive.yaml" for f in ["FAM-CEO","FAM-CTO","FAM-CPO","FAM-CFO","FAM-COO","FAM-CPTO","FAM-VPENG","FAM-ORCH","FAM-STRATEGY"]},
**{f: "product.yaml" for f in ["FAM-PRODUCT-MGMT","FAM-UX-RESEARCH"]},
"FAM-DESIGN":"design.yaml",
**{f: "architecture.yaml" for f in ["FAM-ARCHITECTURE-TECH","FAM-ARCHITECTURE-BIZ"]},
**{f: "engineering.yaml" for f in ["FAM-ENG-BACKEND","FAM-ENG-FRONTEND","FAM-ENG-SPECIAL"]},
**{f: "platform-security-data.yaml" for f in ["FAM-PLATFORM-INFRA","FAM-SECURITY","FAM-DATA","FAM-QA"]},
**{f: "gtm-operations.yaml" for f in ["FAM-GTM-GROWTH","FAM-GTM-SALES","FAM-REVOPS","FAM-LEGAL","FAM-OPS-DELIVERY"]},
**{f: "consulting-documentation.yaml" for f in ["FAM-CONSULTING","FAM-DOC-CONSULT"]},
}
buckets = {}
for f in fams:
fn = GROUP[f["family-id"]]
for rid in f["member-role-ids"]:
if rid in src: buckets.setdefault(fn, {})[rid] = src[rid]
os.makedirs("org-os/00-role-registry/role-working-methods", exist_ok=True)
for fn, roles in buckets.items():
yaml.safe_dump({"role-working-methods": roles}, open(f"org-os/00-role-registry/role-working-methods/{fn}","w"), allow_unicode=True, sort_keys=False)
print("split", sum(len(v) for v in buckets.values()))
```
실행 후 index.yaml 수기 작성. 원본 `role-working-methods.yaml`**v1 fallback로 잔존**(Phase 7서 제거).
- [ ] **Step 4: 통과 확인** — Run 테스트 → `✅ 파일분리 병합 75역할`.
- [ ] **Step 5: Commit**`git add org-os/00-role-registry/role-working-methods .claude/tests/test_p3_infra.py && git commit -m "P3 T1.1: role-working-methods 파일분리+index(75역할·중복0)"`
### Task 1.2: Contract v2 스키마 문서 + gate/artifact vocabulary
**Files:**
- Create: `org-os/06-agent-work/artifact-type-vocabulary.yaml`
- Create: `.claude/schemas/method-execution.schema.json`
- Test: test_p3_infra.py append
**Interfaces:**
- Produces: artifact-type 어휘(handoff·required-inputs가 참조), method-execution JSON schema(step-results/handoffs/decisions).
- [ ] **Step 1: 실패 테스트(append)**
```python
_av = yaml.safe_load(open(os.path.join(ROOT, "org-os/06-agent-work/artifact-type-vocabulary.yaml")))["artifact-types"]
check("artifact vocabulary has core types",
all(t in _av for t in ["product-decision","direction-input-brief","selected-direction","locked-invariants","interaction-state-model","api-contract","design-decision-record"]))
import json
_me = json.load(open(os.path.join(ROOT, ".claude/schemas/method-execution.schema.json")))
check("method-execution schema requires step-results",
"step-results" in _me.get("properties", {}) and "method-id" in _me["properties"])
```
- [ ] **Step 2: 실패 확인.**
- [ ] **Step 3: 작성**
`artifact-type-vocabulary.yaml`:
```yaml
# handoff·required-inputs·output-artifacts가 참조하는 artifact-type 통제 어휘. schema-ref 로 스키마 연결.
artifact-types:
product-decision: { producer-roles: [EXEC-CEO, PROD-PM], schema-ref: decision.schema.json }
direction-input-brief: { producer-roles: [DES-PROD], schema-ref: null }
direction-set: { producer-roles: [DES-DIRECTOR], schema-ref: null }
selected-direction: { producer-roles: [DES-DIRECTOR], schema-ref: approved-direction.schema.json }
locked-invariants: { producer-roles: [DES-DIRECTOR], schema-ref: null }
interaction-state-model: { producer-roles: [DES-PROD], schema-ref: null, required-fields: [states, transitions, exceptions] }
reference-cluster: { producer-roles: [DES-VISUAL], schema-ref: null }
design-decision-record: { producer-roles: [DES-PROD, DES-VISUAL], schema-ref: null }
api-contract: { producer-roles: [ARCH-TECH, ENG-BE], schema-ref: null }
experience-constraints: { producer-roles: [DES-PROD], schema-ref: null }
# Phase 5–6 에서 역할 계약 작성 시 필요한 artifact-type 을 여기 추가(controlled vocabulary).
```
`method-execution.schema.json`:
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["role-id", "method-id", "contract-sha256", "step-results"],
"properties": {
"role-id": {"type": "string"},
"method-id": {"type": "string"},
"contract-sha256": {"type": "string"},
"capability-bindings": {"type": "array", "items": {"type": "object",
"required": ["skill-id","section-id","section-sha256"],
"properties": {"skill-id":{"type":"string"},"section-id":{"type":"string"},"section-sha256":{"type":"string"}}}},
"step-results": {"type": "array", "items": {"type": "object",
"required": ["step-id","status"],
"properties": {"step-id":{"type":"string"},"status":{"enum":["completed","skipped"]},
"artifact-refs":{"type":"array","items":{"type":"object","required":["report-id","sha256"]}},
"evidence-refs":{"type":"array","items":{"type":"object","required":["source-uri","grade"]}},
"skip-rule-id":{"type":"string"},"reason":{"type":"string"}}}},
"decisions": {"type": "array", "items": {"type": "object",
"required": ["decision-id","alternatives","selected-option-id"],
"properties": {"decision-id":{"type":"string"},
"alternatives":{"type":"array","minItems":1,"items":{"type":"object","required":["option-id"]}},
"selected-option-id":{"type":"string"},"rejection-rationales":{"type":"object"}}}},
"handoffs": {"type": "array", "items": {"type": "object",
"required": ["to-role","artifact-refs"],
"properties": {"to-role":{"type":"string"},"to-method":{"type":"string"},
"artifact-refs":{"type":"array","items":{"type":"object","required":["report-id","sha256"]}}}}}
}
}
```
- [ ] **Step 4: 통과 확인.**
- [ ] **Step 5: Commit**`P3 T1.2: artifact-type vocabulary + method-execution schema`
### Task 1.3: Contract v2 스키마 규약 문서(gate catalog)
**Files:** Modify `role-working-methods/index.yaml`(스키마 규약 주석 블록 추가); doc `docs/superpowers/specs/...`(이미 존재).
- [ ] **Step 1**: index.yaml에 `contract-v2-schema` 규약 블록 추가(machine-check 어휘: `artifact-field-present`/`artifact-fields-absent`/`artifact-field-matches`/`artifact-exists`/`receipt-exists`; enforcement: `hard|warning|instructional`; profile 필드 목록). 이는 문서·validator 참조용.
- [ ] **Step 2**: test_p3_infra append — `check("index defines machine-check vocabulary", ...)`.
- [ ] **Step 3: Commit**`P3 T1.3: Contract v2 스키마 규약(gate catalog)`
---
## Phase 2 — P3-A 인프라 (registry · gen v1/v2 · gen_agents · 무결성)
> Phase 2는 P3-A plan(`docs/superpowers/plans/2026-07-13-p3-prompt-skill-separation.md`) Task 18을 **파일분리 SoT + v1/v2 dual 렌더 델타**를 적용해 수행한다. 아래는 델타만; 나머지 코드는 그 plan을 task-brief로 참조.
### Task 2.1: method-skill-registry.yaml
P3-A plan Task 1 그대로(75 roles + families). 변경 없음.
### Task 2.2: gen_method_skills.py — v1/v2 dual 렌더
P3-A plan Task 2 기반 + **델타**:
- 입력 SoT를 단일 파일이 아니라 **`role-working-methods/` 병합**(`load_role_methods`, Task 1.1)으로 로드.
- 엔트리에 `method-contract.version==2`**v2 렌더**(B spec §10: profile별 섹션 — 역할경계/method(입력·워크플로 step[objective/uses-capability/machine·judgment gate/skippable]·판단규칙·근거·대안·산출·handoff·금지·self-check)), 없으면 **v1 flat 렌더**(P3-A 그대로).
- `--check` drift 유지. self-check optional 유지.
**핵심 렌더 함수(추가):**
```python
def _render_v2(rid, entry, prof, skill_name):
L = [f"# {prof.get('role-name', rid)} ({rid}) 실무 계약", "", "## 역할 경계"]
rb = entry.get("role-boundary", {})
L += [f"- owns: {', '.join(rb.get('owns', []))}", f"- not-owns: {', '.join(rb.get('not-owns', []))}"]
for m in entry.get("methods", []):
tt = ", ".join((m.get("applies-when") or {}).get("task-types", []))
L += ["", f"## Method: {m['method-id']} (task-types: {tt})"]
L.append("### 필수 입력")
L += [f"- {i.get('artifact-type')}{' (optional)' if i.get('optional') else ''}" for i in m.get("required-inputs", [])]
L.append("### 워크플로")
for s in m.get("workflow", []):
uc = s.get("uses-capability") or {}
L.append(f"- **{s['step-id']}**: {s.get('objective','')}"
+ (f" · 기법 `{uc.get('skill-id')}#{uc.get('section-id')}`" if uc else "")
+ (f" · 산출 {s.get('required-output')}" if s.get('required-output') else "")
+ (" · skippable" if s.get("skippable") else ""))
for g in (s.get("completion-gates") or {}).get("machine", []):
L.append(f" - [machine:{g.get('enforcement','hard')}] {g['gate-id']}: {g.get('check')} {g.get('artifact','')}.{g.get('field','')}")
for g in (s.get("completion-gates") or {}).get("judgment", []):
L.append(f" - [judgment] {g['gate-id']}: {g.get('criterion','')} (reviewer {g.get('reviewer-role','')})")
for key, title in [("decision-rules","판단 규칙"),("prohibited-shortcuts","금지"),("self-check","자기검증")]:
if m.get(key):
L += [f"### {title}"] + [f"- {x if isinstance(x,str) else x}" for x in m[key]]
if m.get("handoff-contract"):
L.append("### Handoff")
L += [f"- {h.get('edge-id')}: -> {h['to']['role-id']}/{h['to']['method-id']}" for h in m["handoff-contract"]]
return "\n".join(L).rstrip() + "\n"
```
(frontmatter·GEN_HEADER는 P3-A `method_skill_md`와 동일 패턴으로 감싼다. v2면 body=`_render_v2`.)
### Task 2.3: gen_agents.py — spine + registry skills
P3-A plan Task 4 그대로(wm_block→method_spine, router pointer, collapse union). v2 역할도 spine은 essence+프레임워크(계약 첫 method의 working 요지) — 카드는 **여전히 얇게**, 전체 계약은 skill.
### Task 2.4: skill_refs.py + lint_refs 확장
P3-A plan Task 3·6 그대로.
### Task 2.5: doctor check_method_skill_wiring + 재생성 + Phase2 green
P3-A plan Task 5·7·8 기반 + 델타: doctor가 **파일분리 정합**(중복/누락/미include 0)도 검사. 재생성 후 `run_all` green.
- [ ] 각 태스크: P3-A plan 해당 task를 task-brief로 추출 → 위 델타 반영 → 구현·리뷰·커밋. Phase 2 종료 시 `test_p3_infra.py` + `run_all.py` green.
---
## Phase 3 — Runtime contract resolution (policy engine · activation)
### Task 3.1: method_contracts.py 공용 policy engine (읽기 API)
**Files:**
- Create: `.claude/hooks/method_contracts.py`
- Test: `.claude/tests/test_p3b_contracts.py`
**Interfaces:**
- Produces: `resolve_method_profile(role_id, method_id)`, `resolve_activation(role_id, method_id)`, `canonical_contract_hash(contract)`, `validate_method_selection(cp)`, `load_activations()`.
- [ ] **Step 1: 실패 테스트** (`test_p3b_contracts.py` 헤더 + check) — resolve_method_profile로 대표 계약 로드, canonical_contract_hash 결정성(같은 dict→같은 hash), validate_method_selection(standard·method-selection 없음→에러).
- [ ] **Step 2: 실패 확인.**
- [ ] **Step 3: 작성**
```python
#!/usr/bin/env python3
"""method_contracts — Contract v2 정책 해석 단일 지점(P3-B §13.1). 강제는 호출측(spawn/transition/validate)."""
import glob, hashlib, json, os, yaml
ROOT = os.environ.get("CLAUDE_PROJECT_DIR") or os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
REG = os.path.join(ROOT, "org-os", "00-role-registry")
RWM_DIR = os.path.join(REG, "role-working-methods")
ACTIVATIONS = os.path.join(REG, "method-contract-activations.yaml")
def load_role_methods():
idx = yaml.safe_load(open(os.path.join(RWM_DIR, "index.yaml")))["role-method-contracts"]
merged = {}
for inc in idx["includes"]:
d = yaml.safe_load(open(os.path.join(RWM_DIR, inc))) or {}
for rid, e in (d.get("role-working-methods") or {}).items():
if rid in merged: raise AssertionError(f"중복 role-id {rid}")
merged[rid] = e
return merged
def resolve_method_profile(role_id, method_id):
e = load_role_methods().get(role_id) or {}
if (e.get("method-contract") or {}).get("version") != 2:
return None # v1 flat 역할 — 계약 강제 대상 아님
for m in e.get("methods", []):
if m.get("method-id") == method_id:
return m
return None
def load_activations():
if not os.path.exists(ACTIVATIONS): return {}
return (yaml.safe_load(open(ACTIVATIONS)) or {}).get("method-contract-activations", {}).get("roles", {})
def resolve_activation(role_id, method_id):
return ((load_activations().get(role_id) or {}).get("methods") or {}).get(method_id) or {"status": "draft"}
def canonical_contract_hash(contract):
blob = json.dumps(contract, sort_keys=True, ensure_ascii=False, separators=(",", ":"))
return hashlib.sha256(blob.encode()).hexdigest()
def validate_method_selection(cp):
"""context-package dict -> 문제 리스트(빈=통과). standard/heavy 는 method-selection 필수."""
tier = (cp.get("tier") or "standard")
ms = cp.get("method-selection")
role = cp.get("role-id") or (ms or {}).get("role-id")
e = load_role_methods().get(role) or {}
if (e.get("method-contract") or {}).get("version") != 2:
return [] # v1 역할 — 미적용
if not ms or not ms.get("method-id"):
if tier in ("standard", "heavy"):
return [f"{role}: standard/heavy 는 method-selection.method-id 필수(auto-infer 금지)"]
cands = [m["method-id"] for m in e.get("methods", [])]
return [] if len(cands) == 1 else [f"{role}: light 이나 method profile 복수({len(cands)}) — method-selection 필요"]
if not any(m["method-id"] == ms["method-id"] for m in e.get("methods", [])):
return [f"{role}: 미지 method-id {ms['method-id']}"]
return []
```
- [ ] **Step 4: 통과 확인. Step 5: Commit**`P3 T3.1: method_contracts.py policy engine(읽기·해석)`
### Task 3.2: activation registry + activate_method_contract.py (trusted CLI)
**Files:** Create `method-contract-activations.yaml`(빈 골격), `.claude/hooks/activate_method_contract.py`; Modify `guard_tools.py`(직접 write 차단).
- [ ] **Step 1: 실패 테스트** — activate CLI가 (a) golden report 부재 시 거부, (b) HUMAN acceptance hash 불일치 거부, (c) 정상 입력 시 registry에 active + receipt. guard_tools가 activations 직접 Write 차단.
- [ ] **Step 2: 실패 확인.**
- [ ] **Step 3: 작성** — CLI: `--role --method --contract-sha256 --validation-report --acceptance-event` 인자. 검증 순서: 계약 profile 실존 → canonical_contract_hash==인자 → validation-report 파일 실존·hash → acceptance-event(acceptance_log)에서 HUMAN accepted 이벤트 sha256 일치 → 임시파일 write → `os.replace` → activation receipt(evidence-ledger). guard_tools `_bash_write_targets`/Write deny에 `method-contract-activations.yaml` 추가(CLI만 예외).
- [ ] **Step 4: 통과 확인. Step 5: Commit**`P3 T3.2: activation trusted CLI + guard 차단`
### Task 3.3: context_package method-selection 배선
- [ ] context_package.py가 spawn 컴파일 시 `validate_method_selection` 호출 → 문제 있으면 spawn 거부(standard/heavy method-selection 필수). 테스트 + 커밋.
### Task 3.4: capability-sections manifest (design-craft)
- [ ] design-craft SKILL.md frontmatter(또는 `capability-sections.yaml`)에 section-id manifest 추가(brief/reference-cluster/constraints/token-semantics/decisions). `method_contracts.resolve_capability_section(skill_id, section_id)` + doctor 검사. 테스트 + 커밋.
---
## Phase 4 — Enforcement (validate_report · 2지점 handoff gate · debt)
### Task 4.1: method_contracts.validate_method_execution + validate_report 배선
**Interfaces:** `validate_method_execution(report, ws) -> errors[]`; validate_report가 active·standard/heavy에서 호출.
- [ ] **Step 1: 실패 테스트**(`test_p3b_enforcement.py`) — active 계약·standard 보고서에서: required step 누락→에러, completed인데 artifact-ref 부재→에러, skipped인데 허용 skip-rule 불일치→에러, alternatives<min→에러, method-id≠selection→에러. draft/light→무에러.
- [ ] **Step 2: 실패 확인.**
- [ ] **Step 3: 작성**`validate_method_execution`: 보고서 method-execution의 method-id로 profile 조회 → activation status active & tier≥standard일 때만 강제. 각 workflow step에 대해 completed면 artifact-ref 실존(+machine gate), skipped면 profile step.skippable & skip-rule-id∈허용. decisions는 alternatives-policy min·option 구조 검증. validate_report.py `validate()`에서 호출해 errors 병합.
- [ ] **Step 4: 통과 확인. Step 5: Commit**`P3 T4.1: validate_method_execution 배선(step-results 증명)`
### Task 4.2: evaluate_handoff_edge + spawn gate
- [ ] `method_contracts.evaluate_handoff_edge(edge, ws, phase)`: required-artifacts가 실존·required-state(Accepted)·binding(same workflow/decision)·freshness(current-usable) 충족인지. producer+consumer profile active면 hard(문제→차단), 한쪽 draft면 warning+debt event. context_package/subagent_register가 spawn 직전 consumer required-inputs에 대해 `phase="spawn"` 호출 → 미충족 시 spawn 거부. 테스트(consumer spawn 차단) + 커밋.
### Task 4.3: state_engine transition handoff gate
- [ ] state_engine에 handoff predicate 추가: stage 전이 시 해당 stage handoff edge 전부 충족(`phase="transition"`). `_PROTECTED_FACTS`. P2 gate와 동형. 테스트 + 커밋.
### Task 4.4: migration-debt event 원장
- [ ] `method_contracts.record_debt(event)`/`unresolved_debt(ws)`(opened/resolved fold). doctor가 status 분포 + unresolved debt 리포트. handoff gate가 draft 엣지에서 debt opened 기록. 테스트(fold=최신 opened) + 커밋.
---
## Phase 5 — 대표 역할 계약 + golden task + 활성화 (반복 템플릿)
> Phase 56은 **계약 authoring**이다. 각 (역할, method profile)마다 아래 **반복 템플릿**을 수행한다. 계약 본문은 B spec §3–§8 스키마대로 작성(사전 완전코드 아님 — 역할 전문성 반영).
### Task 5.T (템플릿, 대표군 각 역할 반복)
**대표군(B spec §18):** DES-DIRECTOR, DES-PROD, DES-PLATFORM, DES-VISUAL, EXEC-CEO, EXEC-CFO, PROD-PM, ARCH-TECH, ENG-BE, SRE(또는 INFRA-PLATFORM), QA, GTM-PRICING, DOC-LEAD.
각 역할에 대해:
- [ ] **작성**: 해당 family 파일(`role-working-methods/<fam>.yaml`)의 역할 엔트리에 `method-contract: {version: 2}` + `role-boundary`(owns/not-owns) + `methods[]`(호출목적별 profile: applies-when.task-types·required-inputs·workflow[step: uses-capability·completion-gates{machine/judgment}·skippable·skip-rules]·decision-rules·evidence-policy·alternatives-policy·output-artifacts·handoff-contract[profile-to-profile edge]·prohibited-shortcuts·approval-policy·escalation·self-check). **역할 경계 준수**(다른 역할 owns 침범 금지, DES-PROD는 pre/post-direction profile 분리).
- [ ] **schema/lint**: `test_p3b_contracts.py`가 profile 필드 완전·machine gate 어휘 유효·uses-capability section-id 해소·handoff edge from/to 유효 검사.
- [ ] **golden task**: 해당 profile로 대표 task 실행(격리 subagent) → 산출물·step-results·handoff가 계약대로 나오는지 end-to-end 검증. golden report 산출.
- [ ] **contract review**: 독립 리뷰(계약이 역할 전문성·경계·handoff 정합인지).
- [ ] **HUMAN acceptance**: 사용자(또는 승인자)가 golden+계약 수용 → acceptance-event.
- [ ] **활성화**: `activate_method_contract.py --role .. --method .. --contract-sha256 .. --validation-report golden.. --acceptance-event ..` → registry active.
- [ ] wave gate: 대표군 전부 active + 대표군 간 handoff edge debt 0.
> 대표군은 계약 유형 전부(발산·수렴/사업판단/기술설계/구현/운영·검증/가격/문서 handoff)를 커버 — machinery가 모든 유형에서 작동함을 증명.
---
## Phase 6 — family wave 25 이행
### Task 6.W (wave 반복: 2 임원·제품·전략·재무 / 3 디자인·아키텍처·데이터·보안 / 4 개발·인프라·QA / 5 GTM·운영·컨설팅·문서)
각 wave:
- [ ] 해당 family 역할들의 계약 작성(Task 5.T 템플릿, draft).
- [ ] schema/lint + 역할별 대표 task 검증.
- [ ] handoff edge 정합(이 wave가 소비/생산하는 artifact-type을 vocabulary에 추가).
- [ ] golden + HUMAN acceptance → active 승격.
- [ ] wave gate: 이 wave 역할 active + 신규 handoff edge debt 0 → 다음 wave.
- [ ] wave마다 `gen_method_skills`+`gen_agents` 재생성 + `run_all` green.
---
## Phase 7 — cutover
### Task 7: all-active cutover + v1 제거
- [ ] **참조 profile 산출**: commands + execution-plans + context-package method-selection + handoff graph 스캔 → 참조되는 (role, method) 집합.
- [ ] **cutover 게이트**(doctor + test): 참조 profile ⊆ activation active **AND** unresolved debt=0 **AND** 모든 역할 ≥1 필수 profile 존재.
- [ ] **v1 제거**: 원본 단일 `role-working-methods.yaml` 삭제(파일분리로 대체 완료). retired 처리 확인.
- [ ] **최종 재생성**: `gen_method_skills` + `gen_agents` → 72 agents·75 roles·전 skill.
- [ ] `git checkout -- .claude/tests/fixtures/`; `run_all.py` green + `doctor` OK(P3 배선·debt 0·status all-active).
- [ ] CLAUDE.md 갱신(Contract v2·다중 profile·2지점 gate·activation registry·policy engine·파일분리).
- [ ] Commit + finishing-a-development-branch(사용자 선택 merge).
---
## Self-Review
**Spec coverage:** B spec §3 Phase 07 ↔ 본 plan Phase 07. §4 다중 profile(T5.T/T6.W·gen v2 T2.2), §5 method-selection(T3.1·T3.3), §7 machine/judgment gate(T1.3·T4.1), §8 evidence/alternatives(T4.1·schema T1.2), §11 step-results(T1.2·T4.1), §13 2지점 handoff+policy engine(T3.1·T4.2·T4.3), §14 activation CLI(T3.2), §16 hash/section-id(T3.1·T3.4), §17 파일분리(T1.1), §18 wave+cutover(T5T7). A spec: registry·gen·spine·무결성(Phase 2). 전 섹션 커버.
**Placeholder scan:** Phase 04는 완전 코드 TDD. Phase 57은 **의도적으로 authoring 템플릿**(75 계약 본문은 역할 전문성 반영 실행물 — 사전 완전코드 불가, 대신 스키마·게이트·검증 절차를 완전 명시). 이는 writing-plans의 "content authoring은 반복 템플릿" 패턴.
**Type consistency:** `method_contracts.py` API(resolve_method_profile/resolve_activation/validate_method_selection/evaluate_handoff_edge/validate_method_execution/canonical_contract_hash)가 강제 3지점(spawn/transition/validate)에서 동일 시그니처로 소비. `load_role_methods` 병합 규약이 gen·doctor·policy engine 일관. contract-sha256·section-sha256 규약 일관.
## Execution Handoff
**Plan complete and saved to `docs/superpowers/plans/2026-07-13-p3-unified-role-method-contract.md`.**
**Subagent-Driven(권장)** — Phase 0→7 순차, 태스크별 fresh subagent + 2단 리뷰. Phase 04는 완전코드 TDD, Phase 57은 계약 authoring 템플릿×wave. P1·P2와 동일.