@tienne/gestalt 0.84.2 → 0.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/CLAUDE.md +4 -4
  2. package/README.ko.md +72 -22
  3. package/README.md +73 -23
  4. package/dist/benchmarks/runners/passthrough-benchmark-runner.d.ts.map +1 -1
  5. package/dist/benchmarks/runners/passthrough-benchmark-runner.js +8 -7
  6. package/dist/benchmarks/runners/passthrough-benchmark-runner.js.map +1 -1
  7. package/dist/bin/gestalt.js +2 -2
  8. package/dist/package.json +1 -1
  9. package/dist/plugin/skills/dispatch/SKILL.md +14 -2
  10. package/dist/plugin/skills/execute/SKILL.md +219 -52
  11. package/dist/plugin/skills/interview/SKILL.md +15 -2
  12. package/dist/plugin/skills/solve/SKILL.md +20 -5
  13. package/dist/plugin/skills/spec/SKILL.md +2 -0
  14. package/dist/src/cli/commands/interview.d.ts.map +1 -1
  15. package/dist/src/cli/commands/interview.js +16 -4
  16. package/dist/src/cli/commands/interview.js.map +1 -1
  17. package/dist/src/cli/commands/memory-merge.d.ts +2 -0
  18. package/dist/src/cli/commands/memory-merge.d.ts.map +1 -0
  19. package/dist/src/cli/commands/memory-merge.js +13 -0
  20. package/dist/src/cli/commands/memory-merge.js.map +1 -0
  21. package/dist/src/cli/index.d.ts.map +1 -1
  22. package/dist/src/cli/index.js +7 -0
  23. package/dist/src/cli/index.js.map +1 -1
  24. package/dist/src/core/constants.d.ts +4 -0
  25. package/dist/src/core/constants.d.ts.map +1 -1
  26. package/dist/src/core/constants.js +8 -0
  27. package/dist/src/core/constants.js.map +1 -1
  28. package/dist/src/core/errors.d.ts +3 -0
  29. package/dist/src/core/errors.d.ts.map +1 -1
  30. package/dist/src/core/errors.js +7 -0
  31. package/dist/src/core/errors.js.map +1 -1
  32. package/dist/src/core/file-lock.d.ts +37 -0
  33. package/dist/src/core/file-lock.d.ts.map +1 -0
  34. package/dist/src/core/file-lock.js +143 -0
  35. package/dist/src/core/file-lock.js.map +1 -0
  36. package/dist/src/core/json-file.d.ts +40 -0
  37. package/dist/src/core/json-file.d.ts.map +1 -0
  38. package/dist/src/core/json-file.js +82 -0
  39. package/dist/src/core/json-file.js.map +1 -0
  40. package/dist/src/core/types.d.ts +86 -9
  41. package/dist/src/core/types.d.ts.map +1 -1
  42. package/dist/src/events/store.d.ts +6 -0
  43. package/dist/src/events/store.d.ts.map +1 -1
  44. package/dist/src/events/store.js +12 -0
  45. package/dist/src/events/store.js.map +1 -1
  46. package/dist/src/events/types.d.ts +7 -0
  47. package/dist/src/events/types.d.ts.map +1 -1
  48. package/dist/src/events/types.js +7 -0
  49. package/dist/src/events/types.js.map +1 -1
  50. package/dist/src/execute/artifact-verifier.d.ts +12 -0
  51. package/dist/src/execute/artifact-verifier.d.ts.map +1 -0
  52. package/dist/src/execute/artifact-verifier.js +211 -0
  53. package/dist/src/execute/artifact-verifier.js.map +1 -0
  54. package/dist/src/execute/drift-detector.d.ts +2 -0
  55. package/dist/src/execute/drift-detector.d.ts.map +1 -1
  56. package/dist/src/execute/drift-detector.js +9 -13
  57. package/dist/src/execute/drift-detector.js.map +1 -1
  58. package/dist/src/execute/orchestrators/evaluation.d.ts +5 -1
  59. package/dist/src/execute/orchestrators/evaluation.d.ts.map +1 -1
  60. package/dist/src/execute/orchestrators/evaluation.js +48 -41
  61. package/dist/src/execute/orchestrators/evaluation.js.map +1 -1
  62. package/dist/src/execute/orchestrators/evolution.d.ts +17 -3
  63. package/dist/src/execute/orchestrators/evolution.d.ts.map +1 -1
  64. package/dist/src/execute/orchestrators/evolution.js +102 -53
  65. package/dist/src/execute/orchestrators/evolution.js.map +1 -1
  66. package/dist/src/execute/orchestrators/execution.d.ts +17 -2
  67. package/dist/src/execute/orchestrators/execution.d.ts.map +1 -1
  68. package/dist/src/execute/orchestrators/execution.js +99 -3
  69. package/dist/src/execute/orchestrators/execution.js.map +1 -1
  70. package/dist/src/execute/orchestrators/planning.d.ts +18 -4
  71. package/dist/src/execute/orchestrators/planning.d.ts.map +1 -1
  72. package/dist/src/execute/orchestrators/planning.js +62 -21
  73. package/dist/src/execute/orchestrators/planning.js.map +1 -1
  74. package/dist/src/execute/orchestrators/types.d.ts +12 -1
  75. package/dist/src/execute/orchestrators/types.d.ts.map +1 -1
  76. package/dist/src/execute/passthrough-engine.d.ts +12 -5
  77. package/dist/src/execute/passthrough-engine.d.ts.map +1 -1
  78. package/dist/src/execute/passthrough-engine.js +10 -4
  79. package/dist/src/execute/passthrough-engine.js.map +1 -1
  80. package/dist/src/execute/repository.d.ts +11 -1
  81. package/dist/src/execute/repository.d.ts.map +1 -1
  82. package/dist/src/execute/repository.js +138 -19
  83. package/dist/src/execute/repository.js.map +1 -1
  84. package/dist/src/execute/session.d.ts +26 -4
  85. package/dist/src/execute/session.d.ts.map +1 -1
  86. package/dist/src/execute/session.js +165 -48
  87. package/dist/src/execute/session.js.map +1 -1
  88. package/dist/src/execute/structural-commands.d.ts +23 -0
  89. package/dist/src/execute/structural-commands.d.ts.map +1 -0
  90. package/dist/src/execute/structural-commands.js +139 -0
  91. package/dist/src/execute/structural-commands.js.map +1 -0
  92. package/dist/src/interview/engine.d.ts +1 -1
  93. package/dist/src/interview/engine.d.ts.map +1 -1
  94. package/dist/src/interview/engine.js +3 -3
  95. package/dist/src/interview/engine.js.map +1 -1
  96. package/dist/src/interview/passthrough-engine.d.ts +1 -1
  97. package/dist/src/interview/passthrough-engine.d.ts.map +1 -1
  98. package/dist/src/interview/passthrough-engine.js +20 -3
  99. package/dist/src/interview/passthrough-engine.js.map +1 -1
  100. package/dist/src/interview/repository.d.ts +8 -0
  101. package/dist/src/interview/repository.d.ts.map +1 -1
  102. package/dist/src/interview/repository.js +16 -1
  103. package/dist/src/interview/repository.js.map +1 -1
  104. package/dist/src/interview/session.d.ts +15 -2
  105. package/dist/src/interview/session.d.ts.map +1 -1
  106. package/dist/src/interview/session.js +67 -23
  107. package/dist/src/interview/session.js.map +1 -1
  108. package/dist/src/knowledge-base/embedding.d.ts +6 -1
  109. package/dist/src/knowledge-base/embedding.d.ts.map +1 -1
  110. package/dist/src/knowledge-base/embedding.js +19 -6
  111. package/dist/src/knowledge-base/embedding.js.map +1 -1
  112. package/dist/src/local-pr/registry.d.ts +1 -21
  113. package/dist/src/local-pr/registry.d.ts.map +1 -1
  114. package/dist/src/local-pr/registry.js +7 -113
  115. package/dist/src/local-pr/registry.js.map +1 -1
  116. package/dist/src/mcp/input-guard.d.ts +17 -0
  117. package/dist/src/mcp/input-guard.d.ts.map +1 -1
  118. package/dist/src/mcp/input-guard.js +1 -1
  119. package/dist/src/mcp/input-guard.js.map +1 -1
  120. package/dist/src/mcp/schemas.d.ts +62 -7
  121. package/dist/src/mcp/schemas.d.ts.map +1 -1
  122. package/dist/src/mcp/schemas.js +28 -1
  123. package/dist/src/mcp/schemas.js.map +1 -1
  124. package/dist/src/mcp/server.d.ts.map +1 -1
  125. package/dist/src/mcp/server.js +26 -40
  126. package/dist/src/mcp/server.js.map +1 -1
  127. package/dist/src/mcp/tools/execute/evaluate.d.ts.map +1 -1
  128. package/dist/src/mcp/tools/execute/evaluate.js +15 -9
  129. package/dist/src/mcp/tools/execute/evaluate.js.map +1 -1
  130. package/dist/src/mcp/tools/execute/evolve.d.ts +1 -0
  131. package/dist/src/mcp/tools/execute/evolve.d.ts.map +1 -1
  132. package/dist/src/mcp/tools/execute/evolve.js +102 -37
  133. package/dist/src/mcp/tools/execute/evolve.js.map +1 -1
  134. package/dist/src/mcp/tools/execute/execution.d.ts.map +1 -1
  135. package/dist/src/mcp/tools/execute/execution.js +66 -7
  136. package/dist/src/mcp/tools/execute/execution.js.map +1 -1
  137. package/dist/src/mcp/tools/execute/planning.d.ts.map +1 -1
  138. package/dist/src/mcp/tools/execute/planning.js +34 -2
  139. package/dist/src/mcp/tools/execute/planning.js.map +1 -1
  140. package/dist/src/mcp/tools/execute/roles.d.ts.map +1 -1
  141. package/dist/src/mcp/tools/execute/roles.js +13 -5
  142. package/dist/src/mcp/tools/execute/roles.js.map +1 -1
  143. package/dist/src/mcp/tools/execute/utility.d.ts.map +1 -1
  144. package/dist/src/mcp/tools/execute/utility.js +26 -0
  145. package/dist/src/mcp/tools/execute/utility.js.map +1 -1
  146. package/dist/src/mcp/tools/execute/utils.d.ts +1 -0
  147. package/dist/src/mcp/tools/execute/utils.d.ts.map +1 -1
  148. package/dist/src/mcp/tools/execute/utils.js +15 -0
  149. package/dist/src/mcp/tools/execute/utils.js.map +1 -1
  150. package/dist/src/mcp/tools/execute-passthrough.d.ts.map +1 -1
  151. package/dist/src/mcp/tools/execute-passthrough.js +21 -1
  152. package/dist/src/mcp/tools/execute-passthrough.js.map +1 -1
  153. package/dist/src/mcp/tools/interview-passthrough.d.ts +2 -1
  154. package/dist/src/mcp/tools/interview-passthrough.d.ts.map +1 -1
  155. package/dist/src/mcp/tools/interview-passthrough.js +4 -3
  156. package/dist/src/mcp/tools/interview-passthrough.js.map +1 -1
  157. package/dist/src/mcp/tools/interview.d.ts.map +1 -1
  158. package/dist/src/mcp/tools/interview.js +2 -1
  159. package/dist/src/mcp/tools/interview.js.map +1 -1
  160. package/dist/src/mcp/tools/review-passthrough.js +15 -19
  161. package/dist/src/mcp/tools/review-passthrough.js.map +1 -1
  162. package/dist/src/mcp/tools/spec-passthrough.d.ts.map +1 -1
  163. package/dist/src/mcp/tools/spec-passthrough.js +16 -8
  164. package/dist/src/mcp/tools/spec-passthrough.js.map +1 -1
  165. package/dist/src/mcp/tools/status.d.ts.map +1 -1
  166. package/dist/src/mcp/tools/status.js +4 -0
  167. package/dist/src/mcp/tools/status.js.map +1 -1
  168. package/dist/src/memory/memory-context-injector.d.ts +22 -8
  169. package/dist/src/memory/memory-context-injector.d.ts.map +1 -1
  170. package/dist/src/memory/memory-context-injector.js +85 -13
  171. package/dist/src/memory/memory-context-injector.js.map +1 -1
  172. package/dist/src/memory/memory-merge.d.ts +19 -0
  173. package/dist/src/memory/memory-merge.d.ts.map +1 -0
  174. package/dist/src/memory/memory-merge.js +120 -0
  175. package/dist/src/memory/memory-merge.js.map +1 -0
  176. package/dist/src/memory/project-memory-store.d.ts +15 -11
  177. package/dist/src/memory/project-memory-store.d.ts.map +1 -1
  178. package/dist/src/memory/project-memory-store.js +97 -120
  179. package/dist/src/memory/project-memory-store.js.map +1 -1
  180. package/dist/src/memory/semantic-search.d.ts +4 -1
  181. package/dist/src/memory/semantic-search.d.ts.map +1 -1
  182. package/dist/src/memory/semantic-search.js +66 -19
  183. package/dist/src/memory/semantic-search.js.map +1 -1
  184. package/dist/src/resilience/lateral.d.ts +8 -1
  185. package/dist/src/resilience/lateral.d.ts.map +1 -1
  186. package/dist/src/resilience/lateral.js +52 -4
  187. package/dist/src/resilience/lateral.js.map +1 -1
  188. package/package.json +1 -1
  189. package/plugin/.codex-plugin/plugin.json +1 -1
  190. package/plugin/.mcp.json +1 -1
  191. package/plugin/mcp.json +1 -1
  192. package/plugin/skills/dispatch/SKILL.md +14 -2
  193. package/plugin/skills/execute/SKILL.md +219 -52
  194. package/plugin/skills/interview/SKILL.md +15 -2
  195. package/plugin/skills/solve/SKILL.md +20 -5
  196. package/plugin/skills/spec/SKILL.md +2 -0
  197. package/dist/src/interview/mini-interview-engine.d.ts +0 -33
  198. package/dist/src/interview/mini-interview-engine.d.ts.map +0 -1
  199. package/dist/src/interview/mini-interview-engine.js +0 -102
  200. package/dist/src/interview/mini-interview-engine.js.map +0 -1
  201. package/dist/src/memory/user-profile-store.d.ts +0 -13
  202. package/dist/src/memory/user-profile-store.d.ts.map +0 -1
  203. package/dist/src/memory/user-profile-store.js +0 -85
  204. package/dist/src/memory/user-profile-store.js.map +0 -1
