fix(prompt): plan/implement manager hint 도 가짜 팀 narration 금지

자기야 발견: 다랑이/이랑이 (review/deploy) 의 manager 가 가짜 팀 분배를
출력하던 건 이전 커밋에서 고쳤는데, 하랑이/나랑이 (plan/implement) 의
manager 도 똑같이 "수석 1명은... 선임 2명은... 신입 2명은..." 를 풀어서
narration 하고 있었음. 분해는 sister-agent 의 planner.ts 가 complexity
score 로 결정론적으로 결정하지 LLM 의 prose 가 결정하지 않는데, manager
LLM 이 prose 로 가짜 team plan 을 출력해서:

  - 토큰 낭비 (실제로 spawn 에 영향 0)
  - 사용자 혼란 ("진짜 그렇게 팀이 구성됐나?" 오해)
  - 다음 stage 의 priorStages 노이즈 증가

수정 — plan/implement manager hint 를 stage 별로 짧게 재작성:

plan/manager:
  1) MVP 범위 한 줄
  2) 명시적 비범위 한 줄
  3) 통과 기준 한 줄
  명령형/단정형 강제. "수석/선임/신입" 단어 사용 금지.

implement/manager:
  1) 기술 스택 / 런타임 한 줄
  2) 파일 구조 1~2 줄
  3) 핵심 구현 결정 한 줄
  같은 제약.

추가로 principal/lead/junior 의 plan/implement hint 에도 "팀 narration 금지"
한 줄을 박아 일관성 유지. junior 의 implement code 출력에도 코드 블록 안에
가짜 팀 prose 를 섞지 말라는 가드 추가.

실제 분해는 코드 (planner.ts) 가 한다는 사실을 prompt 자체에 명시.
This commit is contained in:
2026-04-11 02:54:02 +09:00
parent 6c43cccca5
commit 6c6a0a50dc

View File

@@ -106,18 +106,44 @@ function roleOutputHint(role: Role, stage: PromptContext["stage"]): string {
}
// ── plan / implement ─────────────────────────────────────────
// IMPORTANT: 팀 분배 (수석/선임/신입 N명...) narration 은 금지다.
// 하위 노드의 spawn 트리는 sister-agent 의 planner.ts 가 complexity score 로
// 결정론적으로 결정한다. LLM manager 는 spawn 결정에 영향을 주지 않으며,
// "수석 1명을 붙일게" 같은 prose 는 빈 약속 + 토큰 낭비 + 사용자 혼란이다.
// 대신 manager 는 이 stage 의 진짜 결정 (범위/스택/파일 경계) 만 짧게.
if (role === "manager") {
return `이 작업을 어떻게 분해할지, 어떤 팀(수석/선임/신입)을 어디에 배치할지 한 문단으로 결정해.`;
if (stage === "plan") {
return [
`너는 이 단계의 최종 결정권자다. 팀(수석/선임/신입)이 자동으로 붙으니 분배 narration 은 절대 하지 마.`,
`대신 다음 3 가지만 짧게 결정해서 답해:`,
`1) MVP 범위: 무엇을 포함하나 한 줄`,
`2) 명시적 비범위: 의도적으로 제외할 것 한 줄`,
`3) 통과 기준: 무엇이 동작해야 끝났다고 보는지 한 줄`,
`각 줄은 명령형/단정형으로. "수석/선임/신입" 단어 사용 금지.`,
].join("\n");
}
if (stage === "implement") {
return [
`너는 이 단계의 최종 결정권자다. 팀(수석/선임/신입)이 자동으로 붙으니 분배 narration 은 절대 하지 마.`,
`대신 다음 3 가지만 짧게 결정해서 답해:`,
`1) 기술 스택 / 런타임 한 줄 (예: "vanilla HTML+JS, localStorage")`,
`2) 파일 구조 1~2 줄 (어떤 파일이 만들어지는지)`,
`3) 핵심 구현 결정 한 줄 (상태 관리 방식, 데이터 형태 등)`,
`각 줄은 명령형/단정형으로. "수석/선임/신입" 단어 사용 금지.`,
].join("\n");
}
// Other stages handled above by reviewHintForRole / deployHintForRole
return `이 단계의 핵심 결정 한 문단으로.`;
}
if (role === "principal") {
return `${STAGE_KOREAN[stage]} 단계에서 구체적으로 어떤 리스크가 있고, 어떻게 분해되어야 하는지 bullet 으로 제시해.`;
return `${STAGE_KOREAN[stage]} 단계의 기술적 리스크와 핵심 결정 사항을 bullet 으로 1~3 개. "수석/선임/신입" 같은 팀 narration 금지 — 시스템이 자동으로 분배한다.`;
}
if (role === "lead") {
return `이 작업을 신입에게 어떻게 나눠줄지, 검증 포인트는 무엇인지 bullet 으로 정리해.`;
return `${STAGE_KOREAN[stage]} 단계에서 검증해야 할 핵심 포인트를 bullet 1~3 개. 팀 분배 narration 금지.`;
}
// junior
if (stage === "plan") {
return `이 프로젝트의 핵심 plan 을 마크다운 bullet 형식으로 작성해.`;
return `이 프로젝트의 핵심 plan 을 마크다운 bullet 형식으로 작성해. "수석/선임/신입" 단어 사용 금지.`;
}
if (stage === "implement") {
return [
@@ -128,6 +154,7 @@ function roleOutputHint(role: Role, stage: PromptContext["stage"]): string {
"```",
`경로는 프로젝트 루트 기준 상대 경로. 언어 태그 콜론 뒤에 경로.`,
`여러 파일이 필요하면 각각 별도 블록으로. 설명은 최소화.`,
`"수석/선임/신입" 같은 팀 narration 은 코드 출력 안에 포함하지 마.`,
].join("\n");
}
return `결과를 명확히 제출해.`;