Files
llm-wiki/docs/superpowers/specs/2026-06-06-spec-d-research-fanout-workflow-design.md
T

169 lines
9.9 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.
---
title: "Spec D — research-fanout Workflow (scoped, Claude 전용, opt-in)"
source_type: llm-generated
status: draft
confidence: medium
tags: [harness, claude-code, workflow, design, automation]
last_reviewed: 2026-06-06
---
# Spec D — research-fanout Workflow
> 상위 감사: [[2026-06-06-harness-audit-report]] §3 G2. 확정 결정: **scoped research-fanout Workflow**(전체 명령 변환 아님), **승인 완료**. **구현(파일 Write + Workflow 실행)은 opt-in 시.**
## 1. 문제 (감사에서) + 재설계
- **G2 (P2)**: `/branch-spec`·`/project-spec` 오케스트레이션이 산문-자문(번호 매긴 LLM 지시). controller 가 단계를 건너뛰어도 탐지 안 됨. deep-research 의 코드 barrier 와 대비.
- **재설계 (브레인스토밍 발견):** 두 명령은 **비-기계적 부분**이 본질적이다 — `project-spec §3` 의 `AskUserQuestion`(사용자 소유 결정), ca-tmpl ground-truth 정독(판단), 노트 채움(user-content 보존), 다이어그램 작성. **전체를 Workflow 로 변환하면 이 상호작용·판단이 깨진다(YAGNI 위반).**
- 따라서 **순수 fan-out 서브페이즈만** 추출: `/branch-spec §5`(결정별 bounded 자동조사 — `wiki-decision-researcher` ×N, cap 6, deferred). 이것이 deep-research 의 `pipeline(angles → research → schema)` 와 정확히 동형이다.
## 2. 핵심 원리 / 비목표
- **산문 명령은 유지** (3-플랫폼). Claude 만 *옵션으로* Workflow 를 호출해 §5 의 병렬 조사를 빠르고 schema-강제·cap-보장으로 수행. Codex/Antigravity 는 기존 순차 dispatch — **parity 안 깨짐.**
- A/B/C 메커니즘의 **진짜 Workflow 형태**: tool-layer `agent({schema})`(B 를 hope→enforce 로) · funnel `found=processed+dropped`(C) · cap+deferred(C no-silent-truncation).
- **autonomous** 조사(deep-research 처럼 user-approval 없이) — 산문 `wiki-decision-researcher`(WebSearch→승인→fetch)와의 trade-off. 둘 병존, 사용자 선택.
- **비목표**: 전체 명령 변환 · `project-spec` 변환(AskUserQuestion 본질적, v2 후보) · verify gate 의 Workflow 화(별도). branch-note 직접 편집(Workflow 는 input 만 반환, 산문 controller 가 §7 채움).
## 3. 설계 결정 (확정)
### DD1 — scoped fan-out only
Workflow 는 §5(결정별 조사 burst)만. §1~4(전제·ground-truth·결정추출)와 §6~9(라벨·채움·게이트)는 산문 controller.
### DD2 — autonomous + schema-enforced
각 결정을 `agent({schema: ALT_SCHEMA})` 로 병렬 조사. user-approval 없음(autonomous). 결과는 구조화된 비교매트릭스.
### DD3 — Claude 전용, 산문은 불변
`.claude/workflows/research-fanout.*` 신규. `/branch-spec §5` 에 "옵션: Claude 에서 research-fanout Workflow 호출" 한 줄만 추가(산문 흐름·3-플랫폼 미러 불변).
## 4. 아키텍처 — Workflow 스크립트
```js
export const meta = {
name: 'research-fanout',
description: 'Bounded parallel alternatives-research for N branch decisions (autonomous, schema-enforced)',
phases: [
{ title: 'Scope', detail: 'validate + cap decisions (max 6), split deferred' },
{ title: 'Research', detail: 'parallel autonomous web research per decision, schema-enforced' },
{ title: 'Synthesize', detail: 'comparison matrices + funnel stats + branch-note DEM input' },
],
}
const MAX_DECISIONS = 6
const ALT_SCHEMA = {
type: "object", required: ["decision", "alternatives", "recommendation", "confidence"],
properties: {
decision: { type: "string" },
alternatives: { type: "array", minItems: 2, maxItems: 5, items: {
type: "object", required: ["name", "pros", "cons", "sources"],
properties: {
name: { type: "string" },
pros: { type: "string" },
cons: { type: "string" },
sources: { type: "array", items: { type: "string" } }, // URL
quote: { type: "string" }, // verbatim 인용
sourceType: { enum: ["official-doc", "company-tech-blog", "personal-blog", "unknown"] },
},
}},
recommendation: { type: "string" },
confidence: { enum: ["high", "medium", "low"] },
unsupported: { type: "boolean" }, // 조사 후에도 근거 부족 → UNSUPPORTED_DECISION
},
}
// ── Scope: cap + deferred (no silent truncation) ──
phase("Scope")
const decisions = (args && Array.isArray(args.decisions)) ? args.decisions : []
if (!decisions.length) {
return { error: "No decisions. Pass args.decisions = [{topic, parentBranch, constraints, n}]." }
}
const capped = decisions.slice(0, MAX_DECISIONS)
const deferred = decisions.slice(MAX_DECISIONS)
log(`${decisions.length} decisions → research ${capped.length}, defer ${deferred.length}`)
const researchPrompt = (d) =>
"## Alternatives Researcher (autonomous)\n\n" +
"Branch decision: \"" + d.topic + "\"\n" +
"Parent branch: " + (d.parentBranch || "(none)") + "\n" +
"Constraints: " + (d.constraints || "(none)") + "\n\n" +
"## Task\n" +
"1. WebSearch official docs + 대기업 기술블로그 for " + (d.n || 3) + " viable alternatives.\n" +
"2. WebFetch each; extract Pros/Cons + a verbatim quote + source URL + sourceType.\n" +
"3. company-tech-blog 만으로 '공식 best practice' 승격 금지(독립 사례 2+ 또는 official 병행).\n" +
"4. 근거가 한쪽으로 명확하면 그대로 recommendation. 가짜 5:5 균형 금지.\n" +
"5. 조사 후에도 근거 부족하면 unsupported=true.\n\nStructured output only."
// ── Research: 진짜 병렬 + tool-layer schema 강제 ──
phase("Research")
const results = (await parallel(
capped.map(d => () =>
agent(researchPrompt(d), { label: "research:" + d.topic.slice(0, 30), phase: "Research", schema: ALT_SCHEMA })
.then(r => r ? { ...r, topic: d.topic } : null)
)
)).filter(Boolean)
// ── Synthesize: funnel + branch-note DEM input ──
phase("Synthesize")
const failures = capped.length - results.length
const stats = {
found: decisions.length,
processed: results.length,
dropped: deferred.length + failures,
dropped_reason: [
deferred.length ? `${deferred.length} over cap(${MAX_DECISIONS})` : null,
failures ? `${failures} research failed/skipped` : null,
].filter(Boolean).join("; ") || "none",
}
// 불변식: found = processed + dropped (decisions.length = results + deferred + failures) ✓
log(`done: ${results.length} researched, ${stats.dropped} dropped`)
return {
matrices: results,
deferred: deferred.map(d => d.topic),
unsupported: results.filter(r => r.unsupported).map(r => r.topic),
stats,
// 산문 controller 가 §7 Decision Evidence Map 채움에 쓰는 input (Workflow 는 노트 직접 편집 안 함)
branchNoteInput: results.map(r => ({
decision: r.topic, recommendation: r.recommendation, confidence: r.confidence,
sources: r.alternatives.flatMap(a => a.sources), unsupported: !!r.unsupported,
})),
}
```
### 4.1 산문 `/branch-spec` 변경 (한 줄 — Claude 전용 옵션)
§5 에 추가:
> **(옵션, Claude 전용)** 결정 수가 많거나 빠른 병렬 조사를 원하면 `research-fanout` Workflow 를 호출한다(`Workflow({name:'research-fanout', args:{decisions:[...]}})`, ultracode/opt-in 필요). 반환된 `matrices`/`branchNoteInput` 으로 §7 Decision Evidence Map 을 채우고, `stats`/`deferred` 를 §9 요약에 반영. **autonomous 조사라 user-approval 이 없으므로**, 승인-gated 가 필요하면 기존 `wiki-decision-researcher` 순차 dispatch 를 쓴다. Codex/Antigravity 는 항상 순차 dispatch.
## 5. 위험
| 위험 | 완화 |
|---|---|
| autonomous 조사가 user-approval 우회 | 산문 `wiki-decision-researcher`(승인-gated)와 병존 — 사용자가 선택. §5 에 trade-off 명시. |
| Workflow Claude 전용 → parity | 산문 명령 불변(3-플랫폼). Workflow 는 *추가* 옵션. project 파이프라인처럼 명시적 Claude 예외. |
| cap 초과 silent 절단 | `deferred` 명시 반환 + funnel `dropped_reason`. |
| schema 강제로 agent 재시도 비용 | deep-research 와 동일 — tool-layer 검증이 신뢰성↑. cap 6 으로 비용 bound. |
| Workflow 실행 opt-in 필요 | spec/plan 은 지금, 실행은 ultracode opt-in. 산문 경로는 항상 가용(non-opt-in fallback). |
## 6. 수용 기준 (검증 가능 — opt-in 실행 시)
1. `Workflow({name:'research-fanout', args:{decisions:[3개]}})``matrices` 3개 + `stats.found=3, processed+dropped=3`.
2. 8개 decisions → 6 researched + `deferred` 2개 명시 + `stats.dropped≥2 with dropped_reason`.
3. 빈 decisions → `{error}` (graceful).
4. 각 matrix 가 ALT_SCHEMA 충족(alternatives ≥2, sources 배열, recommendation/confidence).
5. `branchNoteInput` 이 산문 §7 채움에 바로 쓰일 형태(decision/recommendation/sources/unsupported).
6. 산문 `/branch-spec` 의 기존 순차 경로(비-Workflow)가 여전히 동작(Workflow 미사용 fallback).
## 7. 구현 순서 (writing-plans — 실행은 opt-in)
1. (opt-in) `.claude/workflows/research-fanout.*` 에 §4 스크립트 Write.
2. (opt-in) `Workflow({name:'research-fanout', args:{decisions:[테스트 2-3개]}})` 실행 → §6.1·6.4 검증.
3. (opt-in) 8개 decisions 로 cap/deferred 검증(§6.2).
4. `/branch-spec §5` 에 옵션 호출 한 줄 추가(§4.1) — 이건 산문 편집이라 opt-in 불요(언제든).
5. (opt-in) §6 전 항목 스모크.
> **경계:** 4번(산문 한 줄)은 비-opt-in 으로 지금 가능. 1~3·5(Workflow Write+실행)는 `Workflow` 툴 opt-in 시. plan 이 이 경계를 task 별로 명시.
## 8. 메모
- 이건 "전체 오케스트레이션 결정론화"(원래 G2 야망)가 아니라 *기계화 가능한 한 조각*만 deep-research 형태로. 나머지 산문 오케스트레이션은 interactive/judgment 라 산문이 옳다 — 그 결론 자체가 D 의 산출.
- A(구조 게이트)·B(verdict schema)·C(stats)·D(research-fanout Workflow)로 deep-research 8원칙이 하네스 전반에 이식됨 — 단 P2(코드 오케스트레이션)는 *기계화 가능한 부분에 한해*.