@@ -119,7 +119,7 @@ Orca 런타임이 붙지 않아 워커 디스패치는 못 합니다.
119
119
  - 게슈탈트 실행 세션 ID(UUID 원문 — 워커는 다른 프로세스라 `active`가 다르게 해석될 수 있다)
120
120
  - 이 워커가 맡은 게슈탈트 taskId
121
121
  - `taskContext.taskPrompt` 내용
122
- - 완료 후 `ges_execute action=execute_task`로 결과를 제출하라는 지시
122
+ - 완료 후 `ges_execute action=execute_task`로 결과를 제출하라는 지시. 바꾼 파일은 전부 `artifacts`에 적고 파일을 안 바꾸는 태스크면 `noCodeChange: true`를 같이 낸다. `verification_failed`가 오면 고쳐서 다시 제출하고 끝내지 못했으면 `status: "failed"`로 낸다. `serverError: true`가 함께 오면 고치지 말고 잠시 뒤 같은 결과를 다시 내고 계속 실패하면 `status: "failed"`로 낸다
123
123
  - **다른 태스크는 건드리지 말라는 경계** — 워커가 ready 집합을 보고 남의 태스크까지 하려 들면 충돌한다
124
124
 
125
125
  동시 워커 수는 `maxConcurrent`로 제한한다. 지정이 없으면 ready 집합 크기와 4 중 작은 값을 쓴다. 워커마다 에이전트 프로세스와 게슈탈트 MCP 서버가 하나씩 뜨므로 무제한으로 띄우지 않는다.
@@ -149,7 +149,7 @@ Orca 런타임이 붙지 않아 워커 디스패치는 못 합니다.
149
149
 
150
150
  ## 6단계: 막힌 것은 사람에게 올린다
151
151
 
