Files

154 lines
21 KiB
Markdown

---
description: direction-input-brief(불변)를 입력으로 discovery→3안 독립발산→단일수렴(평균금지)→승자 prototype→비평 재작업 루프→finalize를 거쳐 approved-direction을 산출한다. 제품 cascade 종속 child(1회성 사이클), 모든 전이는 OPS-ORCH 집행.
---
당신은 Orchestrator다. **design-direction** — 제품 cascade(`/design`)에 종속된 **child plan**이다(`execution-plans.yaml` `design-direction`). 입력은 부모 workflow `<p>`가 이미 `/decide`에서 accepted한 **product-decision** report-id `<PD>`와, 부모가 발산 이전에 **불변화(freeze)한** `direction-input-brief` 경로다. 공개 웹·신규 제품·대규모 리디자인이면 부모의 `/experience-foundation`이 이미 approved여야 하며, brief는 accepted competitive benchmark/experience blueprint/wireframe set exact ref+SHA를 포함한다. 이 IA·콘텐츠·screen purpose는 세 방향 모두 동일하다. 브리프는 여기서 만들지 않고 수정하지도 않는다(발산 이후 항목인 reference-cluster/color-palette/typography/layout-grammar/tokens/visual-metaphor가 섞여 있으면 `python3 .claude/hooks/lint_design_direction.py <brief> direction-input-brief`가 거부한다 — 발산 전 고착 방지). **모든 상태 전이는 OPS-ORCH가 집행**한다(워커·`des-director`·`des-visual`은 보고서만 생산).
**활성 cycle 포인터**: `design-direction-active`는 읽기 전용이며 canonical `artifact-submitted` 이벤트 순서에서 각 artifact-kind의 최신 revision을 사용한다.
## 0. dedup — 동일 바인딩(parent+product-decision+brief-hash) 중복 방지
1. brief의 sha256을 계산한다(dedup·staleness 판정에 쓴다).
2. 기존 자식 조회:
```
python3 .claude/hooks/state_engine.py find-child-direction --parent-workflow <p> --product-decision <PD> --direction-input-brief-sha256 <brief-sha256>
```
- **없음(`None`)** → 신규 cycle. 새 child workflow-id를 정한다(예: `<p>-direction-<PD 앞 8자>`, 사람이 추적 가능하면 형식은 자유 — dedup은 이름이 아니라 원장의 `parent-workflow-id`+`product-decision-id` 필드로 판정된다).
- **있고 `stage != design-direction-approved` 이며 `stale=False`(브리프 해시 동일)** → **running**: 그 `workflow-id`로 **resume**한다 — 현재 stage에서 `guard`로 다음 스테이지 가능 여부만 확인하고 이어서 진행(처음부터 다시 밟지 않는다).
- **있고 `stage == design-direction-approved` 이며 `stale=False`** → **approved 재사용**: 이미 승인된 방향이 있다. 새로 발산하지 않고 그 child의 approved-direction report를 그대로 반환한다(멱등).
- **있고 `stale=True`(그 사이 브리프가 바뀜)** → 기존 child는 낡은 바인딩이다. 과거 child는 건드리지 않고(불변 이력 보존) **새 child workflow-id로 신규 cycle**을 연다.
3. **init(신규/resume 공통, idempotent):**
`python3 .claude/hooks/state_engine.py init --workflow <child> --plan design-direction --parent-workflow <p> --product-decision <PD> --direction-input-brief <brief-path>`
부모 원장 실존 + `<PD>`가 부모에서 **정확히** accepted 됐는지(위조/substring 우회 불가, `_al_accepted_ids`) + brief 파일 실존을 검증한 뒤에만 원장을 만든다(위반 시 exit 1, 원장 미생성). 이미 원장이 있으면 그대로 반환(overwrite 없음). stage는 자동으로 `design-direction-intake`.
4. **intake 완료 → discovery 진입:** `guard --workflow <child> --to design-direction-discovery`가
parent binding과 brief lint를 통과하면 `complete-stage --workflow <child> --actor OPS-ORCH
--to design-direction-discovery` 후 `enter-stage --workflow <child> --to design-direction-discovery
--actor OPS-ORCH`를 실행한다.
## 0.5 pre-direction — DES-PROD 제품/UX 프레이밍 (frame-divergence 선행 input, **필수**)
> **왜 이 스텝이 있나(F3 fix, 2026-07-16 실측):** §1 discovery의 method인 `DES-DIRECTOR/frame-divergence` 계약의 `required-inputs`는 **DES-PROD/`pre-direction` 이 same-workflow Accepted 로 산출한 `direction-input-brief`** 를 요구한다(`org-os/00-role-registry/role-working-methods/design.yaml`, 둘 다 active). 이 스텝을 건너뛰면 §1의 `des-director` spawn이 `context_package.py` handoff 게이트에서 `handoff input:direction-input-brief 부재`로 **hard block** 된다(과거엔 이 스텝이 문서에 없어 사이클이 첫 spawn에서 막혔다). 브리프 **파일**은 부모 `/design`이 동결하지만, 계약이 요구하는 **Accepted upstream 산출물**은 여기서 DES-PROD가 만든다 — 제품/UX 프레이밍이 비주얼 발산 프레이밍보다 앞서는 더 풍부한 흐름이다.
`des-prod`(role-id DES-PROD, method-id `pre-direction`)를 context-package로 spawn(mode=converge, must-read=direction-input-brief + 부모 product-decision, task-boundaries에 **brief 수정 금지**·**비주얼 해법 지정 금지**). DES-PROD는 동결 브리프를 **분석·정당화**(수정 아님)하여, 대표화면이 왜 signature moment인지와 3안이 두고 갈라질 `divergence-axes` 후보(≥2, tension만 — 구체 팔레트/타이포/레이아웃/메타포 금지)를 낸다. 이 리포트의 primary-artifact 는 동결 브리프.
- `new_report.py --workflow <child> --role DES-PROD --stub --artifact-kind pre-direction-framing
--stage design-direction-discovery`로 typed envelope를 발급해 채운다(report-header BLUF 필수).
- 등재: `artifact-kind: pre-direction-framing`으로 `submit-artifact --actor OPS-ORCH`.
- **수용**: producer DES-PROD와 다른 DES-DIRECTOR가 `review-artifact --decision accepted --reviewer DES-DIRECTOR`로 정확한 revision을 승인한다.
- 이 뒤 §1의 `des-director` context-package 검증이 통과한다(handoff input 충족). **context_package `--role` 은 소문자 카드명**(`des-prod`/`des-director`)으로 넘긴다 — 카드 파일명과 case-verbatim 일치해야 함(F2).
## 1. design-direction-discovery — 불변 brief 분석 + 발산 영역 계약
`des-director`(DES-DIRECTOR)를 context-package로 spawn(mode=converge, must-read=direction-input-brief만 — 다른 방향 자료 없음, task-boundaries에 **brief 수정 금지**를 명시). direction-input-brief를 **분석만**(수정 아님) 하여 findings·constraints-restated·opportunity-notes를 낸다. 이때 브리프의 `representative-screen-requirement`를 구체 화면 하나(id/kind/description, kind ∈ first-entry\|core-task\|signature-moment)로 못박는다 — 다음 divergence의 3안이 전부 이 화면을 구현한다.
- `new_report.py --workflow <child> --role DES-DIRECTOR --stub --artifact-kind direction-discovery
--stage design-direction-discovery`로 envelope를 발급하고 payload에 필수 필드를 쓴다.
- 린트: `python3 .claude/hooks/lint_design_direction.py <path> direction-discovery`(hard fail 0).
- 등재: `artifact-kind: direction-discovery`로 `submit-artifact --actor OPS-ORCH`.
- 이어서 DES-DIRECTOR가 **별도 `divergence-charter`**를 만든다. `direction-set`이라는 이름을 여기서
쓰지 않는다 — charter는 작업 전 지시서이고 direction-set은 작업 후 결과 묶음이다. charter는 정확히
3개 방향에 대해 design-question·layout-topology·navigation-model·typography-voice·imagery-strategy·
motion-model·dominant/exclusive/forbidden-primitives를 정의하고, 모든 방향 쌍이 6개 축 중 최소 4개에서
갈라짐을 `pairwise-separation`으로 증명한다. 팔레트 이름만 다르거나 같은 centered-card shell을 공유하면
lint hard fail이다.
- `new_report.py ... --artifact-kind divergence-charter --stage design-direction-discovery`로 발급 →
`lint_design_direction.py <path> divergence-charter` → submit → producer와 다른 design-approver가 accepted.
- 완료/진입: direction-discovery와 accepted divergence-charter가 모두 있을 때만 `complete-stage
--to design-direction-divergence` → `enter-stage --to design-direction-divergence`.
## 2. design-direction-divergence — 3안 독립 발산(평균 없음)
`des-visual`(DES-VISUAL)을 **3개의 완전히 격리된 subagent**로 띄운다. 이 workflow는 판단 난도가 높으므로
`tier: light`를 사용할 수 없다(최소 standard). 각 run은:
- 별도 `--task`(예: `direction-a`/`direction-b`/`direction-c`)로 `python3 .claude/hooks/context_package.py --compile --workflow <child> --task direction-a --role DES-VISUAL --mode divergent --tier <tier>`를 각각 컴파일 → `context_package.py <pkg>` exit 0 검증 → 출력된 `context-package:`/`context-package-sha256:` 2줄을 그 spawn 프롬프트 최상단에 포함(guard_tools spawn gate 강제). 이 패키지의 sha256이 그 방향의 `context-package-id`가 된다.
- OPS-ORCH가 spawn 직전 발급하는 고유 값(예: `<child>-divergence-<task>-<UTCstamp>`)을 `producer-run-id`로 그 워커에 전달 — 워커는 자기 산출물의 `producer-run-id` 필드에 그대로 echo한다. 3개 run 모두 값이 달라야 하고(hard fail — `_directions_diverged`), 이 값들은 나중에 `/design-review`의 distinctiveness 리뷰어가 이 run과 겹치지 않는지 판별하는 기준이 된다.
- **must-read/non-goals에 형제 방향의 산출물·경로를 명시적으로 배제**한다. must-read는 direction-input-brief + direction-discovery + 자기 id의 divergence-charter 항목이다. 다른 방향 charter 항목과 산출물은 읽지 않는다.
- 각 run은 동일한 **의미적 signature moment**를 자기 charter의 조형 영역에서 구현한다. direction-set에는
reference-cluster(3~6, 방향 쌍 name 중복 최대 1)·visual thesis·layout/interaction grammar·typography-token
direction·primitive-inventory와 함께 hash-bound reference-board·full-size-preview·coded-slice를 넣는다.
foundation 적용 작업은 direction-set top-level에 experience-blueprint/wireframe-set exact ref+SHA를,
각 방향에 동일한 `content-contract-sha256: <wireframe-set SHA>`를 기록한다.
- 각 방향을 같은 실제 viewport에서 **개별 full-size로 렌더**한다. 비교 이미지는 그 PNG들의 contact sheet로
만들며, 세 앱을 좁은 iframe 세 칸에 넣어 responsive breakpoint를 왜곡하지 않는다. `preview_ui.py` receipt는
build/DOM/contrast/focus/viewport의 **render-health 증거**일 뿐 심미 품질 증거로 부르지 않는다.
- `new_report.py ... --artifact-kind direction-set --stage design-direction-divergence`로 발급한
envelope payload에 `direction-cycle-id`·`representative-screen`·`directions`·`comparison-preview`를
넣고 `divergence-charter-ref`+sha256으로 작업 전 계약에 바인딩한다. 린트는 envelope payload를 검증한다.
- 세 안은 동일한 accepted blueprint/wireframe의 콘텐츠·IA·task/state contract를 사용한다. 바꾸는 것은 visual/interaction expression이며, 정보구조를 바꿔 서로 다른 문제를 푸는 것처럼 보이게 하지 않는다. 품질 평가는 absolute 점수만 쓰지 않고 benchmark의 table-stakes/avoid/differentiation에 대한 pairwise 비교를 기록한다.
- **선택 전 비교감사(필수)**: 새 DES-VISUAL run을 `method-id: compare-directions`로 spawn한다. 이 run만
sibling isolation의 예외이며 charter·3안 원본·reference board·full-size preview를 모두 읽는다. 모든 방향
쌍을 layout/navigation/type/imagery/motion/primitives 6축으로 비교하고 4축 미만 차이, 공통 primitive shell,
reference 과다중복을 blocking으로 기록한다. `comparative-divergence-audit` verdict는 pass|revise|re-diverge.
foundation 적용 작업은 competitive benchmark exact ref+SHA 및 최소 3개의
`benchmark-relative-findings`(table-stakes/avoid/differentiation 대비)를 추가한다.
- `lint_design_direction.py --divergence-bundle <audit> <direction-set> <charter>` 통과 후 audit를 submit하고,
producer와 다른 DES-DIRECTOR가 accepted한다. **audit pass 전에는 decision 진입 불가**다.
- 등재 + 완료/진입: `directions-diverged`와 `divergence-audit-passed`가 모두 참일 때만
`complete-stage --to design-direction-decision` → `enter-stage --to design-direction-decision`.
## 3. design-direction-decision — 단일 수렴(평균 금지)
`des-director`(DES-DIRECTOR, synthesis-lead)가 3안의 **원본**(coded-slice·개별 report)을 전부 읽는다(synthesis-rehydration, 요약 아님). HUMAN-001의 결정은 A/B/C/NONE이다.
- A/B/C: `selection-decision: selected`와 정확히 1개 `selected-direction-id`를 기록한다. `rejected-directions`는 나머지를 모두 덮고, `locked-invariants` ≥3, `adopted-elements` 최대 1개다.
- NONE: `selection-decision: none-of-the-above`, selected id/locked/adopted 요소 없이 세 안을 모두 사유와 함께 reject한다. 엔진은 prototype으로 보내지 않고 `design-direction-discovery`로 되돌린다. 세 안을 평균내거나 가장 덜 나쁜 안을 고르지 않는다.
어느 경우든 **`secondary-influence-id` 필드는 절대 넣지 않는다**. `direction-set-ref`+`direction-set-sha256`로 direction-set에 바인딩하고 `parent-workflow-id`/`product-decision-id`/`direction-input-brief-sha256`를 그대로 echo한다.
- 린트(번들 검증): `python3 .claude/hooks/lint_design_direction.py --bundle <selected-direction-path> <direction-set-path>`.
- **수용**: 시각 방향은 취향·브랜드 판단을 포함하므로 HUMAN-001이 `review-artifact --decision accepted
--reviewer HUMAN-001`로 승인한다. EXEC-CPO/에이전트 단독 승인은 상태엔진이 거부한다.
- 등재 + 완료/진입: HUMAN-001 승인 뒤 selected면 prototype으로 진행한다. none-of-the-above면
`complete-stage --actor OPS-ORCH --to design-direction-discovery` →
`enter-stage --to design-direction-discovery --actor OPS-ORCH`로 돌아가 brief framing을 재검토한다.
## 4. design-direction-prototype — 승자 핵심흐름 coded prototype
승자 방향의 locked-invariants/adopted-elements를 그대로 지키며 DES-VISUAL+ENG-FE가 대표 화면 하나가 아니라
**핵심 흐름(core-flow, 여러 화면/상태)**을 코드로 확장한다. 이 단계에서는 방향 전용 토큰만 쓰며,
DES-PLATFORM의 공용 컴포넌트/시스템화는 visual-craft pass 뒤 `/design-system`에서 한다. 거친 탐색값을 일찍
시스템화해 generic component shell로 굳히지 않는다. `revision`은 첫 사이클이면 1, critique 재작업이면 +1.
- `python3 .claude/hooks/preview_ui.py <prototype-dir> --out <prototype-dir>/preview.png --viewports 360,768,1280 --check-css [--states "loading=...,empty=...,error=..."]` → 이 receipt가 `preview-receipt-ref`/`preview-receipt-sha256`.
- `artifact-kind: winner-prototype`, stage=`design-direction-prototype` envelope payload에
direction-cycle-id, selected-direction-ref+sha256, prototype-path+sha256,
preview-receipt-ref+sha256, revision을 쓴다. 린트는 payload를 검증한다.
- 등재 + 완료/진입: `winner-prototype` submit 후 `complete-stage --actor OPS-ORCH
--to design-direction-critique` → `enter-stage --to design-direction-critique --actor OPS-ORCH`.
## 5. design-direction-critique — `/design-review` 7-lens 패널 → verdict로 라우팅
`/design-review --workflow <child>`를 호출한다(패널 절차는 `design-review.md` 참고 — producer-run-id ≠ reviewer-run-id를 그 커맨드가 강제한다). 반환된 `design-review-panel` 아티팩트를 이 커맨드가 등재하고 전이를 라우팅한다(design-review.md 자체는 상태를 전이시키지 않는다):
- 등재: `artifact-kind: design-review-panel`로 `submit-artifact`.
- **verdict = pass** → `complete-stage --actor OPS-ORCH --to design-direction-finalize
--evidence <panel-path>` → `enter-stage --to design-direction-finalize --actor OPS-ORCH`.
- **verdict = minor-revision** → `complete-stage --actor OPS-ORCH --to design-direction-prototype
--evidence <panel-path>` → `enter-stage --to design-direction-prototype --actor OPS-ORCH`.
같은 cycle/selected-direction을 유지하고 revision만 올린다.
- **verdict = concept-flaw** → `complete-stage --actor OPS-ORCH --to design-direction-divergence` →
`enter-stage --to design-direction-divergence --actor OPS-ORCH`. 새 cycle artifact는 새 id로 submit한다.
## 6. design-direction-finalize — approved-direction 불변 report + 부모 원장 기록
**`approved-direction`은 `lint_design_direction.py`에 전용 kind가 없다** — 별도 lint 커맨드로 미리 검증할 수 없으며, `state_engine.py`가 **전이 시점에** `_has_direction_approval`으로 링크·id·hash·receipt 바인딩만 검증한다. 따라서 direction-cycle-id·critique-report-refs·critique-pass-receipt·locked-invariants·approved-at 등 설계 명세의 구조적 필드 존재는 lint로 강제되지 않는다 — **operator가 수동으로 ensure해야 한다**.
`des-director`가 `artifact-kind: approved-direction` report를 불변 경로에 쓰고 `submit-artifact --actor OPS-ORCH`로 등록한다.
- **수용**: producer와 다른 EXEC-CPO가 `review-artifact --decision accepted --reviewer EXEC-CPO`로 승인한다.
- **부모 원장 기록(유일한 등록 경로)**: `python3 .claude/hooks/state_engine.py register-direction-approval --parent-workflow <p> --child-workflow <child> --report <workspace-상대경로> --report-sha256 <sha>` — child stage가 finalize/approved인지, report 파일 실존+hash 일치, 부모에 기존 충돌 approval이 없는지 전부 재검증한 뒤에만 부모 원장에 `design-direction-approval`(report-ref/report-sha256/child-workflow-id)을 기록한다(guard_tools가 직접 YAML 편집을 막으므로 이 CLI가 유일한 경로).
- 완료/진입: exact 8점 approval 검증이 통과하면 `complete-stage --workflow <child>
--actor OPS-ORCH --to design-direction-approved --evidence <report-path>` →
`enter-stage --workflow <child> --to design-direction-approved --actor OPS-ORCH`, 마지막으로 terminal
stage를 `complete-stage`로 닫는다.
- **다음**: 부모 cascade는 `python3 .claude/hooks/state_engine.py check-direction-approved --workflow <p>`(**부모** workflow로 질의 — child로 질의하면 finalize에서도 YES가 나올 수 있어 "전이 가능"과 "최종 승인"을 혼동한다)로 승인 완료를 확인하고 `/design-system`·`/spec`으로 진행한다.
## 규칙 / 불변식
- **격리**: divergence의 3 run과 critique의 7 lens는 각자 독립 context-package로 spawn한다 — 형제의 산출물을 must-read에 넣지 않는다(발산·비평의 다양성이 여기서 나온다).
- **격리 예외**: comparative-divergence-audit만 세 방향 원본을 함께 읽는다. 비교 렌즈를 격리하면
"다르다"는 주장을 검증할 수 없다.
- **리뷰 veto**: critique는 7개 lens 모두 pass여야 한다. distinctiveness/visual-craft concerns,
blocking·critical finding, unresolved-dissent는 DES-DIRECTOR synthesis가 덮을 수 없다.
- **평균 금지**: decision은 정확히 1개를 고르거나 none-of-the-above로 전부 거절한다(`secondary-influence-id` 금지). adopted-elements는 최대 1개, locked-invariants는 침범 불가.
- **producer ≠ reviewer**: 어떤 divergence run이 만든 방향도 critique에서 자기 자신을 심사하지 않는다(`/design-review` 참고).
- **스크린샷 존재 ≠ 품질**: `preview_ui.py`는 반드시 **실제로 실행**해 evidence-ledger receipt(exit 0)를 남긴다 — 문서만으로 렌더를 위장할 수 없다.
- **모든 상태 전이는 OPS-ORCH가 집행**한다(state-transition-rules.yaml의 design-direction 9개 전이 전부 `allowed-by: [OPS-ORCH]`).
- 보고서는 불변이며 직접 원장 편집 대신 `submit-artifact`/`review-artifact`/
`complete-stage`/`enter-stage`/`register-direction-approval`만 쓴다.
- 권한: npm/vite/headless chrome 로컬 빌드·렌더는 허용 범위(design-system.md와 동일). slack/PR/deploy/secret/db-write 등 external side-effect는 기본 금지.
- report-header(BLUF) 없이 종료 금지. evidence 없는 confidence:High 금지.
- **submit은 승인과 다르다.** 다음 워커 spawn 전 producer와 다른 권한 있는 reviewer가 `review-artifact`해야 method-contract handoff gate가 통과한다.
- **coded-slice 는 디렉터리가 아니라 파일 경로여야 한다(F6)** — `_directions_diverged`(state_engine)와 `lint_design_direction._file_sha` 가 `open(coded-slice)` 로 hash 대조하므로 디렉터리면 크래시한다. direction-set 의 각 direction 은 `coded-slice` 를 대표 파일(예: `directions/<id>/Workbench.jsx`)로, `coded-slice-sha256` 을 그 파일 해시로 채운다(워커 프롬프트에도 명시).
- **direction-set을 OPS-ORCH가 쓰면 orchestrate 계약 full 준수가 필요하다(F7)** — envelope의
top-level `method-execution`에 active contract hash와 required step-results를 두고, accept 전
`validate_report.py`를 통과시킨다.
## 산출/handoff
- `completion-records/<child>/approved-direction-<ts>.report.yaml`(불변) + 부모 원장 `design-direction-approval` 링크.
- 중간 산출물: `direction-discovery`·`direction-set`·`selected-direction`·`winner-prototype`·`design-review-panel`(각 completion-records/<child>/ 경로, 통합 원장 artifacts에 등재).
- **다음**: 승인된 방향을 입력으로 `/design-system`(코드 디자인 시스템 확정) 또는 직접 `/spec`으로 진행.