Files
connectai/src/features/company/pipelineTemplates.ts
T
koriweb ebfce17b03 fix: v2.2.203 — 기업모드 dev-impl 빈 깡통 99% 버그 (hollow check 기본 ON)
증상: 사용자가 기획서 + 폴더 주고 "여기 개발해줘" 요청 → ASTRA 가 파일 만들고
"개발 완료" 보고 → 실제 파일을 열면 class/함수 본문이 비어 있음
(def foo(): pass · 빈 class · imports only). 99% 확률 재발.

원인:
- 안전망 이미 존재 (selfReflectorHollow.ts 가 정규식으로 빈 깡통 감지)
- BUT 두 개 config 모두 OFF — selfReflectorEnabled (Phase A) +
  selfReflectorExternalEnabled (Phase B)
- Phase A 켜면 [Self-Reflector Check] 블록이 답변에 노출 (UX 부작용),
  Phase B 는 +1 LLM 호출 비용 — 부작용 때문에 기본 OFF
- 결과: 다수 사용자가 안전망 전혀 없는 상태로 코드 작성 → 빈 깡통 통과

Fix 3종:

1. Hollow check 를 selfReflector 와 분리 — 신규 설정 2개:
   - g1nation.hollowCheck.enabled (boolean, 기본 ON) — action-tag 있는 모든
     응답에 무조건 hollow 스캔. LLM 호출 0.
   - g1nation.hollowCheck.autoRetry (boolean, 기본 ON) — 검출 시 1회 자동
     재작업. Phase B 와 분리.
   - dispatcher.ts 게이트 조건 교체

2. dev-impl 프롬프트 강화 (pipelineTemplates.ts) — [빈 깡통 금지] 5개 규칙:
   - 파일은 하나씩 생성, 모든 함수 본문 완전 구현 후 다음 파일로
   - 금지 패턴 명시: pass · ... · NotImplementedError · # TODO · 빈 class
   - 인터페이스/추상 메서드만 빈 본문 OK
   - 각 파일 생성 직후 자가 검증
   - 최종 요약에 파일별 핵심 동작 한 줄씩

3. 기본값 변경 — 사용자 행동 없이 안전망 작동. 옛 selfReflector Phase A/B 는
   그대로 OFF (UX 부작용 보존).

예상 효과: ~70-85% stub 감소. 남은 ~15% (작은 모델 attention 한계 / 큰 프로젝트)
는 per-file 순차 생성으로 v2.2.204+ 검토.

모델 한계 vs 로직 fix: 대부분 로직 fix 가능. 매우 작은 모델 (≤4B) 은 한계 더
빠름 — 더 큰 모델 (gemma-12b, qwen-32b) 권장.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 11:52:12 +09:00

286 lines
16 KiB
TypeScript