152
- 게슈탈트가 human escalation으로 세션을 끝냈으면(`terminationReason: 'human_escalation'`) 그 사실을 `orchestration gate-create`로 올려 사람 눈에 보이게 한다.
152
+ lateral persona를 다 써서 게슈탈트 세션이 `awaiting_human`으로 멈췄으면 그 사실을 `orchestration gate-create`로 올려 사람 눈에 보이게 한다. evolve 응답의 `status: 'awaiting_human'`으로 알 수 있다. `status` 조회에 `openGate`가 실려 있어도 같은 뜻이다. 질문에는 `gate.question`과 `gate.options`의 `id`, `label`을 그대로 옮긴다.
153
153
 
154
154
  ```bash
155
155
  <실행파일> orchestration gate-create --task <task_id> --question "<막힌 지점과 필요한 판단>" --json
@@ -158,6 +158,18 @@ Orca 런타임이 붙지 않아 워커 디스패치는 못 합니다.
158
158
 
159
159
  카드 코멘트를 남기면 터미널을 열지 않고도 `worktree ps`나 모바일에서 상태가 보인다. 의미 있는 체크포인트마다 코멘트를 갱신한다.
160
160
 
161
+ Orca 쪽에서 사람이 답해 해소되면(`gate-resolve`) 그 답을 게슈탈트에 넘겨야 세션이 움직인다. Orca 쪽 해소만으로는 게슈탈트 세션이 `awaiting_human`에 그대로 남는다. 그동안 `ges_execute`는 `status`, `resume`, `gate_resolve`, `evolution_viz` 말고는 다 거절한다.
162
+
163
+ ```json
164
+ {
165
+ "action": "gate_resolve",
166
+ "sessionId": "<UUID>",
167
+ "gateResolution": { "gateId": "<gate.gateId>", "optionId": "<사람이 고른 id>", "decision": "<사람의 결정>", "rationale": "<그 이유>" }
168
+ }
169
+ ```
170
+
171
+ `decision`과 `rationale`은 사람이 적은 말을 쓴다. 비어 있으면 서버가 거절한다. 코디네이터가 지어 채우면 지어낸 판단이 Memory에 남는다. 응답의 `nextAction`이 `evolve_patch`나 `evaluate`면 execute 스킬로 돌려보낸다. `terminated`가 오면(`restart`, `abort`) 세션이 종료된 것이니 디스패치를 멈춘다.
172
+
161
173
  ## Do-NOT
162
174
 
163
175
  - **execute 스킬을 대체하지 않는다.** 계획 수립(Planning), 평가(Evaluate), 개선(Evolve)은 execute가 한다. 이 스킬은 Phase 2 실행을 다른 백엔드로 돌리는 것뿐이다.
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  name: execute
3
- version: "1.3.0"
4
- description: "Gestalt-driven execution planner that transforms a Spec into a validated ExecutionPlan. Requires a Spec that already exists. Given only a problem statement, use solve instead — it drives interview → spec → execute as one loop."
3
+ version: '1.3.0'
4
+ description: 'Gestalt-driven execution planner that transforms a Spec into a validated ExecutionPlan. Requires a Spec that already exists. Given only a problem statement, use solve instead — it drives interview → spec → execute as one loop.'
5
5
  triggers:
6
- - "execute"
7
- - "plan execution"
8
- - "create execution plan"
6
+ - 'execute'
7
+ - 'plan execution'
8
+ - 'create execution plan'
9
9
  inputs:
10
10
  spec:
11
11
  type: object
12
12
  required: true
13
- description: "A validated Spec specification from the spec generation step"
13
+ description: 'A validated Spec specification from the spec generation step'
14
14
  outputs:
15
15
  - executionPlan
16
16
  ---
@@ -61,6 +61,7 @@ Success condition: `score ≥ 0.85` AND `goalAlignment ≥ 0.80`
61
61
  - **Flow A — Structural Fix**: fix lint/build/test failures → re-evaluate
62
62
  - **Flow B — Contextual Evolution**: patch Spec ACs/constraints → re-execute impacted tasks → re-evaluate
63
63
  - **Flow C — Lateral Thinking**: when stagnation detected, rotate through Multistability / Simplicity / Reification / Invariance personas
64
+ - **Flow D — Human Decision**: when all four personas are exhausted, the session pauses as `awaiting_human` — ask the human, then `gate_resolve` and follow `nextAction`
64
65
 
65
66
  ## Phase 0 — 규칙 확보 (필수 — 스킵 불가)
66
67
 
@@ -109,16 +110,15 @@ ges_status() → {
109
110
 
110
111
  **`ruleSourceErrors`가 비어 있지 않으면 멈춘다.** 판정과 사용자에게 알릴 문구는 [`../_shared/rule-sources.md`](../_shared/rule-sources.md)의 "선언이 깨졌을 때" 절이 원본이다. **`ruleSources`가 비어 있지 않아도 일부가 빠진 상태일 수 있으니 배열 길이로 판정하지 않는다.**
111
112
 
112
-
113
113
  `scope`가 비어 있지 않으면 **이번 Spec에 해당하는 소스만** 읽는다. 백엔드 태스크만 있는 Spec에서 디자인 토큰을 물어볼 이유가 없다. 여기는 건드릴 파일이 정해진 자리라 태그를 그 파일에서 뽑는다.
114
114
 
115
115
  **`solve`로 들어와 소스 읽기를 건너뛰는 경우에도 이 판정은 한다.** 건너뛰는 건 읽기지 판정이 아니다. 앞 스킬은 파일을 모른 채 넘겼으므로 여기서 세 가지가 정해진다.
116
116
 
117
- | 앞에서 넘어온 것 | 여기서 |
118
- |---|---|
117
+ | 앞에서 넘어온 것 | 여기서 |
118
+ | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
119
119
  | 넓게 잡아 읽어둔 `convention` 소스 중 파일을 보니 안 걸리는 것 | `repoRules.sources`에서 뺀다. 거기서 빠지면 서브에이전트 프롬프트와 완료 보고 양쪽에서 함께 빠진다 |
120
- | 판정을 미뤄둔 `stop`과 `delegate` 소스 | 여기서 판정한다. 걸리면 읽거나 멈추거나 넘긴다 |
121
- | 새로 걸리는 소스 | 그것만 더 읽는다 |
120
+ | 판정을 미뤄둔 `stop`과 `delegate` 소스 | 여기서 판정한다. 걸리면 읽거나 멈추거나 넘긴다 |
121
+ | 새로 걸리는 소스 | 그것만 더 읽는다 |
122
122
 
123
123
  `trust: "delegate"`인 소스가 이번 작업 범위에 걸리면 그 부분은 게슈탈트가 직접 만들지 않고 넘긴다. 어디까지 넘기는지 사용자에게 알리고 진행한다.
124
124
 
@@ -145,41 +145,52 @@ API 키 없이 MCP 서버 실행 시 자동 활성화. LLM 작업을 caller가
145
145
  ### Action별 사용법
146
146
 
147
147
  **`start`** — 실행 계획 세션 시작
148
+
148
149
  ```json
149
150
  { "action": "start", "spec": { ... } }
150
151
  ```
152
+
151
153
  → `{ status, sessionId, specId, executeContext, message }`
152
154
 
153
155
  **`plan_step`** — 각 계획 단계 결과 제출
156
+
154
157
  ```json
155
158
  { "action": "plan_step", "sessionId": "...", "stepResult": { "principle": "figure_ground", "classifiedACs": [...] } }
156
159
  ```
160
+
157
161
  → `{ status, sessionId, stepsCompleted, isLastStep, executeContext?, message }`
158
162
 
163
+ continuity에서 DAG가 무효면 `error`가 함께 실린 `status: "plan_rewound"` 응답이 온다. [DAG가 무효일 때](#dag가-무효일-때--closure로-되감기)를 본다.
164
+
159
165
  **`plan_complete`** — 최종 실행 계획 조립
166
+
160
167
  ```json
161
168
  { "action": "plan_complete", "sessionId": "..." }
162
169
  ```
170
+
163
171
  → `{ status, sessionId, executionPlan, message }`
164
172
 
173
+ 저장된 계획의 DAG가 무효면 확정하지 않고 같은 `plan_rewound` 응답을 돌려준다.
174
+
165
175
  **`status`** — 세션 상태 확인
176
+
166
177
  ```json
167
178
  { "action": "status", "sessionId": "..." }
