7.9 KiB
7.9 KiB
Cascade 디자인 통합 + End-to-End 오케스트레이터 설계
- 날짜: 2026-07-11
- 상태: 구현 완료 — state_engine
next+_has_preview_receipt,/designUI-bearing 분기,/run-cascade, collaboration-mapdesign-system-gate, 테스트test_p2_cascade_design.py(19)·test_p2_orchestrator.py(34). run_all 17/17 green. - 근거 리뷰: "훅을 고치면 안전한 하네스가 될 뿐, 품질엔 (3)cascade에 통합된 디자인, (4)end-to-end 오케스트레이터, (5)골든태스크 실증이 더 필요하다."
- 선행: P0 신뢰경계 하드닝(커밋 51d101d). 이 설계는 그 위에서 품질 층을 얹는다.
- 실증(항목5) 결과:
benchmark/BENCHMARK.md— low 난이도 code-bugfix(GT-01·GT-R2)에서 plain==harness(둘 다 만점). 하네스 lift는 단순 과제가 아니라 모호·다관점·교차 작업(design/decision/feature)에서 나온다는 가설을 강화. 이 설계(3·4)는 바로 그 경로를 실물로 만든다.
문제 (코드로 확인된 사실)
항목 3 — 디자인이 cascade 밖에 있다
/design(DESIGN stage)은 설계 문서만 fan-out한다(fam-architecture-tech·fam-design·fam-data·fam-security).fam-design은 "UX/UI·디자인시스템"을 개념적으로 다루고 design-brief를 채우지만, 코드 디자인 시스템 파이프라인(discovery→tokens.css→components→screens→preview_ui렌더·품질게이트)을 돌리지 않는다./design-system은 그 렌더 산출물을 만드는 독립 커맨드로, cascade에서 호출되지 않는다.collaboration-map.yaml의design-to-build-contract는FAM-ENG-FRONTEND의 must-read-designs로 **design-system**을 이미 요구한다(Accepted 전 프론트 BUILD 금지). 그런데 그design-system산출물을 생산·게이팅하는 cascade stage가 없다 → 계약과 생산의 미스매치. 결과: 프론트 기능이 설계문서 → spec → build로 흐르는 동안 실제 렌더된 화면(상태 loading/empty/error/overflow·반응형·대비·포커스)을 한 번도 검증하지 않을 수 있다("docs는 있는데 pixels는 없다").
항목 4 — 상위 end-to-end 오케스트레이터가 없다
/ceo-intake·/ground·/decide·/design·/spec·/build가 전부 사람이 수동 호출하는 개별 커맨드다.state_engine이 stage 순서를 강제하지만(예: 설계 Accepted 없으면/build거부), 다음 커맨드를 반드시 호출하게 만드는 것은 없다 — 사람이/design후 멈추고 하네스 밖에서 코딩해버릴 수 있다. 전 과정을 일관되게 걷고 사람 결정 지점에서만 멈추는 단일 진입점이 없다.
설계
항목 3 — 디자인 파이프라인의 조건부 cascade 통합
원칙: 조건부 게이팅. 모든 cascade가 UI를 만들지 않는다. 백엔드/인프라/데이터/의사결정 워크플로에 design-system을 강제하면 과설계다. UI를 만드는 워크플로에서만 렌더 게이트를 요구한다.
- UI-bearing 술어. 워크플로가 UI-bearing = 그 BUILD 계획에
FAM-ENG-FRONTEND가 포함(사용자 대면 UI). 이는design-to-build-contract가 이미 인코딩한 것(FAM-ENG-FRONTEND→design-system)과 동치다. DECIDE에서ExecutiveDecisionPacket에ui-bearing: true|false를 명시하거나, 계획된 build family에서 파생한다. - UI-bearing이면 DESIGN이 렌더 산출물을 생산.
/design의fam-design분기는 design-system 서브파이프라인(=/design-system절차: discovery→design-brief→tokens/components/screens→preview_ui게이트)을 돌리고design-type: design-system산출물을 낸다. 그 **acceptance는 통과한preview_uireceipt(E4/E5)**를 요구한다 — 산문 문서가 아니라 렌더 증거(#root 비어있지 않음·WCAG 대비 ok·포커스 가시·반응형 스냅샷). - state_engine 강제.
design-system산출물의 acceptance가 must-read-designs-accepted에 카운트되려면 evidence-ledger에 **preview_ui receipt(E4/E5)**가 결속돼야 한다 — 렌더된 적 없는 design-system을 "Accepted"로 위장 불가. non-UI 워크플로는 FAM-ENG-FRONTEND 매핑이 적용 안 되므로 design-system 불요(과차단 없음). - 기계를 새로 만들지 않고 배선.
/design커맨드: "UI-bearing이면 design-system 서브파이프라인이 DESIGN의 일부 — preview_ui로 게이팅된design-system산출물을 낸다./design-system절차를 따른다" 조건부 섹션 추가.collaboration-map.yaml:design-system(FAM-ENG-FRONTEND)이 preview_ui 게이트(E4/E5)를 요구함을 명시.state_engine.py:design-systemdesign-type의 accepted 카운트에 preview_ui receipt 결속 요건 추가(없으면 must-read 충족으로 안 침)./design-system은 독립 호출도 유지(하위호환) —/design이 UI 서브파이프라인으로 참조.
비목표: 백엔드/인프라/의사결정 워크플로에 design-system 강제 금지. 모든 cascade에 /design-system 필수화 금지.
항목 4 — 얇은 오케스트레이터 /run-cascade
원칙: 기존 state graph 위의 얇은 드라이버. 평행 엔진을 새로 만들지 않고 state_engine을 재사용한다. 사람 게이트에서 멈추는 것이 존재 이유 — 절대 자동 승인/자동 완주하지 않는다.
state_engine.py next --workflow <wf>— 신규 결정론적 서브커맨드. 반환:current-stage,next-stage(execution-plans cascade 그래프에서),guard: next-stage 진입 게이트 결과(pass / block + 사유) — 기존can_transition재사용,human-gate: true|false+what+approver— governance-tiers human-gate + DRAI decider=human + DECIDE(go/no-go) + release에서 파생,command: next-stage에 대응하는 커맨드(/ground·/decide·/design·/spec·/build·…)와 spawn할 families.
/run-cascade커맨드 = Orchestrator가 따르는 얇은 루프:state_engine.py next호출.guard가 block → 미충족 선행조건을 담은 BlockedReport + 정지.human-gate→ decision-needed 보고(BLUF: 무슨 결정·승인자·근거) + 정지(진행 금지). 사람이 승인(acceptance_log/signoff)한 뒤/run-cascade재호출로 재개.- 아니면 → 해당 stage 커맨드 절차를 따른다(그 stage의 families만 fan-out) → 산출물 →
transition으로 전진 → 루프. released에서 종료.
- 불변식(반드시):
- state_engine guard/transition 재사용 — 평행 엔진 금지.
- 사람 게이트 자동 승인 금지(멈추는 것이 목적).
- 각 stage는 여전히 자기 context-package spawn 게이트·validator·token/lens 게이트를 통과.
- resumable:
next가 현재 state를 읽으므로, 사람 승인 후 재호출하면 멈춘 지점부터 계속(mid-start).
정지 지점(사람 게이트): DECIDE(go/no-go)·tier=heavy plan-signoff·Release acceptance(DRAI decider=human)·guard가 block하는 모든 stage.
테스트 계획
test_p2_cascade_design.py(신규): (a) UI-bearing 워크플로에서 design-system 없이 spec→build guard가 block, (b) preview_ui receipt 없는 design-system accepted는 must-read 충족으로 안 침, (c) non-UI 워크플로는 design-system 불요로 통과.test_p2_orchestrator.py(신규): (a)state_engine.py next가 current/next/guard/human-gate/command를 정확히 반환, (b) DECIDE·release에서 human-gate=true, (c) guard block 시 next가 block 사유 노출, (d) 재호출 resumable.- 회귀:
run_all.py(doctor+lint_refs+모든 test_*) 그린 유지,gen_agents.py --check정합.
롤아웃
- 항목5 벤치마크 실증(완료 — BENCHMARK.md).
- state_engine
next+ preview_ui-gated design-system 강제(코어). /run-cascade·/design커맨드 배선(프롬프트 층).- 테스트 + doctor/lint_refs/run_all 그린 + 커밋.