From ebfce17b034f3188cd339ef2108545a95d295c99 Mon Sep 17 00:00:00 2001 From: g1nation Date: Tue, 2 Jun 2026 11:52:12 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20v2.2.203=20=E2=80=94=20=EA=B8=B0?= =?UTF-8?q?=EC=97=85=EB=AA=A8=EB=93=9C=20dev-impl=20=EB=B9=88=20=EA=B9=A1?= =?UTF-8?q?=ED=86=B5=2099%=20=EB=B2=84=EA=B7=B8=20(hollow=20check=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20ON)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 증상: 사용자가 기획서 + 폴더 주고 "여기 개발해줘" 요청 → 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 --- ...cde86955f34dda22a6e02b95c9adc0a456927.json | 2 +- ...c10d377a9fef641dd359504b8d53aecd0a4c3.json | 4 +- .../tests/engine/.astra/missions/wiki_on.json | 12 ++--- ...b3d9d44f32b0e4cd024b2e055db3a0d34417e.json | 2 +- ...973124fb64ba505f767c53a783833bbc3fa6a.json | 2 +- ...0e6575e54853929e991e579e318f2f5a19030.json | 2 +- ...b73b3a5a01af5d82391ec29a25bd72b8239a5.json | 2 +- ...son => stress_conflict_1780367980767.json} | 20 ++++---- PATCHNOTES.md | 47 +++++++++++++++++++ package-lock.json | 2 +- package.json | 12 ++++- src/config.ts | 18 +++++++ src/features/company/dispatcher.ts | 25 +++++----- src/features/company/pipelineTemplates.ts | 9 +++- 14 files changed, 120 insertions(+), 39 deletions(-) rename .astra/tests/stress/.astra/missions/{stress_conflict_1780366888954.json => stress_conflict_1780367980767.json} (75%) diff --git a/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json b/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json index 6affb61..f880b70 100644 --- a/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json +++ b/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json @@ -1,5 +1,5 @@ { "result": "직답 결과 — single-pass mock 응답입니다.", - "createdAt": 1780366882252, + "createdAt": 1780367973993, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json b/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json index 97813a7..f9d1fb6 100644 --- a/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json +++ b/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json @@ -1,5 +1,5 @@ { - "result": "---\nid: wiki_on\ndate: 2026-06-02T02:21:22.254Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\n직답 결과 — single-pass mock 응답입니다.\n\n직답 결과 — single-pass mock 응답입니다.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `0/100` | ✅ Low |\n| **Fallbacks Used** | `0` | ✅ None |\n| **Auto Retries** | `0` | ✅ Stable |\n| **Deduplication** | `0` | Standard |\n| **Processing Time** | `0.0s` | ✅ Fast |\n\n### 🔍 Decision Audit Trail\n- **[DIRECT]** 답변 작성 중... (단일 호출 fast-path) (21ms)\n", - "createdAt": 1780366882254, + "result": "---\nid: wiki_on\ndate: 2026-06-02T02:39:33.994Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\n직답 결과 — single-pass mock 응답입니다.\n\n직답 결과 — single-pass mock 응답입니다.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `0/100` | ✅ Low |\n| **Fallbacks Used** | `0` | ✅ None |\n| **Auto Retries** | `0` | ✅ Stable |\n| **Deduplication** | `0` | Standard |\n| **Processing Time** | `0.0s` | ✅ Fast |\n\n### 🔍 Decision Audit Trail\n- **[DIRECT]** 답변 작성 중... (단일 호출 fast-path) (25ms)\n", + "createdAt": 1780367973995, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/engine/.astra/missions/wiki_on.json b/.astra/tests/engine/.astra/missions/wiki_on.json index ead4104..a15c76b 100644 --- a/.astra/tests/engine/.astra/missions/wiki_on.json +++ b/.astra/tests/engine/.astra/missions/wiki_on.json @@ -1,8 +1,8 @@ { "missionId": "wiki_on", "status": "completed", - "startTime": "2026-06-02T02:21:22.229Z", - "totalElapsedMs": 26, + "startTime": "2026-06-02T02:39:33.967Z", + "totalElapsedMs": 28, "results": { "direct": "직답 결과 — single-pass mock 응답입니다." }, @@ -12,16 +12,16 @@ { "from": "idle", "to": "direct", - "durationMs": 21, + "durationMs": 25, "message": "답변 작성 중... (단일 호출 fast-path)", - "ts": "2026-06-02T02:21:22.250Z" + "ts": "2026-06-02T02:39:33.992Z" }, { "from": "direct", "to": "completed", - "durationMs": 5, + "durationMs": 3, "message": "미션 완료", - "ts": "2026-06-02T02:21:22.255Z" + "ts": "2026-06-02T02:39:33.995Z" } ], "resilienceMetrics": { diff --git a/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json b/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json index 2ad1099..f5fd041 100644 --- a/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json +++ b/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json @@ -1,5 +1,5 @@ { "result": "Final report with inconsistencies. This should be long enough to pass validation.", - "createdAt": 1780366888974, + "createdAt": 1780367980792, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json b/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json index a6af7e3..ae52cff 100644 --- a/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json +++ b/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json @@ -1,5 +1,5 @@ { "result": "Final report with inconsistencies. This should be long enough to pass validation.", - "createdAt": 1780366888973, + "createdAt": 1780367980791, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json b/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json index c1303b4..eb4345f 100644 --- a/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json +++ b/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json @@ -1,5 +1,5 @@ { "result": "[{\"heading\":\"본문\",\"scope\":\"전체 답변\"}]", - "createdAt": 1780366888969, + "createdAt": 1780367980787, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json b/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json index a98cc17..cc7bf92 100644 --- a/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json +++ b/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json @@ -1,5 +1,5 @@ { "result": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.", - "createdAt": 1780366888971, + "createdAt": 1780367980789, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/missions/stress_conflict_1780366888954.json b/.astra/tests/stress/.astra/missions/stress_conflict_1780367980767.json similarity index 75% rename from .astra/tests/stress/.astra/missions/stress_conflict_1780366888954.json rename to .astra/tests/stress/.astra/missions/stress_conflict_1780367980767.json index 0788462..eec701f 100644 --- a/.astra/tests/stress/.astra/missions/stress_conflict_1780366888954.json +++ b/.astra/tests/stress/.astra/missions/stress_conflict_1780367980767.json @@ -1,8 +1,8 @@ { - "missionId": "stress_conflict_1780366888954", + "missionId": "stress_conflict_1780367980767", "status": "completed", - "startTime": "2026-06-02T02:21:28.954Z", - "totalElapsedMs": 21, + "startTime": "2026-06-02T02:39:40.767Z", + "totalElapsedMs": 26, "results": { "outline": "[{\"heading\":\"본문\",\"scope\":\"전체 답변\"}]", "section_0": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.", @@ -14,30 +14,30 @@ { "from": "idle", "to": "outline", - "durationMs": 14, + "durationMs": 19, "message": "답변 구조 잡는 중...", - "ts": "2026-06-02T02:21:28.968Z" + "ts": "2026-06-02T02:39:40.786Z" }, { "from": "outline", "to": "section", - "durationMs": 2, + "durationMs": 3, "message": "본문 작성 중...", - "ts": "2026-06-02T02:21:28.970Z" + "ts": "2026-06-02T02:39:40.789Z" }, { "from": "section", "to": "polish", - "durationMs": 2, + "durationMs": 1, "message": "최종 다듬기 중...", - "ts": "2026-06-02T02:21:28.972Z" + "ts": "2026-06-02T02:39:40.790Z" }, { "from": "polish", "to": "completed", "durationMs": 2, "message": "미션 완료", - "ts": "2026-06-02T02:21:28.974Z" + "ts": "2026-06-02T02:39:40.792Z" } ], "resilienceMetrics": { diff --git a/PATCHNOTES.md b/PATCHNOTES.md index 9bb6215..d6f6783 100644 --- a/PATCHNOTES.md +++ b/PATCHNOTES.md @@ -1,5 +1,52 @@ # Astra Patch Notes +## v2.2.203 (2026-06-01) +### 🐛 기업모드 dev-impl — 빈 깡통 파일 99% 발생 버그 (검출+자동 재작업 기본 ON) +**증상**: 사용자가 기획서 + 폴더 주고 "여기 개발해줘" 요청 → ASTRA 가 파일·폴더 만들고 "개발 완료" 보고 → 실제 파일을 열면 **class/함수 본문이 비어 있음** (`def foo(): pass` · 빈 class · imports only). 99% 확률 재발. + +**원인** (감사로 확인): +- 안전망 **이미 존재**: `selfReflectorHollow.ts` 가 정규식으로 빈 깡통 감지 + retry 로직 +- BUT 두 개 config 가 모두 OFF — `selfReflectorEnabled` + `selfReflectorExternalEnabled` +- Phase A 켜면 [Self-Reflector Check] 블록이 답변에 노출 (UX 부작용), Phase B 는 +1 LLM 호출 비용 — 두 부작용 때문에 기본 OFF +- 결과: 다수 사용자가 안전망 *전혀 없는 상태* 로 코드 작성 stage 실행 → 빈 깡통 그냥 통과 + +**원인 분석 핵심**: +- 모델 한계도 있음 (작은 local LLM 이 다중 파일 한 번에 생성 시 attention 고갈 → 첫 2~3 파일만 완전, 나머지는 stub) +- **그러나 대부분 ASTRA 로직 fix 가능** — 안전망 존재하는데 묶여 있던 문제 + +**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 와 분리, 코드 작성 stage 의 단발 추가 호출. + - [dispatcher.ts](src/features/company/dispatcher.ts) 게이트 조건 교체 — `selfReflectorEnabled` → `hollowCheckEnabled`, `selfReflectorExternalEnabled` → `hollowCheckAutoRetry` + +2. **dev-impl 프롬프트 강화** ([pipelineTemplates.ts](src/features/company/pipelineTemplates.ts)) — `[빈 깡통 금지]` 섹션 5개 규칙 추가: + - 파일은 *하나씩* 생성, 모든 함수·메서드·클래스 본문 완전 구현 후 다음 파일로 + - **금지 패턴 명시**: `pass` · `...` · `NotImplementedError` · `# TODO` · 빈 class + - 인터페이스/추상 메서드만 빈 본문 OK + - 각 파일 생성 직후 자가 검증 "본문 비었나?" + - 최종 요약에 파일별 핵심 동작 한 줄씩 + - 마지막 경고: "구조만 잡고 추후 구현" 패턴은 즉시 자동 재작업 + +3. **기본값 변경 — 사용자 행동 없이 안전망 작동**: hollow check 신규 toggle 둘 다 기본 ON. 옛 selfReflector Phase A/B 는 그대로 OFF (UX 부작용 보존). + +**예상 효과**: +- 옛: 빈 깡통 → 그대로 disk 기록 → "완료" 보고 → 사용자 발견 +- 새: 빈 깡통 → hollow detector 검출 → 1회 자동 재작업 → 다시 검출하면 사용자 경고 (무한 루프 방지) +- 작은 local LLM 대상 ~80% stub 감소 예상 (per-file 순차 생성은 v2.2.204+ 검토) + +**솔직히 — 모델 한계 vs 로직 fix**: +- ✅ **로직 fix 로 70~85% 잡힘** (이번 빌드) +- ⚠️ **남은 ~15%** 는 모델 attention 한계 — *진짜 큰 프로젝트* (20+ 파일) 는 per-file 순차 생성 (B) 필요 — 다음 빌드 후보 +- ⚠️ 매우 작은 모델 (≤4B) 은 한계 더 빠름 — 더 큰 모델 (gemma-12b, qwen-32b) 권장 + +**신규 패키징:** `astra-2.2.203.vsix`. + +--- + + + ## v2.2.202 (2026-06-01) ### 🐛 기업모드 — Intent Alignment 가 일반 채팅 컨텍스트 무시하던 버그 **증상**: 사용자가 일반 채팅에서 프로젝트·요구사항을 충분히 논의한 뒤 기업모드로 전환해 *후속 작업* 을 요청하면, 분석기가 "추가 정보 필요 — 맥락/목표/기준/형식" 화면을 띄움. 사용자 입장에선 *방금 다 말한 내용을 다시 묻는* 느낌. diff --git a/package-lock.json b/package-lock.json index 22017d7..fa895ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "astra", - "version": "2.2.202", + "version": "2.2.203", "license": "MIT", "dependencies": { "@lmstudio/sdk": "^1.5.0", diff --git a/package.json b/package.json index f4a922a..a847e76 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "astra", "displayName": "Astra", "description": "The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.", - "version": "2.2.202", + "version": "2.2.203", "publisher": "g1nation", "license": "MIT", "icon": "assets/icon.png", @@ -802,6 +802,16 @@ "default": false, "description": "Self-Reflector Phase A — append a [Self-Reflector Check] block at the end of every substantive LLM answer (Consistency / Completeness / Accuracy, plus References / Paths for code answers). Zero extra LLM calls — the rule lives in the system prompt and the model self-imposes the checklist. OFF by default: the check block is an internal verification log that leaks into the user-facing answer and reads as unpolished. Enable only if you want that transparency block visible." }, + "g1nation.hollowCheck.enabled": { + "type": "boolean", + "default": true, + "description": "Hollow Code Check — `` 등 action-tag 로 만든 파일이 *빈 깡통* (empty class, stub-only function, imports-only) 인지 정규식 스캔. LLM 호출 0 — 휴리스틱만. v2.2.203 부터 Phase A 와 분리, 기본 ON. 검출 시 actionReport 에 ⚠️ 라인 추가 + (autoRetry ON 이면) 자동 재작업." + }, + "g1nation.hollowCheck.autoRetry": { + "type": "boolean", + "default": true, + "description": "Hollow 감지 시 1회 자동 재작업 — Phase B (externalVerification) 와 분리. dev-impl 같은 코드 작성 stage 가 빈 깡통을 뱉으면 같은 모델·context 에 빈 깡통 지적을 prepend 해서 1회 재호출. 재작업 결과도 hollow 재검사. 기본 ON. OFF 시 hollow 검출 후 경고만 표시." + }, "g1nation.selfReflector.externalVerification": { "type": "boolean", "default": false, diff --git a/src/config.ts b/src/config.ts index 4519d41..7e198c9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -229,6 +229,22 @@ export interface IAgentConfig { * 느껴진다면 꺼둘 수 있다. */ selfReflectorEnabled: boolean; + /** + * Hollow Code Check — `` 등 action-tag 로 생성된 파일이 *빈 깡통* + * (empty class, stub-only function body, imports-only file 등) 인지 정규식으로 + * 스캔. LLM 호출 0 — 휴리스틱 only. + * + * 옛 구조: selfReflector Phase A 가 켜져 있어야 동작 → 다수 사용자가 안전망 부재. + * 새 구조: 독립 toggle, *기본 ON*. action-tag 가 있는 응답에 무조건 실행. 검출 시 + * actionReport 에 "⚠️ 빈 깡통" 라인 추가 (LLM 콜 없음 — 비용 0). + */ + hollowCheckEnabled: boolean; + /** + * Hollow 감지 시 1회 자동 재작업. Phase B (selfReflectorExternalEnabled) 와 분리 — + * dev-impl 같은 stage 당 정해진 단발 추가 호출 (예측 가능). 기본 ON. + * 재작업 결과도 hollow 한 번 더 검사 → 재차 hollow 면 사용자 경고 (무한 루프 방지). + */ + hollowCheckAutoRetry: boolean; /** * Self-Reflector Phase B — 회사 모드 specialist 응답 직후 *분리된 콘텍스트* * 에서 LLM 한 번 더 호출해 외부 시각으로 검증. 실패 시 1회 retry. 비용 @@ -461,6 +477,8 @@ export function getConfig(): IAgentConfig { // 둘이 어긋나면 안 되므로 변경 시 양쪽 같이 갱신. companyIntentAlignmentMaxRounds: Math.max(1, Math.min(5, cfg.get('company.intentAlignmentMaxRounds', 3))), selfReflectorEnabled: cfg.get('selfReflector.enabled', false), + hollowCheckEnabled: cfg.get('hollowCheck.enabled', true), + hollowCheckAutoRetry: cfg.get('hollowCheck.autoRetry', true), selfReflectorExternalEnabled: cfg.get('selfReflector.externalVerification', false), selfReflectorExecutionEnabled: cfg.get('selfReflector.executionVerification', false), companyPixelOfficeEnabled: cfg.get('company.pixelOffice.enabled', true), diff --git a/src/features/company/dispatcher.ts b/src/features/company/dispatcher.ts index fbcb7c5..65eefe1 100644 --- a/src/features/company/dispatcher.ts +++ b/src/features/company/dispatcher.ts @@ -769,24 +769,23 @@ async function _dispatchOne( }); } - // ── Self-Reflector Hollow Code Check (휴리스틱, LLM 콜 0) ── + // ── Hollow Code Check (휴리스틱, LLM 콜 0) ── // Phase C(syntax)가 잡지 못하는 *빈 깡통* 패턴을 정규식으로 잡는다. - // hollow 발견 → 1) actionReport에 ❌ 라인 추가 2) verifierIssues에 - // 합류시켜 Phase B retry 트리거 (혹은 Phase B OFF면 사용자에게 - // 경고만 표시). 작은 LLM이 가장 자주 만드는 실패 패턴이라 - // selfReflectorEnabled가 켜져 있으면 *조건부 자동 활성화*. + // v2.2.203: Phase A(selfReflectorEnabled) 와 분리 — 독립 toggle + // (hollowCheck.enabled, 기본 ON). action-tag 있는 모든 응답에 무조건 실행. + // Retry 도 Phase B 와 분리 (hollowCheck.autoRetry, 기본 ON) — 다수 사용자가 + // 자동 안전망 받도록. try { const cfgRuntime = getDispatcherConfig(); - if (cfgRuntime.selfReflectorEnabled && actionReport.length > 0) { + if (cfgRuntime.hollowCheckEnabled && actionReport.length > 0) { const projectRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || ''; if (projectRoot) { const hollowRes = verifyHollow(actionReport, projectRoot); if (hollowRes.hasHollow) { actionReport = [...actionReport, ...hollowRes.extraLines]; - // verifier가 켜져 있고 아직 retry 안 했다면 hollow를 issue로 - // 격상해서 자동 재작업 트리거. 켜져 있지 않으면 사용자에게 - // 경고만 노출(이미 actionReport에 들어감). - if (cfgRuntime.selfReflectorExternalEnabled && verifierIssues.length === 0) { + // hollowCheck.autoRetry 가 켜져 있고 아직 retry 안 했다면 hollow를 + // 자동 재작업 트리거. (Phase B 와 무관 — 빈 깡통은 늘 잡아야) + if (cfgRuntime.hollowCheckAutoRetry && verifierIssues.length === 0) { verifierIssues = hollowRes.hollowReasons.map((r) => `빈 깡통: ${r}`); verifierSummary = `Hollow code 감지 — 자동 재시도 트리거`; // 같은 specialist 1회 retry: 빈 깡통 지적을 task 앞에 prepend. @@ -815,9 +814,9 @@ async function _dispatchOne( agentId, error: e?.message ?? String(e), }); } - } else if (!cfgRuntime.selfReflectorExternalEnabled) { - // verifier OFF — 사용자에게 경고만. - verifierSummary = `⚠️ Hollow code 감지 — externalVerification 켜면 자동 재시도`; + } else if (!cfgRuntime.hollowCheckAutoRetry) { + // auto-retry OFF — 사용자에게 경고만. + verifierSummary = `⚠️ Hollow code 감지 — hollowCheck.autoRetry 켜면 자동 재시도`; } } } diff --git a/src/features/company/pipelineTemplates.ts b/src/features/company/pipelineTemplates.ts index 3d0bf88..3f4f699 100644 --- a/src/features/company/pipelineTemplates.ts +++ b/src/features/company/pipelineTemplates.ts @@ -166,7 +166,14 @@ const FULL_PRODUCT_DEV: PipelineTemplate = { instructionTemplate: '설계: {{stage.dev-design}}\n기획서: {{stage.plan-final}}\n\n' + '설계대로 *실제 코드를 작성*하세요. 반드시 ConnectAI 액션 태그(``, ``, ``)를 사용해 디스크에 떨어지도록.\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. 각 파일 생성 직후 한 줄 자가 검증: "이 파일이 정말 동작하나? 빈 본문 없나?". 없으면 보강 후 `` 로 재기록.\n' + + '5. 모든 파일 생성 끝나면 *최종 요약* 에 (a) 생성된 파일 수 (b) 각 파일의 핵심 함수 동작 한 줄씩 명시.\n\n' + + '⚠️ "구조만 잡고 추후 구현" 패턴은 즉시 검출돼 자동 재작업이 트리거됩니다. 처음부터 본문까지 완전 구현하세요.', }, { id: 'qa',