168
179
  ```
169
180
 
170
181
  ### ExecuteContext 필드
171
182
 
172
- | 필드 | 타입 | 설명 |
173
- |------|------|------|
174
- | `systemPrompt` | string | 실행 계획 시스템 프롬프트 |
175
- | `planningPrompt` | string | 현재 단계의 계획 프롬프트 |
176
- | `currentPrinciple` | string | 현재 적용 중인 게슈탈트 원리 |
177
- | `principleStrategy` | string | 해당 원리의 전략 설명 |
178
- | `phase` | string | 현재 단계 (`planning`) |
179
- | `stepNumber` | number | 현재 스텝 번호 (1-4) |
180
- | `totalSteps` | number | 전체 스텝 수 (4) |
181
- | `spec` | Spec | 원본 Spec 스펙 |
182
- | `previousSteps` | array | 이전 단계 결과들 |
183
+ | 필드 | 타입 | 설명 |
184
+ | ------------------- | ------ | ----------------------------------------------------------------------------------------------- |
185
+ | `systemPrompt` | string | 실행 계획 시스템 프롬프트 |
186
+ | `planningPrompt` | string | 현재 단계의 계획 프롬프트 |
187
+ | `currentStage` | string | 현재 단계를 풀어 쓴 문구 (예: `빠진 요구사항 채우기`). 서버 내부의 원리 이름 대신 응답에 실린다 |
188
+ | `principleStrategy` | string | 해당 원리의 전략 설명 |
189
+ | `phase` | string | 현재 단계 (`planning`) |
190
+ | `stepNumber` | number | 현재 스텝 번호 (1-4) |
191
+ | `totalSteps` | number | 전체 스텝 수 (4) |
192
+ | `spec` | Spec | 원본 Spec 스펙 |
193
+ | `previousSteps` | array | 이전 단계 결과들 |
183
194
 
184
195
  ### Planning Principle 순서
185
196
 
@@ -195,6 +206,31 @@ API 키 없이 MCP 서버 실행 시 자동 활성화. LLM 작업을 caller가
195
206
  - Continuity 단계에서는 서버 측 DAG 검증이 추가로 수행됨
196
207
  - 모든 AC가 분류되어야 하고 모든 Task가 그룹에 포함되어야 함
197
208
 
209
+ ### DAG가 무효일 때 — closure로 되감기
210
+
211
+ 순환은 closure 단계 `atomicTasks`의 `dependsOn`에서 생긴다. continuity만 다시 내서는 못 고친다. 그래서 `dagValidation.isValid: false`를 보고하거나 서버가 순환이나 충돌을 찾으면 `plan_step`(continuity)과 `plan_complete` 둘 다 계획을 확정하지 않는다. 대신 세션을 figure_ground까지만 남기고 되감은 뒤 이렇게 돌려준다.
212
+
213
+ ```json
214
+ {
215
+ "error": "Dependency DAG is invalid (...)",
216
+ "status": "plan_rewound",
217
+ "sessionId": "...",
218
+ "rewoundToStep": 2,
219
+ "hasCycles": true,
220
+ "cycleDetails": ["Cycle detected involving tasks: task-0 → task-1"],
221
+ "conflictDetails": [],
222
+ "executeContext": { "currentStage": "빠진 요구사항 채우기", "stepNumber": 2, "...": "..." },
223
+ "nextAction": "plan_step"
224
+ }
225
+ ```
226
+
227
+ - `cycleDetails`와 `conflictDetails`를 보고 문제가 된 태스크의 `dependsOn`을 고친다.
228
+ - 응답의 `executeContext`로 closure부터 다시 낸다. 그다음 proximity와 continuity를 차례로 다시 제출한다.
229
+ - `isValid: false`를 그대로 두고 continuity만 다시 내면 또 되감긴다. 호출자 보고가 무효여도 막는다.
230
+ - 이 응답에는 `error` 필드가 함께 실린다. `plan_complete`나 `execute_start`로 넘어가지 않는다.
231
+ - 되감은 뒤의 closure 프롬프트에는 순환 정보도 직전 `atomicTasks`도 없다. 서브에이전트로 다시 낼 때는 응답의 `cycleDetails`와 `conflictDetails`, 직전에 제출한 `atomicTasks`를 함께 넘기고 순환을 만든 `dependsOn`을 고치라고 적는다.
232
+ - 같은 세션에서 `plan_rewound`를 연속 두 번 받으면 closure를 다시 제출하지 않는다. `cycleDetails`를 사용자에게 보여주고 어떻게 할지 묻는다. 서버는 횟수를 세지 않으므로 스킬이 센다.
233
+
198
234
  ### Reasoning Model 서브에이전트로 플래닝 추론
199
235
 
200
236
  Phase 1 플래닝(`plan_step` 4단계 + `plan_complete`)은 Spec을 태스크 DAG로 분해하는 깊은 one-shot 추론이라, 게슈탈트에서 상위 추론 모델이 진짜 값을 하는 지점이다. 각 `plan_step`의 `stepResult`(classifiedACs / atomicTasks / taskGroups / dagValidation)를 만드는 추론은 현재 세션이 직접 하지 말고 별도 Agent 서브에이전트로 스폰한다.
@@ -207,7 +243,7 @@ Phase 1 플래닝(`plan_step` 4단계 + `plan_complete`)은 Spec을 태스크 DA
207
243
  ges_status() → { reasoningModel: "fable", reasoningModelFallback: "opus", ... }
208
244
  ```
209
245
 
210
- **스폰.** 각 `plan_step`(그리고 `plan_complete` 조립을 위한 추론이 필요하면 그 단계)에서 Agent 도구로 서브에이전트를 띄우되 `model` 파라미터에 `reasoningModel` 값을 넘긴다. 서브에이전트에는 해당 단계의 `executeContext`(`systemPrompt`, `planningPrompt`, `currentPrinciple`, `spec`, `previousSteps`)를 전달하고 그 단계의 `stepResult`를 산출하게 한다. 결과를 `plan_step`으로 제출한다.
246
+ **스폰.** 각 `plan_step`(그리고 `plan_complete` 조립을 위한 추론이 필요하면 그 단계)에서 Agent 도구로 서브에이전트를 띄우되 `model` 파라미터에 `reasoningModel` 값을 넘긴다. 서브에이전트에는 해당 단계의 `executeContext`(`systemPrompt`, `planningPrompt`, `currentStage`, `spec`, `previousSteps`)를 전달하고 그 단계의 `stepResult`를 산출하게 한다. 결과를 `plan_step`으로 제출한다.
211
247
 
212
248
  **폴백은 스킬 런타임에서 발동한다.** 서버는 폴백 대상(`reasoningModelFallback`)만 알려줄 뿐, 모델 가용성을 감지하거나 재시도하지 않는다. Agent 도구가 `reasoningModel`(예: `fable`)을 지원하지 않아 스폰이 거부/실패하면, 그때 스킬이 직접 `model`을 `reasoningModelFallback`(예: `opus`)로 바꿔 1회 재시도한다. 폴백 판단과 재시도는 전적으로 이 스킬 런타임의 책임이다.
213
249
 