/**
* Built-in pipeline templates for 1인 기업 모드.
*
* These are *blueprints*, not data — they're surfaced in the manage panel's
* "템플릿에서 추가" dropdown so a non-developer user can stamp out a
* working pipeline in one click and then tweak the labels / 지시 / agent
* assignments in the card editor. Once stamped, the pipeline lives in
* `state.pipelines` like any other; templates themselves stay read-only in
* code so a future Astra version can ship improved defaults without
* trampling user edits.
*
* Why ship a template at all: the user's own description of the desired
* workflow ("작업 수락 → 기획 → 시장 조사 → … → QA → 배포") is exactly the
* shape this codifies. Without the template they'd have to author 13
* cards from scratch the first time they open the editor — which is
* exactly the friction we're trying to remove.
*/
import { PipelineDef } from './types';
export interface PipelineTemplate {
/** Stable id used by the UI dropdown and `applyTemplate` call. */
templateId: string;
/** Korean display name shown in the dropdown. */
name: string;
/** One-line description of when this template fits. */
description: string;
/**
* Default pipeline id when stamping. The UI will suggest this and let
* the user override before saving so two stamps don't collide.
*/
suggestedPipelineId: string;
/** Default human-readable name for the stamped pipeline. */
suggestedPipelineName: string;
/** Stage definitions — same shape as a saved PipelineDef.stages. */
stages: PipelineDef['stages'];
}
/**
* "풀 프로덕트 개발" — the user's described workflow, codified:
* 1. 작업 수락 — CEO 브리프 (자동, 별도 stage 아님)
* 2. 기획 논의 — planner
* 3. 시장 조사 — researcher
* 4. 트렌드 조사 — researcher
* 5. 방향성 정의 — planner
* 6. 기획문서 작성 — planner
* 7. 기획문서 검토 — inspector (재작업 발견 시 → 6번 loop-back)
* 8. 기획문서 최종본 — planner
* 9. 개발 설계 — developer
* 10. 설계 검토 — inspector (재작업 발견 시 → 9번 loop-back)
* 11. 개발 진행 — developer
* 12. QA 진행 — qa (버그 발견 시 → 11번 loop-back)
* 13. 라이브 배포 — developer
*
* 1번 "작업 수락"은 별도 stage가 아니라 CEO의 브리프 발신 — 모든 pipeline
* turn은 자동으로 brief를 생성해 `{{brief}}` 토큰으로 사용 가능하다.
*
* 지시 템플릿은 작은 LLM이 가장 자주 어기는 두 가지 — (a) 기획 문맥 잊기,
* (b) 단순 코드만 던지기 — 를 강하게 누른다. 사용자가 처음 보면 길어
* 보일 수 있는데, "이 단계에서 정확히 뭘 해야 하나" 가이드가 필요한
* 작은 모델 (gemma e2b·4b 등)에서 결과 품질을 크게 좌우한다.
*/
const FULL_PRODUCT_DEV: PipelineTemplate = {
templateId: 'full-product-dev',
name: '풀 프로덕트 개발 (13단계)',
description: '기획 → 리서치 → 기획서 → 검토 → 설계 → 개발 → QA → 배포. 기획 누락 없이 풀 사이클을 도는 표준 워크플로.',
suggestedPipelineId: 'product-dev',
suggestedPipelineName: '제품 개발 파이프라인',
stages: [
// 모든 stage가 *직군*만 지정하고 담당자는 비워둠 (agentId 생략). dispatcher가
// stage 진입 시 CEO에게 1회 LLM 콜로 적임자 선택. 활성 후보가 1명뿐이면
// 콜 없이 그 사람을 쓴다. 사용자의 의도("CEO가 배분 결정")와 일치.
{
id: 'plan-discuss',
label: '기획 논의',
roleCategory: 'planner',
instructionTemplate:
'사용자 요청: {{userPrompt}}\n\n' +
'이번 작업의 목표·사용자·성공 기준을 정리하세요. 결정 사항이 아니라 *논의 정리* 단계입니다.\n' +
'- 누구를 위한 결과물인가\n- 핵심 가치 한 줄\n- 우리가 모르는 것 / 더 알아봐야 할 것\n- 위험 요소',
},
{
id: 'market-research',
label: '시장 조사',
roleCategory: 'researcher',
instructionTemplate:
'기획 논의 정리: {{stage.plan-discuss}}\n\n' +
'위 맥락에서 *시장 측면*을 조사하세요. 추측 금지, 데이터/사례 기반.\n' +
'- 비슷한 시도가 이미 있나 (3개 이상)\n- 시장 크기·고객 페르소나\n- 가격대·수익화 패턴\n결과는 "출처(또는 일반론임을 명시)" 표시.',
},
{
id: 'trend-research',
label: '트렌드 조사',
roleCategory: 'researcher',
instructionTemplate:
'기획 논의: {{stage.plan-discuss}}\n시장 조사 결과: {{stage.market-research}}\n\n' +
'*최근 트렌드*를 조사하세요. 6개월 이내 변화를 우선.\n' +
'- 떠오르는 키워드/패턴\n- 사용자 기대치 변화\n- 우리가 활용할 수 있는 기술/문화 신호',
},
{
id: 'direction',
label: '방향성 정의',
roleCategory: 'planner',
instructionTemplate:
'기획 논의: {{stage.plan-discuss}}\n시장: {{stage.market-research}}\n트렌드: {{stage.trend-research}}\n\n' +
'위 3개를 종합해 *우리가 갈 방향*을 한 문단으로 결론지어요.\n포함:\n' +
'- 무엇을 만들 것인가 (제품 한 줄 설명)\n- 누가 첫 사용자인가\n- 안 만들 것 (out of scope)\n- 성공 판단 기준 1~3가지',
},
{
id: 'plan-draft',
label: '기획문서 초안',
roleCategory: 'planner',
instructionTemplate:
'방향성: {{stage.direction}}\n\n' +
'이 방향에 맞는 *기획서 초안*을 마크다운으로 작성하세요.\n' +
'필수 섹션:\n' +
'## 배경\n## 목표\n## 핵심 사용자 시나리오 (3개 이상, 구체적)\n## 주요 기능 목록\n## 비기능 요구사항\n## 측정 지표 (KPI)\n## 미래 확장 / 비-목표\n\n' +
'아직 *최종본 아님* — 검토자가 피드백 줄 수 있도록 가정·미확정 사항을 명시하세요.',
},
{
id: 'plan-review',
label: '기획문서 검토',
roleCategory: 'inspector',
instructionTemplate:
'검토 대상: {{stage.plan-draft}}\n\n' +
'*감리* 관점에서 기획서를 검토하세요. 칭찬 X, 구체적 피드백 O.\n' +
'확인 사항:\n- 시나리오가 구체적인가 ("사용자가 X를 한다" vs "사용자가 잘 쓴다")\n' +
'- 기능 vs 시나리오 매핑이 1:1로 되는가\n- 측정 가능한 성공 기준이 있는가\n- 빠진 케이스/엣지 케이스\n\n' +
'결론은 반드시 "✅ 승인" 또는 "❌ 재작업 필요: <항목 나열>" 로 시작.',
loopBackPattern: '재작업 필요|reject|보완 필요',
loopBackTo: 'plan-draft',
maxIterations: 3,
},
{
id: 'plan-final',
label: '기획문서 최종본',
roleCategory: 'planner',
instructionTemplate:
'초안: {{stage.plan-draft}}\n검토 피드백: {{stage.plan-review}}\n\n' +
'피드백을 모두 반영해 *최종 기획서*를 다시 쓰세요. 다음 단계(개발 설계)에서 그대로 사양서로 쓸 정도로 명확해야 합니다.',
},
{
id: 'dev-design',
label: '개발 설계',
roleCategory: 'developer',
instructionTemplate:
'최종 기획서: {{stage.plan-final}}\n\n' +
'이 기획서 기준으로 *개발 설계 문서*를 작성하세요. 아직 코드는 쓰지 않습니다.\n' +
'포함:\n## 데이터 모델\n## 컴포넌트/모듈 분할\n## 외부 의존성\n## 단계별 구현 순서 (체크리스트)\n## 테스트 전략\n## 알려진 리스크',
},
{
id: 'design-review',
label: '설계 검토',
roleCategory: 'inspector',
instructionTemplate:
'설계 문서: {{stage.dev-design}}\n기획서: {{stage.plan-final}}\n\n' +
'설계가 기획 의도를 모두 커버하는지 *감리*하세요. 누락된 시나리오·과도한 over-engineering이 있나.\n' +
'결론은 "✅ 승인" 또는 "❌ 재작업 필요: ..." 로 시작.',
loopBackPattern: '재작업 필요|reject|보완 필요',
loopBackTo: 'dev-design',
maxIterations: 2,
},
{
id: 'dev-impl',
label: '개발 진행',
roleCategory: 'developer',
instructionTemplate:
'설계: {{stage.dev-design}}\n기획서: {{stage.plan-final}}\n\n' +
'설계대로 *실제 코드를 작성*하세요. 반드시 ConnectAI 액션 태그(`<create_file>`, `<edit_file>`, `<run_command>`)를 사용해 디스크에 떨어지도록.\n' +
'코드 블록만 보여주고 "생성 완료"라고 말하면 디스크엔 아무것도 안 만들어집니다.\n\n' +
'[빈 깡통 금지 — 가장 자주 발생하는 실패 패턴]\n' +
'1. 파일은 **하나씩** 생성. 한 파일 안의 **모든 함수·메서드·클래스 본문을 완전히 구현** 후 다음 파일로.\n' +
'2. **금지 패턴**: `def foo(): pass` · `def foo(): ...` · `def foo(): raise NotImplementedError` · `def foo(): # TODO` · 빈 class 본문 (`class Foo: pass`) · imports 만 있는 파일.\n' +
'3. 함수 본문이 정말 비어도 되는 경우는 *인터페이스/추상 메서드* 만. 나머지는 **무조건 동작하는 코드** 작성. 단순화는 OK, 빈 깡통은 NO.\n' +
'4. 각 파일 생성 직후 한 줄 자가 검증: "이 파일이 정말 동작하나? 빈 본문 없나?". 없으면 보강 후 `<edit_file>` 로 재기록.\n' +
'5. 모든 파일 생성 끝나면 *최종 요약* 에 (a) 생성된 파일 수 (b) 각 파일의 핵심 함수 동작 한 줄씩 명시.\n\n' +
'⚠️ "구조만 잡고 추후 구현" 패턴은 즉시 검출돼 자동 재작업이 트리거됩니다. 처음부터 본문까지 완전 구현하세요.',
},
{
id: 'qa',
label: 'QA 진행',
roleCategory: 'qa',
instructionTemplate:
'구현 결과: {{stage.dev-impl}}\n기획서: {{stage.plan-final}}\n\n' +
'*테스트 시나리오를 직접 실행*해 기능을 검증하세요. 케이스별로 PASS/FAIL 명확히 적고, 실패 시 재현 방법을 적어요.\n' +
'결론은 "✅ 모든 케이스 통과" 또는 "❌ 버그 발견: ..." 로 시작 (loop-back regex가 이걸 봅니다).',
loopBackPattern: '버그 발견|❌|버그|오류|실패',
loopBackTo: 'dev-impl',
maxIterations: 4,
},
{
id: 'deploy',
label: '라이브 배포',
roleCategory: 'developer',
instructionTemplate:
'QA 통과 결과: {{stage.qa}}\n\n' +
'배포 절차를 *실행*하세요. README 갱신, 버전 태깅, 배포 스크립트 실행 등 필요한 명령은 `<run_command>` 로.\n' +
'마지막에 배포된 상태 요약과 사용자에게 안내할 한 줄 (📝 다음).',
},
],
};
/**
* 짧은 "기획만" 워크플로 — 사용자가 기획문서까지만 필요한 경우. 각 산출물
* stage에 3-way 검수 사이클을 켜서 셋(작업자 + 감리 + CEO) 합의로 통과
* 시키는 패턴을 보여준다. 풀-프로덕트와 달리 별도 review stage를 두지 않고
* 사이클로 합쳐서 빠르게 끝낸다.
*/
const PLAN_ONLY: PipelineTemplate = {
templateId: 'plan-only',
name: '기획서까지만 (검수 사이클)',
description: '시장 조사 → 방향성 → 기획서. 각 산출물 stage에서 검수자 + CEO 합의로 통과시키는 짧은 워크플로.',
suggestedPipelineId: 'plan-only',
suggestedPipelineName: '기획서 작성',
stages: [
{
id: 'market-research',
label: '시장 조사',
roleCategory: 'researcher',
instructionTemplate:
'사용자 요청: {{userPrompt}}\n\n' +
'이 요청 맥락에서 *시장 측면*을 조사하세요. 추측 금지, 데이터/사례 기반.\n' +
'- 비슷한 시도가 이미 있나 (3개 이상)\n- 시장 크기·고객 페르소나\n- 가격대·수익화 패턴\n' +
'결과는 "출처(또는 일반론임을 명시)" 표시.',
},
{
id: 'direction',
label: '방향성 정의',
roleCategory: 'planner',
instructionTemplate:
'사용자 요청: {{userPrompt}}\n시장 조사: {{stage.market-research}}\n\n' +
'*우리가 갈 방향*을 한 문단으로 결론짓고 측정 가능한 성공 기준을 1~3개 적으세요.',
reviewWith: 'inspector',
reviewMaxRounds: 3,
},
{
id: 'plan-doc',
label: '기획문서',
roleCategory: 'planner',
instructionTemplate:
'방향성: {{stage.direction}}\n\n' +
'아래 섹션 구조로 *기획서*를 마크다운으로 작성하세요. 합의 통과 후엔 사장님께 그대로 전달됩니다.\n\n' +
'## 배경\n## 목표\n## 핵심 사용자 시나리오 (3개 이상, 구체적)\n## 주요 기능 목록\n## 비기능 요구사항\n## 측정 지표 (KPI)\n## 미래 확장 / 비-목표',
reviewWith: 'inspector',
reviewMaxRounds: 3,
},
],
};
/**
* "개발까지만" — FULL_PRODUCT_DEV 의 1~10 단계 (plan-discuss ~ dev-impl) 만 진행.
* QA·배포는 사용자가 코드 받아본 뒤 수동 처리하길 원하는 경우. dev-impl 종료
* 직후 CEO 합산 보고로 turn 종료. design-review 의 dev-design loop-back 은 유지.
*
* stages 는 FULL_PRODUCT_DEV.stages.slice(0, 10) 으로 *참조 공유* — 사용자가
* 템플릿 stamp 시 deep-copy 되므로 본 정의 객체는 read-only 안전.
*/
const DEV_ONLY: PipelineTemplate = {
templateId: 'dev-only',
name: '개발까지만 (10단계)',
description: '풀 워크플로에서 QA·배포 단계를 뺀 버전. 기획 → 개발까지 만들고 검증·배포는 사용자가 직접 챙깁니다.',
suggestedPipelineId: 'dev-only',
suggestedPipelineName: '기획→개발 파이프라인',
stages: FULL_PRODUCT_DEV.stages.slice(0, 10),
};
/** Read-only registry of templates the UI surfaces. */
export const PIPELINE_TEMPLATES: PipelineTemplate[] = [
PLAN_ONLY,
DEV_ONLY,
FULL_PRODUCT_DEV,
];
/**
* 스코프 단축 표기 — 사용자가 사이드바에서 한 번에 보고 선택할 수 있는 3-way 라벨.
* 각 키는 PIPELINE_TEMPLATES 의 templateId 와 1:1. 매핑 변경 시 UI 동기화 필요.
*/
export const SCOPE_PRESETS = [
{ templateId: 'plan-only', shortLabel: '기획만', longLabel: '기획서까지만' },
{ templateId: 'dev-only', shortLabel: '개발까지', longLabel: '개발까지만' },
{ templateId: 'full-product-dev', shortLabel: '풀', longLabel: '배포까지 풀 파이프라인' },
] as const;
export function getPipelineTemplate(id: string): PipelineTemplate | undefined {
return PIPELINE_TEMPLATES.find((t) => t.templateId === id);
}