init: company-haness 설계

This commit is contained in:
DongHyeonka
2026-07-23 17:49:00 +09:00
parent 57d1bab894
commit f668d6a158
962 changed files with 98989 additions and 1 deletions
@@ -0,0 +1,401 @@
# P2 — Design Direction 스테이지 설계
- 날짜: 2026-07-13
- 상태: 설계(brainstorm 승인 + §15 열린항목 결정 + 4 구조수정 반영) — 구현 전
- 관련: [design-craft-upgrade](2026-07-08-design-craft-upgrade-design.md), [design-system-pipeline](2026-07-08-design-system-pipeline-design.md), [P1 venture-bootstrap](2026-07-12-p1-company-venture-bootstrap-design.md)
- 로드맵: 리뷰 2번째 핵심결함(디자인 탐색 없이 design-system으로 조기고착) 해소 = P2.
## §1. 문제 (리뷰 2번째 핵심결함)
현재 `/design-system` 파이프라인은 `design-brief 세우기 → tokens → components → screens → preview`**바로** 들어간다. design-brief의 reference cluster가 **탐색 없이 단번에 확정**되고, 그 순간 시각 방향이 고착된다. 빠진 것:
1. **방향 발산 부재** — 2~3개의 서로 다른 시각 방향을 실물로 세워 비교하는 단계가 없다. LLM은 단일 brief를 generic 평균("modern/clean")으로 채운다(design-craft 근거: vague prototyping = generic, NNGroup).
2. **비평 게이트 부재** — generic·미분화 산출을 되돌리는 critique 루프가 없다. preview_ui는 *기술 품질*(렌더됨·대비·포커스)만 보고 *방향의 독창성/일관성*은 보지 않는다.
3. **조기고착 방지 선행조건 부재** — "방향 승인 전 시스템 고착 금지"가 `/design-system` 진입에 강제되지 않는다.
4. **FAM-DESIGN에 리드 부재** — FAM-CONSULTING(CONSULT-EM)·FAM-DOC-CONSULT(DOC-LEAD)와 달리 FAM-DESIGN에는 발산을 프레이밍하고 수렴을 종합하는 `lead-role-id`가 없다.
5. **입력 brief 자체가 조기고착의 원천** — reference cluster·색·typography·layout·token·visual metaphor가 이미 박힌 design brief를 발산의 입력으로 주면 "방향이 정해진 뒤 발산하는" 모순이 된다. 따라서 발산 이전 입력(direction-input-brief)과 승인 이후 시스템 입력(design-system-brief)을 **분리**해야 한다(§3).
cascade의 `design` 스테이지는 역할 관점 fan-out(PRD/RFC/data-model/threat-model)이라 **시각 방향 발산은 그 안에 없다**.
## §2. 결정 요약
**확정 문장:** design-direction은 제품 cascade에 종속된 별도 named child plan이다. UI-bearing standard/heavy 작업에서 강제되며, 독립 발산·단일 방향 수렴·coded prototype·비평 재작업 루프를 state machine으로 보장한다. 승인 결과는 부모 workflow, 제품 결정, direction-input-brief hash에 바인딩되고 `/design-system`의 선행조건으로 사용된다.
접근법 A(별도 named plan, venture-bootstrap과 동형)를 택한 이유: 리뷰의 결함(탐색 없이 조기고착)을 *구조로* 막으려면 발산→수렴→비평이 **강제 스테이지**여야 한다. 게이트+커맨드만(C안)은 P1의 핵심 교훈("prose가 아니라 hook 강제")을 위반하고, cascade design 스테이지 내부 삽입(B안)은 단일 스테이지를 오염시키고 non-UI cascade에 죽은 하위단계를 남긴다.
**정제 6종(사용자 승인):** ①부모 workflow 바인딩(§3) ②namespaced 스테이지(§4) ③critique 실패 역전이(§4) ④divergence 3안 동일 대표화면 coded slice(§11) ⑤평균금지 스키마 강제(§6) ⑥`/design-system` 게이트 tier 한정+바인딩+staleness(§7).
**4 구조수정(사용자 지시, 구현 계획 전 필수):**
- **S1. brief 입력/출력 분리** — direction-input-brief(발산 이전) vs design-system-brief(승인 이후). 바인딩·staleness 앵커는 direction-input-brief-sha256(§3).
- **S2. approved-direction을 terminal로** — 스테이지별 산출물 재명명: decision→selected-direction, prototype→winner-prototype, critique→design-review, approved(terminal)→approved-direction. critique 통과 전엔 승인 아티팩트가 존재하지 않는다(§4/§5).
- **S3. 리뷰 패널(자기승인 차단)** — critique는 다관점 패널이 평가, DES-DIRECTOR는 종합만. producer는 자기 방향의 필수 reviewer 불가(§5/§8/§9).
- **S4. 방향 독립성 격리 강제** — 3안은 각자 다른 producer-run-id + context-package로 격리 생산, 형제 산출물 must-read 금지(§9/§11).
**§15 열린항목 결정:** ①/design 자동 spawn + /design-direction 수동 유지(dedup) ②guard_tools 특수보호 없음(불변 report만) ③preview_ui `--url-path` 미확장(별도 갤러리 패키지) ④secondary-influence-id 제거→adopted-elements 원자 예외 최대1(§6).
## §3. child-plan 바인딩 + brief 분리 (정제 ① + 구조수정 S1)
design-direction은 venture-bootstrap 같은 독립 lifecycle이 **아니다**. 특정 제품 결정에서 파생되는 **자식 workflow**다.
### brief 분리 (S1) — 조기고착 재발 방지
```
direction-input-brief → design-direction → approved-direction → design-system-brief → design-system
```
- **direction-input-brief**(발산 이전 입력): 제품 목표 · 핵심 사용자 · 핵심 작업 · 정보 밀도 · 필수 접근성 · 브랜드 제약 · 피해야 할 클리셰 · 대표 화면 요구 · 기술·플랫폼 제약.
- **포함 금지**(넣으면 lint Hard Fail): 최종 reference cluster · 확정 색상 팔레트 · 확정 typography · 확정 layout grammar · 확정 token · 선택된 visual metaphor. (이게 있으면 발산 전에 방향이 고착됨.)
- **design-system-brief**(승인 이후, 기존 `design-brief-spec.yaml`의 design-brief 역할): 입력 = `direction-input-brief-ref` + `approved-direction-ref/sha256`. reference cluster·색·typography·token은 여기서 **승인된 방향으로부터** 확정(발명 아님). `design-brief-spec.yaml``brief-phase: system-ready`와 approved-direction 인용 필드를 추가.
### 바인딩 메타 (child 원장 `state/<wf>/workflow.yaml`)
```yaml
plan: design-direction
parent-workflow-id: product-cascade-001 # 필수 — 부모 제품 cascade wf-id
product-decision-id: PD-001 # 필수 — 부모 decide 산출(ExecutiveDecisionPacket) id
company-context-ref: org-os/01-company/company-context.yaml
direction-input-brief-ref: <path> # 발산 입력(design-brief 아님)
direction-input-brief-sha256: <hash> # staleness 앵커 (§7)
```
- 바인딩이 없으면 한 제품 방향을 다른 제품/오래된 brief에 재사용할 수 있다 — P1의 company↔product seam과 동형.
- `state_engine.py init``--parent-workflow`, `--product-decision`, `--direction-input-brief` 인자. 미지정 시 design-direction init 거부(BlockedReport). parent wf-id는 실존 원장, product-decision-id는 부모 원장의 accepted decision-packet과 대조.
### 부모 원장의 child 등록 (dedup 근거, §10)
```yaml
child-workflows:
design-direction:
workflow-id: product-001-direction-01
input-brief-sha256: ...
status: running | approved | stale
```
## §4. 스테이지 그래프 (정제 ②③ + 구조수정 S2)
### 스테이지 (전역 그래프 충돌 방지 위해 전부 접두어)
```
design-direction-intake
design-direction-discovery
design-direction-divergence
design-direction-decision
design-direction-prototype
design-direction-critique
design-direction-finalize
design-direction-approved # terminal
```
`unified-stage-graph`에 위 8개 추가(venture-bootstrap 스테이지 추가와 동형). intake도 일반 cascade intake와 구분. critique pass 직후 바로 approved로 가지 않고 **finalize**를 하나 더 거친다 — approved-direction 불변 report 작성과 부모 원장 등록(§10)이라는, critique 자체와는 다른 책임을 별도 stage로 분리해 "패널 통과"와 "최종 확정·부모 바인딩"을 섞지 않기 위함이다.
### 스테이지별 산출물 이름 (S2 — 의미와 상태 일치)
| 스테이지 | 산출 아티팩트 |
|---|---|
| divergence | **direction-set**(3안, 각 격리 생산) |
| decision | **selected-direction**(1안 선택 + rejected + locked-invariants, 사람 선택) |
| prototype | **winner-prototype**(승자 핵심흐름 coded) |
| critique | **design-review-panel**(다관점 verdict + 종합) |
| finalize | **approved-direction**(불변 report — 위 전부를 hash로 묶음) + 부모 원장 `design-direction-approval` 등록 |
| approved(terminal) | (신규 아티팩트 없음 — finalize 산출물의 유효성·해시·바인딩이 8점 검증을 통과했음을 표시하는 종료 상태) |
critique 통과 **전**에는 approved-direction이 존재하지 않는다(finalize에서 비로소 작성된다). selected-direction은 "선택"이지 "승인"이 아니다.
### 전이 (선형 아님 — critique 실패 역전이 포함, 전부 `allowed-by: [OPS-ORCH]`)
```
intake → discovery : parent-binding-present
discovery → divergence : direction-input-brief-valid (S1 포함금지 통과)
divergence → decision : directions-diverged (§9 독립성 6검사)
decision → prototype : selected-direction-accepted (1안 선택 + 사람 acceptance)
prototype → critique : winner-prototype-present
critique → prototype : critique-revision-requested (역전이: minor revision)
critique → divergence : concept-rejection-recorded (역전이: concept flaw)
critique → finalize : direction-critique-passed (패널 pass + winner preview_ui receipt)
finalize → approved : approved-direction-valid + approval-receipt-bound
+ parent-approval-link-recorded (report 확정+hash 일치 + acceptance receipt 바인딩 + 부모 원장 등록)
```
전이 **9종**(순방향 7 + 역전이 2).
```
┌──────────────── concept-rejection-recorded ───────────────┐
↓ │
-divergence → -decision → -prototype → -critique ── pass ──→ -finalize → -approved
↑ │
└── minor rev ─┘
```
## §5. 아티팩트/스키마 (4종)
계약 파일: `org-os/06-agent-work/design-direction-spec.yaml`(4 아티팩트 함께 정의) + JSON Schema(validator 소비).
### (a) direction-set (`-divergence` 산출)
```yaml
direction-set:
representative-screen: # 3안이 공유하는 동일 대표 화면 (비교 가능성 핵심)
id: SCREEN-CORE-TASK
kind: first-entry | core-task | signature-moment # 버튼/카드 갤러리 금지
description: ...
directions:
- id: DIR-001
producer-role-id: DES-VISUAL
producer-run-id: RUN-001 # 격리 생산 증거 (S4)
context-package-id: PKG-001
concept-artifact: ...
reference-cluster: # 6집중, 각 '나르는 신호'(형용사 금지)
- { name: ..., signal: ..., why-relevant: ... }
visual-thesis: ...
layout-grammar: ...
interaction-grammar: ...
typography-token-direction: ...
coded-slice: <path> # representative-screen 구현 경량 slice
render-manifest: <ref> # 갤러리 렌더 receipt 참조
```
### (b) selected-direction (`-decision` 산출 — 사람 선택, 아직 승인 아님)
```yaml
selected-direction:
selected-direction-id: DIR-002 # 정확히 1개
rejected-directions: # 모든 비선택에 reason 필수
- { id: DIR-001, reason: ... }
- { id: DIR-003, reason: ... }
locked-invariants: [...] # 최소 3개
flexible-elements: [...]
adopted-elements: # optional, 최대 1개 (§6 — 원자 예외, secondary 대체)
- from-direction-id: DIR-001
element-id: typography-scale
description: "본문 크기 비율만 채택"
rationale: "고밀도 데이터 화면 판독성 우수"
affected-invariants: []
parent-workflow-id: ...
product-decision-id: ...
direction-input-brief-sha256: ...
selection-acceptance-receipt: ... # 사람 선택 acceptance
```
### (c) design-review-panel (`-critique` 산출 — 다관점, S3)
```yaml
design-review-panel:
target-prototype: <path>
preview-receipt: <ref> # winner 프로토타입 실제 렌더 preview_ui receipt
reviews:
- { reviewer-role-id: DES-PROD, reviewer-run-id: ..., lens: product-fit, verdict: pass, report-ref: ..., report-sha256: ... }
- { reviewer-role-id: UX-RESEARCHER, reviewer-run-id: ..., lens: usability, verdict: ..., ... }
- { reviewer-role-id: DES-VISUAL, reviewer-run-id: ..., lens: distinctiveness, verdict: ..., ... } # producer-run-id와 상이해야
- { reviewer-role-id: DES-PLATFORM, reviewer-run-id: ..., lens: systematizability, verdict: ..., ... }
- { reviewer-role-id: GTM-PMM, reviewer-run-id: ..., lens: market-memorability, verdict: ..., ... }
- { reviewer-role-id: ENG-FE, reviewer-run-id: ..., lens: implementability, verdict: ..., ... }
synthesis:
role-id: DES-DIRECTOR
verdict: pass | minor-revision | concept-flaw
unresolved-dissent: []
```
distinctiveness/generic-risk 판정 기준(reference-signal-fidelity, generic-adjective-risk="modern/clean"이면 weak, layout-information-hierarchy, token-consistency)은 각 reviewer가 관찰+근거로 기록(자기채점 금지). synthesis.verdict가 §4 역전이 구동.
### (d) approved-direction (`-finalize` 산출 — 불변 report, S2)
`-critique` pass 직후의 **`-finalize`** stage에서 작성된다(terminal인 `-approved`가 만드는 것이 아니다 — `-approved`는 이 report의 유효성·hash·acceptance receipt·부모 원장 등록이 전부 확인된 뒤 도달하는 종료 상태). 경로: `<workspace>/completion-records/<child-workflow-id>/approved-direction-<timestamp>.report.yaml`(불변 report, guard 특수보호 불요).
```yaml
approved-direction:
selected-direction-ref: ...
selected-direction-sha256: ...
final-prototype-ref: ...
final-prototype-sha256: ...
critique-report-refs: [...]
critique-pass-receipt: ...
locked-invariants: [...]
approved-at: ...
parent-workflow-id: ...
product-decision-id: ...
direction-input-brief-sha256: ...
```
부모 원장엔 파일 복사 없이 hash-bound 참조만:
```yaml
design-direction-approval:
report-ref: ...
report-sha256: ...
child-workflow-id: ...
```
### JSON Schema
`.claude/schemas/`에 selected-direction·design-review-panel·approved-direction schema. (direction-set는 lint가 검사.)
## §6. 평균 금지 = 스키마 강제 (정제 ⑤ + secondary 제거)
hook은 시각적 독창성은 판정 못 하나 **"선택 대신 평균내는 구조적 실패"는 차단**한다. `lint_design_direction.py`(=`lint_company_context.py` 형제)의 Hard Fail:
- selected-direction-id 정확히 1개(0·복수 = Hard Fail), direction-set 실존 id.
- 모든 비선택(rejected)에 reason 필수(빈 사유 = Hard Fail).
- locked-invariants ≥ 3.
- rejected {selected} = direction-set 모든 id(누락·유령 id = Hard Fail).
- **secondary-influence-id 필드가 있으면 Hard Fail**(제거됨 — 평균의 뒷문).
- **adopted-elements**: 최대 1개. element-id 필수, rationale 필수. selected의 locked-invariants를 침범하면 Hard Fail. "분위기/감성/스타일" 같은 포괄 표현이면 Hard Fail(원자적 element-id만 허용).
Warning: reference-cluster가 형용사만("modern/clean/minimal/sleek") → generic-risk 경고. direction-input-brief에 §3 포함금지 항목이 있으면 Hard Fail(발산 전 고착 방지).
## §7. `/design-system` 게이트 (정제 ⑥ + 구조수정 gate)
**tier 어휘 정합:** 사용자 "standard/high" = 하네스 **standard/heavy**(governance-tiers `High: heavy`).
### UI-bearing 판정 (proxy 아님 — 명시 필드 우선)
부모 decision-brief(ceo-intake 산출)에 명시 필드:
```yaml
deliverable-profile:
ui-bearing: true
ui-kind: product | admin | internal-tool
governance-tier: standard
```
판정 우선순위: **① decision-brief `ui-bearing` 명시값 → ② 산출물 타입/요구에서 파생 → ③ FAM-ENG-FRONTEND 포함 여부(fallback)**. 누락 + standard/heavy + UI 가능성 있으면 **warning 또는 fail-closed**(안전측).
### 게이트
```
UI-bearing && tier ∈ {standard, heavy} → design-direction-approved 필수 → 없으면 Hard Fail(BlockedReport)
UI-bearing && tier = light → Warning + 기존 승인 방향 있으면 반드시 상속
non-UI → N/A (child plan 생성 안 함)
```
### `direction-approved`는 boolean 아님 — 바인딩 검사
`state_engine._has_direction_approval(wf)`(= `_has_preview_receipt` 형제)가 부모 원장의 `design-direction-approval` 참조를 따라가 확인:
1. approved-direction 불변 report 존재(completion-records 경로)
2. schema/validator(lint_design_direction) 통과
3. acceptance receipt 존재(acceptance_log accepted, report-sha256 바인딩 — P1 hash 바인딩 재사용)
4. report hash 일치(receipt report-sha256 == 실제 파일 hash — 수정 시 mismatch)
5. parent-workflow-id 일치
6. product-decision-id 일치(부모 accepted decision-packet)
7. **direction-input-brief-sha256 일치**
8. critique pass receipt 존재(design-review-panel synthesis=pass + winner preview_ui receipt)
### staleness (자동 무효화)
```
current direction-input-brief-sha256 (실측) != approved.direction-input-brief-sha256 → 승인 무효
```
매 평가 시 현재 direction-input-brief 파일 hash 재계산 대조(P1 company-context-lint live 평가와 동형). product-decision supersede 시도 무효.
## §8. 역할 신설 + 리뷰 패널 (구조수정 S3)
- **DES-DIRECTOR**: FAM-DESIGN `lead-role-id`(synthesis-lead). 발산 프레이밍(discovery→direction-input-brief 정련) + 3안 원본 종합 수렴(decision) + critique **종합**(단독 평가자 아님). CONSULT-EM/DOC-LEAD 동형.
- **DES-VISUAL**: FAM-DESIGN fan-out 워커. 방향별 아트디렉션(각 방향 격리 생산, §11).
**리뷰 패널(critique 평가자 — DES-DIRECTOR는 종합만):**
| lens | 역할 |
|---|---|
| 제품 흐름·핵심 작업 (product-fit) | DES-PROD |
| 사용성·인지부하 (usability) | UX-RESEARCHER |
| 시각적 독창성·일관성 (distinctiveness) | DES-VISUAL(생산 안 한 별도 run) |
| 시스템화 가능성 (systematizability) | DES-PLATFORM |
| 시장 전달·기억성 (market-memorability) | GTM-PMM |
| 구현 손실·기술 가능성 (implementability) | ENG-FE(FAM-ENG-FRONTEND) |
| 최종 종합 | DES-DIRECTOR |
**패널 pass 조건(구조화):** 필수 reviewer lens 전부 존재 · producer-run-id ≠ 각 reviewer-run-id(생산자가 자기 방향 필수 reviewer 불가) · critical blocker 없음 · 각 review report hash 검증 · DES-DIRECTOR synthesis 존재.
변경 파일: `roles.yaml`(+2), `role-profiles.yaml`, `role-working-methods.yaml`(design-craft 근거 embed), `capability-families.yaml`(FAM-DESIGN `member-role-ids += [DES-DIRECTOR, DES-VISUAL]`, `lead-role-id: DES-DIRECTOR`) → `gen_agents.py` 재생성. roles 73→75, family 28·lens 12 불변.
## §9. 강제기 / predicate
### state_engine.py (신설)
- predicate: `parent-binding-present`, `direction-input-brief-valid`, `directions-diverged`, `selected-direction-accepted`, `winner-prototype-present`, `critique-revision-requested`, `concept-rejection-recorded`, `direction-critique-passed`, `direction-approved`(복합 §7).
- helper:
- `_directions_diverged(wf)`**S4 독립성 6검사**: ① direction ≥ 3 ② producer-run-id 전부 상이 ③ context-package-id 전부 상이 ④ 각 worker의 must-read에 형제 direction 산출물 없음 ⑤ 동일 representative-screen ⑥ 각 coded-slice + render-manifest 존재.
- `_selected_direction_ok(wf)`(lint 통과 + 평균금지 + adopted-elements 규칙).
- `_critique_panel_ok(wf)`(§8 패널 pass 조건 — producer≠reviewer run-id 포함).
- `_has_direction_approval(wf)`(§7 8검사 + staleness).
- `_current_input_brief_sha(ref)`.
- `_PROTECTED_FACTS`에 신규 fact 키 전부 추가(자기신고 차단 — P1 동일).
- CLI: `state_engine.py check-direction-approved --workflow WF`(advisory 조회, /design-system·/design 진입이 호출).
### lint_design_direction.py (신설)
`lint_file(path, kind) -> (hard_fails, warnings)`. §6(selected-direction 평균금지) + direction-input-brief 포함금지(§3) + direction-set 구조 강제. run_all·doctor 배선.
### collaboration-map.yaml (수정)
`design-to-build-contract``direction-gate` 추가(design-system-gate 형제):
```yaml
direction-gate:
requires: design-direction-approved
enforced-by: state_engine._has_direction_approval
applies-to: [FAM-ENG-FRONTEND]
hard-if: tier in [standard, heavy] # light: warning + 상속
```
`must-read-designs`(FAM-ENG-FRONTEND)에 approved-direction을 선행으로 추가(design-system preview receipt와 함께).
### guard_tools.py — **변경 없음** (§15 결정 ②)
approved-direction은 기존 immutable report 경로에 생성, 부모 원장엔 hash-bound reference만. 별도 mutable canonical 파일을 두지 않으므로 특수 직접쓰기 보호 불요. 일반 report immutability로 충분.
## §10. 커맨드
### `/design` (수정 — 자동 spawn + dedup, §15 결정 ①)
UI-bearing && tier ∈ {standard, heavy} 판정(§7 우선순위) → 유효 child 없으면 자동 init/spawn → `/design-direction` 절차 실행 → child approved까지 부모 design 전이 대기.
**dedup**(중복 생성 방지): (parent-workflow-id + product-decision-id + direction-input-brief-sha256)로 기존 child 검색 —
- 일치 & running → **resume**
- 일치 & approved → **재사용**
- hash 상이 → **stale 처리 후 신규 child 생성**
사용자가 `/design`을 돌렸는데 나중에 `/design-system`에서 갑자기 막히지 않도록, 방향 탐색이 필요한 순간(`/design`)에 child를 자동 시작.
### `/design-direction` (신설 — 수동 진입점 유지)
용도: 독립 실행 · 중단 후 resume · critique 실패 후 재진입 · stale 승인 재생성 · child 복구/디버깅. 인자 `--parent-workflow --product-decision --direction-input-brief`. 각 스테이지 종료 시 `state_engine transition`, 산출 시 `record` + `acceptance_log append accepted`(P1 deadlock 교훈 — 커맨드 본문에 명시).
### `/design-review` (신설)
critique 패널 실행(§8). 프로토타입 대상 다관점 verdict 산출. `-critique`에서 호출되거나 임의 프로토타입에 독립 실행.
### `/design-system` (수정)
진입 선행조건에 `check-direction-approved`. UI+standard/heavy면 승인 없을 시 BlockedReport, light면 경고+상속. 입력 brief = design-system-brief(approved-direction 인용, §3).
## §11. divergence 충실도 + 독립성 (정제 ④ + 구조수정 S4 + Q2)
- 각 방향 = concept artifact · reference cluster(6집중) · visual thesis · layout/interaction grammar · typography/token direction · signature interaction · **대표 화면 1개 경량 coded slice**.
- 대표 화면 = 첫 진입 / 핵심 작업 / signature moment 중 하나. **버튼·카드 수준 금지**. **3안 모두 동일 대표 화면**(`representative-screen.id` 공유, lint 강제).
- **독립 생산(S4)**: 3안은 각자 다른 `producer-run-id` + `context-package-id`로 격리 실행. 각 worker의 must-read에 형제 direction 산출물 금지(한 에이전트가 A/B/C를 한 번에 쓰면 표면만 다른 동일 사고 — `_directions_diverged`가 거부).
- **비교 렌더(§15 결정 ③)**: 3 slice를 **별도 Vite 갤러리 패키지**의 root(ComparisonGallery)로 묶어 기존 `preview_ui.py`로 root 1회 렌더 → 3-way PNG(receipt). `--url-path` 확장 없이 최단·재현성. `_directions_diverged`가 이 render-manifest 요구.
```
design-direction-preview/
src/{DirectionA,DirectionB,DirectionC,ComparisonGallery}.jsx
App.jsx # ComparisonGallery를 root에서 렌더
```
- 수렴 후 `-prototype`: 승자 방향 **핵심 사용자 흐름 전체** coded → `-critique`(preview_ui + design-review-panel). 통과 후에야 `/design-system`이 그 방향으로 재사용 토큰+컴포넌트 확장.
## §12. 하네스 정합성 영향
- **카운트**: roles 73→75(실측). family 28·lens 12 불변. FAM-DESIGN `lead-role-id` 획득 → gen_agents가 DES-DIRECTOR synthesis-lead + DES-VISUAL 워커 생성. 갱신할 구체 단언:
- `test_enforcement.py:722` `role-working-methods covers 73 roles`**75**.
- FAM-DESIGN `member-role-ids` 카운트 단언(있으면) 3→5.
- gen_agents agent 총수 단언(doctor·test 있으면) 신규 2 반영.
- **gen_agents.py 재생성** 필수. `.claude/agents/*.md`는 생성물 — 수기편집 금지.
- **doctor.py**: `check_design_direction_wiring` 신설 — 스키마 존재, lint 배선, DES-* 등록, 커맨드→에이전트 참조 무결성.
- **execution-plans.yaml**: `design-direction` plan(§4 스테이지 + 바인딩). **state-transition-rules.yaml**: 전이 8종 + condition-catalog.
- **design-brief-spec.yaml**: `brief-phase: pre-direction | system-ready` + approved-direction 인용 필드 추가(design-system-brief가 승인 방향 소비).
- **기존 불변식 유지**: report immutability, evidence 등급, 권한(외부 side-effect 기본금지; npm/chrome 로컬빌드 허용), design-brief 없이 컴포넌트 생성 금지.
## §13. 테스트 (`test_design_direction.py` 신설, standalone `check()` 규약)
**기본 8종:** ①평균금지 negative(selected 0/2개, rejected reason 누락, locked<3) ②평균금지 positive ③staleness(input-brief sha 불일치→승인 무효) ④바인딩 검사(parent/product-decision 불일치, critique·preview receipt 없음) ⑤게이트 tier 분기(UI+standard 승인없음→Hard Fail; UI+light→Warning; non-UI→N/A) ⑥critique 역전이(minor-revision→prototype, concept-flaw→divergence, pass→approved) ⑦directions-diverged(3안 미만·대표화면 불일치·render-manifest 없음→거부) ⑧바인딩 부재 init 거부.
**추가 11종(구조수정 검증):**
9. 동일 producer-run-id가 3안 생산 → divergence 거부.
10. DES-VISUAL producer가 자기 방향 필수 reviewer → critique 거부.
11. selected-direction만 있고 최종 approved-direction 없음 → /design-system 거부.
12. critique 전 생성된 approval artifact → 승인으로 불인정.
13. direction-input-brief hash 변경 → child·approval 모두 stale.
14. /design 재실행 시 같은 binding child 중복 spawn 안 하고 resume.
15. 승인 immutable report 수정 → hash mismatch로 게이트 거부.
16. secondary-influence-id가 스키마에 들어오면 거부.
17. adopted-elements 허용량 초과·locked-invariant 침범 → 거부.
18. ui-bearing=true + standard/heavy인데 child 없음 → /design 자동 생성.
19. ui-bearing=false → child plan 생성 안 함.
## §14. 비목표 (YAGNI)
- 시각적 독창성 자동 정량 판정(hook이 미적 채점) — hook은 구조적 평균금지·바인딩·격리·렌더 receipt만 강제, 미적 판단은 패널/사람.
- 3안 각각 풀 프로토타입 — divergence는 동일 대표화면 slice만, 풀은 승자만.
- preview_ui `--url-path` 다중 route 순회 — 별도 갤러리 패키지로 대체(실제 요구 생기면 후속).
- Figma MCP·비주얼 회귀 스냅샷 diff — 후속.
- 제품 cascade 밖(마케팅 사이트 등) 적용 — 우선 제품 child로 검증 후.
## §15. 열린항목 — 결정 완료
1. **자동 spawn + 수동 유지**: `/design`이 UI+standard/heavy에서 child 자동 init/spawn(dedup), `/design-direction`은 독립·resume·재진입·재생성·복구용 수동 진입점 유지(§10).
2. **guard_tools 특수보호 없음**: approved-direction은 immutable report 경로에 생성, 부모 원장엔 hash-bound reference만. mutable canonical 파일 없음 → 일반 report immutability로 충분(§9).
3. **preview_ui 미확장**: 비교 갤러리를 별도 Vite 패키지 root로, 기존 preview_ui root 1회 렌더(§11).
4. **secondary-influence-id 제거**: 평균의 뒷문. 대신 원자적 `adopted-elements` 최대 1개(element-id+rationale 필수, locked-invariant 침범·포괄표현 금지, §6).
## §16. 구현 체크리스트
- [ ] `design-direction-spec.yaml`(direction-set/selected-direction/design-review-panel/approved-direction + direction-input-brief) + 3 JSON Schema
- [ ] `design-brief-spec.yaml`에 brief-phase + approved-direction 인용(design-system-brief 분리)
- [ ] roles/role-profiles/role-working-methods/capability-families에 DES-DIRECTOR(lead)+DES-VISUAL → gen_agents 재생성
- [ ] execution-plans.yaml `design-direction` plan(namespaced 스테이지 + 바인딩)
- [ ] state-transition-rules.yaml 전이 8종(역전이 2) + condition-catalog
- [ ] state_engine.py predicate/helper(독립성 6검사·패널·8검사·staleness)/_PROTECTED_FACTS/CLI + init 바인딩 인자
- [ ] lint_design_direction.py(평균금지·포함금지 Hard Fail) + run_all/doctor 배선
- [ ] collaboration-map.yaml direction-gate + must-read
- [ ] /design(자동 spawn+dedup) · /design-direction · /design-review · /design-system 선행조건
- [ ] test_design_direction.py(19종) + 카운트 단언 갱신(test_enforcement:722 →75) + doctor check
- [ ] 전체 green(run_all) + doctor OK