@@ -220,9 +256,18 @@ ges_status() → { reasoningModel: "fable", reasoningModelFallback: "opus", ..
220
256
  `plan_complete` 이후 호출. 태스크 목록을 받아 실행 준비.
221
257
 
222
258
  ```json
223
- { "action": "execute_start", "sessionId": "..." }
259
+ { "action": "execute_start", "sessionId": "...", "cwd": "/path/to/project" }
224
260
  ```
225
- → `{ status, sessionId, executionPlan, message }`
261
+
262
+ → `{ status, sessionId, executionPlan, artifactCheck, message }`
263
+
264
+ `cwd`에는 프로젝트 루트를 넘긴다. 서버가 이 디렉토리에서 git 작업 트리가 실행 시작 시점에 어떤 상태였는지 잡아 두고 나중에 `completed` 보고의 `artifacts`를 그 상태와 대조한다. `cwd`를 비우면 세션의 `codeGraphRepoRoot`를 쓰고 그것도 없으면 서버 프로세스의 cwd를 쓴다. git 레포가 아니면 대조 없이 진행한다. 대조 중에는 그 레포의 `filter.*.clean` 설정이 실행되므로 믿지 않는 레포를 `cwd`로 넘기지 않는다.
265
+
266
+ 응답에는 `artifactCheck: { repoRoot, baseline, error? }`가 붙는다. `repoRoot`는 실제로 대조에 쓸 디렉토리다. `baseline`은 아래 셋 중 하나다. `execute_task` 응답의 `artifactCheck`는 `verified` 같은 문자열 하나라 꼴이 다르다.
267
+
268
+ - `captured`: 시작 시점 상태를 잡았다. 이후 `completed` 보고를 대조한다
269
+ - `no_baseline`: git 레포가 아니라 대조하지 않는다
270
+ - `baseline_failed`: git 호출이 실패해 대조하지 않는다. 실패 내용은 `error`에 담긴다
226
271
 
227
272
  ---
228
273
 
@@ -236,6 +281,7 @@ ges_status() → { reasoningModel: "fable", reasoningModelFallback: "opus", ..
236
281
  // Call 1: 매칭 컨텍스트 요청
237
282
  { "action": "role_match", "sessionId": "..." }
238
283
  ```
284
+
239
285
  → `{ matchContext }` — 어떤 에이전트가 적합한지 판단하기 위한 프롬프트
240
286
 
241
287
  `matchContext.tierHint`는 `"frugal"`이다. `matchContext.availableAgents`에는 에이전트 20여 개의 description이 통째로 들어 있다. 그걸 세션 컨텍스트에 들이는 대신 **서브에이전트에 넘겨 1차 후보를 좁힌다.**
@@ -259,11 +305,22 @@ Agent {
259
305
  "action": "role_match",
260
306
  "sessionId": "...",
261
307
  "matchResult": [
262
- { "agentName": "technical-writer", "domain": ["documentation"], "relevanceScore": 0.9, "reasoning": "..." },
263
- { "agentName": "architect", "domain": ["architecture"], "relevanceScore": 0.7, "reasoning": "..." }
308
+ {
309
+ "agentName": "technical-writer",
310
+ "domain": ["documentation"],
311
+ "relevanceScore": 0.9,
312
+ "reasoning": "..."
313
+ },
314
+ {
315
+ "agentName": "architect",
316
+ "domain": ["architecture"],
317
+ "relevanceScore": 0.7,
318
+ "reasoning": "..."
319
+ }
264
320
  ]
265
321
  }
266
322
  ```
323
+
267
324
  → `{ perspectivePrompts }` — 각 에이전트별 관점 생성 프롬프트
268
325
 
269
326
  **`role_consensus` — 다중 관점 합의 (2-Call)**
@@ -279,6 +336,7 @@ Agent {
279
336
  ]
280
337
  }
281
338
  ```
339
+
282
340
  → `{ synthesisContext }` — 관점 통합 프롬프트
283
341
 
284
342
  ```json
@@ -293,6 +351,7 @@ Agent {
293
351
  }
294
352
  }
295
353
  ```
354
+
296
355
  → `{ roleGuidance }` — execute_task 시 참조할 최종 guidance
297
356
 
298
357
  ---
@@ -320,13 +379,13 @@ Agent {
320
379
 
321
380
  ```
322
381
  // 같은 메시지에서 동시 호출 — Agent 1
323
- Agent(task: "task-0 실행: {task-0 title}\n컨텍스트: {taskContext}\n완료 후 execute_task로 결과 제출")
382
+ Agent(task: "task-0 실행: {task-0 title}\n컨텍스트: {taskContext}\n완료 후 execute_task로 결과 제출. 바꾼 파일은 전부 artifacts에 적는다. 파일을 안 바꾸는 태스크면 noCodeChange: true를 같이 낸다. verification_failed가 오면 고쳐서 다시 제출하고 끝내지 못했으면 status: \"failed\"로 낸다. serverError: true가 함께 오면 고치지 말고 잠시 뒤 같은 결과를 다시 내고 계속 실패하면 status: \"failed\"로 낸다")
324
383
 
325
384
  // 같은 메시지에서 동시 호출 — Agent 2
326
- Agent(task: "task-1 실행: {task-1 title}\n컨텍스트: {taskContext}\n완료 후 execute_task로 결과 제출")
385
+ Agent(task: "task-1 실행: {task-1 title}\n컨텍스트: {taskContext}\n완료 후 execute_task로 결과 제출. 바꾼 파일은 전부 artifacts에 적는다. 파일을 안 바꾸는 태스크면 noCodeChange: true를 같이 낸다. verification_failed가 오면 고쳐서 다시 제출하고 끝내지 못했으면 status: \"failed\"로 낸다. serverError: true가 함께 오면 고치지 말고 잠시 뒤 같은 결과를 다시 내고 계속 실패하면 status: \"failed\"로 낸다")
327
386
 
328
387
  // 같은 메시지에서 동시 호출 — Agent 3
329
- Agent(task: "task-2 실행: {task-2 title}\n컨텍스트: {taskContext}\n완료 후 execute_task로 결과 제출")
388
+ Agent(task: "task-2 실행: {task-2 title}\n컨텍스트: {taskContext}\n완료 후 execute_task로 결과 제출. 바꾼 파일은 전부 artifacts에 적는다. 파일을 안 바꾸는 태스크면 noCodeChange: true를 같이 낸다. verification_failed가 오면 고쳐서 다시 제출하고 끝내지 못했으면 status: \"failed\"로 낸다. serverError: true가 함께 오면 고치지 말고 잠시 뒤 같은 결과를 다시 내고 계속 실패하면 status: \"failed\"로 낸다")
330
389
  ```
331
390
 
332
391
  **각 Agent의 execute_task 제출:**
@@ -345,6 +404,7 @@ Agent(task: "task-2 실행: {task-2 title}\n컨텍스트: {taskContext}\n완료
345
404
  ```
346
405
 
347
406
  실패 시:
407
+
348
408
  ```json
349
409
  {
350
410
  "action": "execute_task",
@@ -379,10 +439,54 @@ role_match/role_consensus로 얻은 `roleGuidance`를 참조해 태스크를 수
379
439
  }
380
440
  }
381
441
  ```
382
- → `{ status, nextTaskId?, allTasksCompleted, driftResult? }`
442
+
443
+ → `{ status, nextTaskId?, allTasksCompleted, artifactCheck?, driftResult? }`
383
444
 
384
445
  `driftResult`가 반환되면 Spec과의 drift 경고 — 계속 진행하되 다음 태스크에서 방향 보정.
385
446
 
