Files
company-haness/docs/superpowers/specs/2026-07-13-p2-design-direction-design.md
T

402 lines
29 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.
# 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