504 lines
33 KiB
Markdown
504 lines
33 KiB
Markdown
# 통합 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.1–T1.3 |
|
||
| **2** | P3-A 인프라(registry·gen v1/v2·gen_agents·ref/orphan/drift) | T2.1–T2.5 |
|
||
| **3** | method_contracts.py policy engine + method-selection + activation(CLI·hash) | T3.1–T3.4 |
|
||
| **4** | Enforcement(validate_report·spawn gate·transition gate·debt) | T4.1–T4.4 |
|
||
| **5** | 대표 역할 계약 + golden task + active 승격 | T5(템플릿)×대표군 |
|
||
| **6** | family wave 2–5 이행 | T6(wave 반복) |
|
||
| **7** | cutover(참조 profile all-active·debt 0·v1 제거·재생성) | T7 |
|
||
|
||
**Phase 0–4 = 계약 machinery(완전 코드).** 계약 0개여도 v1 fallback으로 green. **Phase 5–7 = 계약 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 1–8을 **파일분리 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 5–6은 **계약 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 2–5 이행
|
||
|
||
### 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 0–7 ↔ 본 plan Phase 0–7. §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(T5–T7). A spec: registry·gen·spine·무결성(Phase 2). 전 섹션 커버.
|
||
|
||
**Placeholder scan:** Phase 0–4는 완전 코드 TDD. Phase 5–7은 **의도적으로 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 0–4는 완전코드 TDD, Phase 5–7은 계약 authoring 템플릿×wave. P1·P2와 동일.
|