447
+ **artifacts 대조.** `status: "completed"`로 보고하면 서버가 `artifacts`의 파일이 실행 시작 뒤로 실제로 바뀌었는지 확인한다. 수정하거나 새로 만들거나 커밋하거나 지운 파일은 모두 바뀐 것으로 친다. 상대 경로는 `execute_start`의 `cwd` 기준이다. 디렉토리나 gitignore에 걸린 경로는 확인할 수 없으니 바꾼 소스 파일을 하나씩 적는다. `failed`와 `skipped`는 대조하지 않는다. 대조는 `execute_task`에만 있고 `evolve_re_execute`와 `evolve_fix`로 낸 결과는 대조하지 않는다.
448
+
449
+ `artifacts`가 빈 `completed`는 거절된다. 조사나 판단처럼 원래 파일을 안 바꾸는 태스크는 `noCodeChange: true`를 같이 낸다. `artifacts`가 하나라도 있으면 `noCodeChange`와 상관없이 대조한다.
450
+
451
+ ```json
452
+ {
453
+ "action": "execute_task",
454
+ "sessionId": "...",
455
+ "taskResult": {
456
+ "taskId": "task-1",
457
+ "status": "completed",
458
+ "output": "기존 인증 흐름 조사 결과 요약",
459
+ "artifacts": [],
460
+ "noCodeChange": true
461
+ }
462
+ }
463
+ ```
464
+
465
+ 통과하면 응답에 `artifactCheck`가 붙는다.
466
+
467
+ - `verified`: 대조를 통과한 경우
468
+ - `no_code_change`: `noCodeChange: true`로 대조를 건너뛴 경우
469
+ - `no_baseline`: git 레포가 아니라 시작 시점 상태가 없는 경우
470
+ - `baseline_failed`: `execute_start` 때 git 호출이 실패해 시작 시점 상태를 못 잡은 경우
471
+ - `baseline_truncated`: 시작 시점에 커밋 안 된 파일이 2000개를 넘어 이벤트에 해시를 다 못 남겼고 이 세션을 다른 서버 프로세스가 이벤트에서 불러와 대조하지 못한 경우. 해시는 실행을 시작한 프로세스 메모리에만 있고 이벤트에는 사유만 남는다. 그래서 서버가 재시작됐거나 MCP 서버를 따로 띄우는 dispatch 워커가 보고하면 대조 없이 통과한다. 시작한 프로세스는 상태를 잡았으므로 `execute_start` 응답의 `artifactCheck.baseline`은 이때도 `captured`로 나간다. dispatch를 쓸 땐 시작 전에 커밋 안 된 파일을 줄여 둔다
472
+
473
+ **`verification_failed`를 받으면.** 바뀌지 않은 파일이 하나라도 있으면 서버는 결과를 기록하지 않고 이렇게 돌려준다.
474
+
475
+ ```json
476
+ {
477
+ "status": "verification_failed",
478
+ "recorded": false,
479
+ "problems": [{ "path": "src/auth.ts", "status": "unchanged", "hint": "실행 시작 뒤로 내용이 그대로입니다" }],
480
+ "nextAction": "execute_task"
481
+ }
482
+ ```
483
+
484
+ `problems[].status`는 `unchanged`, `missing`, `outside_repo`, `ignored`, `directory`, `invalid_path`(경로에 개행이나 NUL 문자), `not_regular_file`(FIFO나 소켓처럼 일반 파일이 아님) 중 하나다. 태스크는 아직 끝나지 않은 상태로 남는다. 파일을 실제로 고쳤는지 확인하고 수정을 마치거나 `artifacts` 목록을 바로잡아 같은 태스크를 다시 제출한다. 끝내지 못했으면 `status: "failed"`로 낸다.
485
+
486
+ 응답에 `serverError: true`가 있으면 보고 내용 문제가 아니라 서버 쪽 git 호출이 실패한 것이다. 이때는 고칠 것이 없으니 잠시 뒤 같은 결과를 그대로 다시 낸다. 계속 실패하면 `status: "failed"`로 내고 `output`에 오류 내용을 적는다.
487
+
488
+ > 기준점은 태스크마다가 아니라 `execute_start` 때 한 번 잡는다. 앞선 태스크가 바꾼 파일을 뒤 태스크가 `artifacts`에 적어도 통과한다.
489
+
386
490
  ---
387
491
 
388
492
  ## Phase 3 — Evaluate
@@ -390,12 +494,19 @@ role_match/role_consensus로 얻은 `roleGuidance`를 참조해 태스크를 수
390
494
  모든 태스크 완료 후 3-Call 평가 진행.
391
495
 
392
496
  **Call 1 — Structural 단계 시작**
497
+
393
498
  ```json
394
499
  { "action": "evaluate", "sessionId": "..." }
395
500
  ```
501
+
396
502
  → `{ stage: "structural", structuralContext }` — lint/build/test 실행 지시
397
503
 
504
+ `structuralContext.commands`의 `command` 문자열을 고치지 말고 그대로 실행한다. 패키지 매니저는 서버가 package.json의 `packageManager` 필드나 lockfile로 골라뒀다. scripts에 없는 lint, build는 목록에서 빠지고 test는 항상 남는다. 제출할 때도 같은 문자열을 그대로 싣는다 — 명령이 다르거나 빠지면 서버가 거부한다. 종료 코드가 0이 아닌 명령이 있으면 `allPassed`를 `true`로 보내도 실패로 처리된다.
505
+
506
+ 거부 메시지가 `Submitted commands do not match`로 시작하면 `structuralContext.commands`의 명령을 그대로 다시 실행해서 그 실행의 종료 코드와 출력으로 다시 제출한다. 이전 실행 결과에 명령 문자열만 바꿔 싣지 않는다. 다른 거부 메시지면 다시 제출하지 말고 Call 1부터 다시 시작한다.
507
+
398
508
  **Call 2 — Structural 결과 제출**
509
+
399
510
  ```json
400
511
  {
401
512
  "action": "evaluate",
@@ -410,24 +521,25 @@ role_match/role_consensus로 얻은 `roleGuidance`를 참조해 태스크를 수
410
521
  }
411
522
  }
412
523
  ```
413
- → structural 실패 시 `{ stage: "structural_failed", evolveContext }` → Evolve Flow A 진입
414
- → structural 통과 시 `{ stage: "contextual", evaluationContext }` — AC별 LLM 검증 지시
524
+
525
+ → structural 실패 시 `{ stage: "complete", shortCircuited: true, nextAction: "evolve_fix" }` → Evolve Flow A 진입
526
+ → structural 통과 시 `{ stage: "contextual", contextualContext }` — AC별 LLM 검증 지시
415
527
 
416
528
  **Call 3 — Contextual 결과 제출**
529
+
417
530
  ```json
418
531
  {
419
532
  "action": "evaluate",
420
533
  "sessionId": "...",
421
534
  "evaluationResult": {
422
- "verifications": [
423
- { "acIndex": 0, "satisfied": true, "evidence": "...", "gaps": [] }
424
- ],
535
+ "verifications": [{ "acIndex": 0, "satisfied": true, "evidence": "...", "gaps": [] }],
425
536
  "overallScore": 0.92,
426
537
  "goalAlignment": 0.88,
427
538
  "recommendations": []
428
539
  }
429
540
  }
430
541
  ```
542
+
431
543
  → `{ status: "completed" }` (score ≥ 0.85, goalAlignment ≥ 0.80)
432
544
  → 미달 시 `{ evolveContext }` → Evolve Flow B 진입
433
545
 
@@ -477,7 +589,7 @@ role_match/role_consensus로 얻은 `roleGuidance`를 참조해 태스크를 수
477
589
  {
478
590
  "action": "evolve_re_execute",
479
591
  "sessionId": "...",
480
- "reExecuteTaskResult": { "taskId": "task-3", "status": "completed", "output": "...", "artifacts": [] }
592
+ "reExecuteTaskResult": { "taskId": "task-3", "status": "completed", "output": "...", "artifacts": ["src/auth/oauth.ts"] }
481
593
  }
482
594
 
483
595
  // 4. Re-evaluate
@@ -510,25 +622,64 @@ role_match/role_consensus로 얻은 `roleGuidance`를 참조해 태스크를 수
510
622
  { "action": "evolve_lateral", "sessionId": "..." }
511
623
  ```
512
624
 
513
- | Stagnation 패턴 | Persona | 전략 |
625
+ | Stagnation 패턴 | Persona | 전략 |
626
+ | ------------------- | -------------- | ---------------- |
627
+ | hard_cap | Multistability | 다른 각도로 보기 |
628
+ | oscillation | Simplicity | 단순하게 줄이기 |
629
+ | no_drift | Reification | 빠진 조각 채우기 |
630
+ | diminishing_returns | Invariance | 성공 패턴 복제 |
631
+
632
+ 4개 persona를 다 써도 점수가 안 오르면 세션은 끝나지 않고 `awaiting_human`으로 멈춘다. 응답에 `gate`가 실려 온다.
633
+
634
+ ```json
635
+ → { status: "awaiting_human", gate: { gateId, question, options: [...], context }, escalationContext, nextAction: "gate_resolve", nextActionParams: { sessionId, gateResolution: { gateId } } }
636
+ ```
637
+
638
+ ### Flow D — 사람 판단 대기 (`awaiting_human`)
639
+
640
+ 여기서 스킬은 스스로 고르지 않는다. **반드시 사람에게 묻고 답을 기다린다.**
641
+
642
+ 1. `gate.question`과 `gate.context`(막힌 태스크, 시도한 persona, 최고 점수, 남은 문제)를 보여준다.
643
+ 2. `gate.options`를 선택지로 띄운다. 호스트에 선택형 질문 도구가 있으면(AskUserQuestion 등) 그걸 쓴다. 없으면 번호 목록으로 보여주고 답을 받는다. `restart`와 `abort`는 세션이 종료된다는 점을 함께 알린다.
644
+ 3. 고른 선택지에 더해 **결정(`decision`)과 이유(`rationale`)를 한 줄씩** 받는다. 둘 다 비면 서버가 거절한다. 사람이 이유를 안 적었으면 다시 묻는다. 대신 지어내지 않는다 — 이 두 줄이 그대로 Memory에 남는다.
645
+ 4. `gate_resolve`를 부른다.
646
+
647
+ ```json
648
+ {
649
+ "action": "gate_resolve",
650
+ "sessionId": "...",
651
+ "gateResolution": {
652
+ "gateId": "gate-...",
653
+ "optionId": "patch_spec",
654
+ "decision": "사람이 내린 결정",
655
+ "rationale": "그렇게 정한 이유"
656
+ }
657
+ }
658
+ ```
659
+
660
+ 5. 응답의 `nextAction`을 따른다.
661
+
662
+ | `optionId` | 응답 | 다음 |
514
663
  |---|---|---|
515
- | hard_cap | Multistability | 다른 각도로 보기 |
516
- | oscillation | Simplicity | 단순하게 줄이기 |
517
- | no_drift | Reification | 빠진 조각 채우기 |
518
- | diminishing_returns | Invariance | 성공 패턴 복제 |
664
+ | `patch_spec` | `gate_resolved`, 세션 `executing` | 사람이 말한 대로 AC나 제약을 고쳐 `evolve_patch` (Flow B) |
665
+ | `manual_task` | `gate_resolved`, 세션 `executing` | 사람이 태스크를 처리했는지 확인한 뒤 `evaluate` |
666
+ | `restart` | `terminated` | 세션 종료. 태스크를 더 잘게 쪼갠 새 스펙으로 `start`를 안내 |
667
+ | `abort` | `terminated` | 세션 종료. 막힌 지점과 시도한 접근을 보고 |
668
+
669
+ 이어간 뒤 다음 평가가 한 번만 성공 기준에 못 미쳐도 persona를 되풀이하지 않고 곧바로 새 `awaiting_human` 응답이 온다. 진화 이력과 이미 써본 persona 기록이 남아 있어서다. 그때도 1번부터 다시 한다.
519
670
 
520
- 4개 persona 소진 → `human_escalation` 반환으로 세션 종료.
671
+ `awaiting_human`인 동안에는 `status`, `resume`, `gate_resolve`, `evolution_viz` 말고는 전부 에러로 거절된다. 세션을 이어받았는데 `resume`이 `awaiting_human`을 돌려주면 1번부터 다시 한다.
521
672
 
522
673
  ### 종료 조건
523
674
 
524
- | 조건 | 트리거 |
525
- |------|--------|
526
- | `success` | score ≥ 0.85 AND goalAlignment ≥ 0.80 |
527
- | `stagnation` | 2회 연속 delta < 0.05 |
528
- | `oscillation` | 2회 연속 점수 역전 |
529
- | `hard_cap` | structural 3회 + contextual 3회 실패 |
530
- | `caller` | `{ action: "evolve", terminateReason: "caller" }` |
531
- | `human_escalation` | 4개 lateral persona 소진 |
675
+ | 조건 | 트리거 |
676
+ | ------------------ | ------------------------------------------------------------- |
677
+ | `success` | score ≥ 0.85 AND goalAlignment ≥ 0.80 |
678
+ | `stagnation` | 2회 연속 delta < 0.05 |
679
+ | `oscillation` | 2회 연속 점수 역전 |
680
+ | `hard_cap` | structural 3회 + contextual 3회 실패 |
681
+ | `caller` | `{ action: "evolve", terminateReason: "caller" }` |
682
+ | `human_escalation` | 4개 lateral persona 소진 후 사람이 `restart`나 `abort`를 고름 |
532
683
 
533
684
  ---
534
685
 
@@ -551,7 +702,13 @@ activeForm: "실행 계획 수립 중"
551
702
  `TaskUpdate`로 현재 Planning 단계를 업데이트한다.
552
703
 
553
704
  ```
554
- description: "Planning 중 | 단계 {stepsCompleted}/4 | {currentPrinciple}"
705
+ description: "Planning 중 | 단계 {stepsCompleted}/4 | {executeContext.currentStage}"
706
+ ```
707
+
708
+ `plan_rewound`를 받으면 `stepsCompleted`가 없으므로 이렇게 바꾼다.
709
+
710
+ ```
711
+ description: "Planning 되감김 | 단계 {rewoundToStep - 1}/4 | {executeContext.currentStage}"
555
712
  ```
556
713
 
557
714
  ### Execution 시작 후 (`execute_start` 응답 수신 후)
@@ -584,12 +741,14 @@ activeForm: "병렬 실행 중: 그룹 {groupIndex}/{totalGroups} — {agentCoun
584
741
  `TaskUpdate`로 진행 상황과 현재 실행 태스크명을 업데이트한다.
585
742
 
586
743
  순차 실행 중:
744
+
587
745
  ```
588
746
  description: "{completedCount}/{totalTasks} 완료 | 실패: {failedCount}개 | 그룹 {groupIndex}/{totalGroups}"
589
747
  activeForm: "실행 중: {taskContext.currentTask.title}"
590
748
  ```
591
749
 
592
750
  병렬 그룹 실행 중 (각 Agent의 execute_task 완료 시):
751
+
593
752
  ```
594
753
  description: "{completedCount}/{totalTasks} 완료 | 실패: {failedCount}개 | 그룹 {groupIndex}/{totalGroups}"
595
754
  activeForm: "병렬 실행 중: 그룹 {groupIndex}/{totalGroups} — {agentCount}개 Agent 실행 중"
@@ -609,6 +768,14 @@ activeForm: "병렬 실행 중: 그룹 {groupIndex}/{totalGroups} — {agentCoun
609
768
  - 평가 완료(success): `TaskUpdate({ status: "completed", description: "완료 | score: {overallScore} | alignment: {goalAlignment}" })`
610
769
  - Evolve 진입: description에 "개선 중 (generation {N})" 추가
611
770
 
771
+ ### 사람 판단 대기 시 (`awaiting_human`)
772
+
773
+ ```
774
+ description: "사람 판단 대기 | 최고 점수: {gate.context.bestScore}"
775
+ ```
776
+
777
+ `gate_resolve`가 `gate_resolved`를 돌려주면 진화 단계 표시로 돌아간다.
778
+
612
779
  ### 오류/에스컬레이션 시
613
780
 
614
781
  ```
@@ -128,7 +128,15 @@ The interview only has value if the human's actual intent is captured. A self-an
128
128
  1. **Start**: Create a session, detect project type (greenfield/brownfield), ask the first question
129
129
  2. **Iterate**: Present each generated question to the user → wait for answer → submit answer to Gestalt
130
130
  3. **Score**: Continuously assess resolution across multiple dimensions
131
- 4. **Complete**: When resolution score ≥ 0.8, the interview is ready for spec generation
131
+ 4. **Complete**: Call `complete` only after `resolutionScore.isReady === true` (overall ≥ 0.8). The server rejects `complete` on a session that has no score or is below threshold
132
+
133
+ ### 0.8 미만에서 끝내기
134
+
135
+ 사용자가 0.8 미만에서 넘어가겠다고 직접 답한 경우에만 `force: true`로 `complete`를 부른다. 15라운드를 다 채워 `respond`가 더 받지 않으면 그 마지막 답의 점수는 반영되지 않은 상태다. 먼저 `score`로 그 점수를 넣고 `isReady`를 확인한다. 그래도 0.8 미만이면 에이전트가 현재 점수와 덜 채워진 차원을 보여주고 넘어갈지 묻는다. 라운드 수만으로 `force`를 넘기지 않는다. 사용자가 먼저 "그냥 넘어가자"고 했을 때도 같은 내용을 보여주고 한 번 더 확인한 뒤에 부른다.
136
+
137
+ 사용자가 넘어가지 않겠다고 하면 세션을 `in_progress`로 둔다. 15라운드 전이면 같은 세션에서 덜 채워진 차원을 다시 묻는다. 15라운드를 다 채웠으면 덜 채워진 차원을 사용자와 함께 정리해 새 인터뷰로 이어가거나 거기서 멈춘다.
138
+
139
+ 에이전트가 스스로 `force`를 판단하지 않는다. 거절 메시지에 "force=true로 넘기세요"가 나와도 그건 사용자에게 물어볼 근거이지 바로 넘길 근거가 아니다. 이렇게 끝낸 세션에는 `forcedComplete`가 기록된다. Spec을 뽑을 때도 `ges_generate_spec`에 `force`를 따로 넘겨야 한다.
132
140
 
133
141
  ## Gestalt Principles Applied
134
142
 
@@ -154,9 +162,12 @@ API 키 없이 MCP 서버 실행 시 자동 활성화. LLM 작업을 caller가
154
162
  | `resolutionScore.priorityClarity` | number (0-1) | 필수* | 우선순위 명확도 |
155
163
  | `resolutionScore.contextClarity` | number (0-1) | 선택 | 컨텍스트 명확도 |
156
164
  | `resolutionScore.contradictions` | string[] | 선택 | 발견된 모순 목록 |
165
+ | `force` | boolean | 선택 (기본 `false`) | `complete` 전용. 0.8 미만이어도 완료한다. 사용자가 직접 정했을 때만 넘긴다 |
157
166
 
158
167
  \* resolutionScore 객체를 제공할 경우 필수
159
168
 
169
+ 답변 라운드가 0인 세션에 기준을 넘는 resolutionScore를 넣으면 `score`와 `respond`가 거절한다. 공백만 보낸 답은 답변으로 세지 않는다. 기준 미만 점수는 받는다.
170
+
160
171
  ### Action별 응답 구조 (Passthrough)
161
172
 
162
173
  **`start`** → `{ status, sessionId, projectType, detectedFiles, gestaltContext, roundNumber, message }`
@@ -166,7 +177,9 @@ API 키 없이 MCP 서버 실행 시 자동 활성화. LLM 작업을 caller가
166
177
  **`score`** (점수 미제공 시) → `{ status, resolutionScore, scoringPrompt, message }`
167
178
  **`score`** (점수 제공 시) → `{ status, resolutionScore }`
168
179
 
169
- **`complete`** → `{ status, sessionId, totalRounds, finalResolutionScore, message }`
180
+ **`complete`** → `{ status, sessionId, totalRounds, finalResolutionScore, forced, message }`
181
+
182
+ `forced`는 기준 미만 세션을 `force`로 끝냈을 때만 `true`다. 이미 준비된 세션에 `force`를 넘겨도 `false`로 남는다.
170
183
 
171
184
  ### GestaltContext 필드
172
185
 
@@ -25,7 +25,7 @@ outputs:
25
25
  > `ges_*` 도구가 없거나 호출이 실패하면 직접 흉내내 진행하지 않고 무엇이 왜 안 되는지 말하고 멈춥니다.
26
26
 
27
27
  - **인터뷰**: 사람이 직접 답변 (큰 관점 정리 포함, 자동화하지 않음)
28
- - **스펙 생성 이후**: AI가 자율로 드라이빙 — 사람 개입 없이 루프를 돌린다
28
+ - **스펙 생성 이후**: AI가 자율로 드라이빙 — 사람 개입 없이 루프를 돌린다. lateral persona를 다 써서 `awaiting_human`으로 멈췄을 때만 사람에게 묻는다
29
29
 
30
30
  ---
31
31
 
@@ -84,12 +84,14 @@ Phase 3의 레포 안 탐색까지 앞당기지는 않는다. 그건 실행 대
84
84
 
85
85
  → resolutionScore.isReady === true 또는 overallScore ≥ 0.8이 될 때까지 반복한다.
86
86
 
87
- 완료:
87
+ 완료 (`isReady === true`일 때만):
88
88
 
89
89
  ```json
90
90
  { "action": "complete", "sessionId": "..." }
91
91
  ```
92
92
 
93
+ 0.8 미만이면 서버가 `complete`를 거절한다. 자율 루프라도 `force`는 에이전트가 정하지 않는다. 15라운드를 다 채운 경우에는 마지막 답의 점수가 빠져 있으니 먼저 `score`로 넣고 `isReady`를 확인한다. 그래도 0.8 미만이면 사용자에게 현재 점수를 보여주고 넘어가기로 직접 답했을 때만 `{ "action": "complete", "sessionId": "...", "force": true }`로 부른다. 이렇게 끝낸 세션은 `complete` 응답에 `forced: true`가 온다. 그 값을 근거로 Phase 2에서 `ges_generate_spec`에도 `force: true`를 넘긴다.
94
+
93
95
  ### 진행 패널
94
96
 
95
97
  세 Phase를 도는 동안 사용자가 어디까지 왔는지 볼 자리를 만든다. 패널은 best-effort다 — 패널을 못 만들거나 못 고쳐도 인터뷰와 스펙과 실행은 그대로 간다.
@@ -143,7 +145,7 @@ description: "Phase 2/3 — 스펙 완료 | AC {N}개"
143
145
 
144
146
  ## Phase 3 — Execute 루프 (자율)
145
147
 
146
- 스펙을 받아 실행 → 평가 → 개선 루프를 자율로 드라이빙한다. **사람 개입 없이 루프를 돈다.**
148
+ 스펙을 받아 실행 → 평가 → 개선 루프를 자율로 드라이빙한다. **사람 개입 없이 루프를 돈다.** 예외는 lateral persona를 다 써서 세션이 사람 판단을 기다릴 때 하나다 (→ [사람 판단 대기](#사람-판단-대기-awaiting_human)).
147
149
 
148
150
  execute 스킬의 전체 파이프라인(Planning → Execution → Evaluate → Evolve)을 그대로 따른다. 단, 각 단계 사이에서 사람에게 확인을 구하지 않는다.
149
151
 
@@ -168,9 +170,21 @@ activeForm: "{현재 단계: 실행 중 / 평가 중 / 개선 중}"
168
170
  | 조건 | 대응 |
169
171
  |------|------|
170
172
  | `success` (score ≥ 0.85, goalAlignment ≥ 0.80) | 루프 종료 → 완료 보고 |
171
- | `human_escalation` (lateral 4개 소진) | 루프 종료 → 막힌 지점과 시도한 접근법 보고 |
173
+ | `awaiting_human` (lateral 4개 소진) | 루프를 멈추고 사람에게 묻는다 → `gate_resolve` → `nextAction`대로 이어간다 (아래 참고) |
174
+ | `human_escalation` (사람이 `restart`나 `abort`를 고름) | 루프 종료 → 막힌 지점과 시도한 접근법 보고 |
172
175
  | `caller` (사용자가 명시적으로 중단) | 즉시 종료 |
173
176
 
177
+ ### 사람 판단 대기 (`awaiting_human`)
178
+
179
+ lateral persona 4개를 다 써도 점수가 안 오르면 세션은 끝나지 않고 `awaiting_human`으로 멈춘다. 여기는 인터뷰와 같다. **반드시 사람에게 묻고 답을 기다린다.** 스스로 고르지 않는다.
180
+
181
+ 1. `gate.question`과 막힌 지점(`gate.context`)을 보여주고 `gate.options`를 선택지로 띄운다.
182
+ 2. 고른 선택지와 함께 결정과 이유를 한 줄씩 받는다. 비어 있으면 서버가 거절한다. 대신 채우지 않는다 — 그대로 Memory에 남는 말이다.
183
+ 3. `ges_execute { action: "gate_resolve", sessionId, gateResolution: { gateId, optionId, decision, rationale } }`를 부른다.
184
+ 4. `patch_spec`이면 `evolve_patch`로, `manual_task`면 사람이 처리한 걸 확인하고 `evaluate`로 루프를 이어간다. `restart`나 `abort`면 세션이 종료되니 루프를 끝내고 아래 에스컬레이션 보고를 한다.
185
+
186
+ 자세한 흐름은 execute 스킬의 Flow D와 같다.
187
+
174
188
  ### 완료 보고
175
189
 
176
190
  루프 종료 시 사람에게 결과를 보고한다:
@@ -216,7 +230,8 @@ description: "에스컬레이션 | 최고 점수: {bestScore} | {시도한 perso
216
230
  execute → evaluate → evolve → re-execute → evaluate → ...
217
231
  ↓
218
232
  success → 완료 보고
219
- human_escalation → 막힌 지점 보고
233
+ awaiting_human → 사람에게 묻고 gate_resolve → 이어가거나 종료
234
+ human_escalation (restart/abort) → 막힌 지점 보고
220
235
  ```
221
236
 
222
237
  인터뷰에서 사람과 큰 관점을 충분히 정리한 뒤, 그 이후는 AI가 목표를 향해 스스로 루프를 돈다.