elanous 0.2.15 → 0.2.17

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 (309) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/chunks/{1307-33ffcc49ab45123b.js → 1307-aac7332576c4d6fc.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{6877-7c6208705c284124.js → 6877-fe94e76a5841ee9b.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/8401-4ce1c42c8d89903f.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/899-f41be85e8a680651.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/{9103-7a3ae7f60af3b99f.js → 9103-60fbef33e66f0a46.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/9247-269e4464cc4b491c.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/app/approvals/{page-0e2c57fe6add4b2a.js → page-3143b07a817d1da9.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-e05a77df7e005b04.js → page-17ba086ef82d339b.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/app/board/page-7eb661ff23af7da2.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/app/botlab/page-6b8444914da74ca6.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/app/bots/{page-b8c49f6b4fa2df91.js → page-6e5c3a867557298b.js} +1 -1
  14. package/apps/pwa/out/_next/static/chunks/app/ceo/page-7110f732f45bf944.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/app/chat/{page-976813c91d7394ea.js → page-9a41d65355fc25b9.js} +1 -1
  16. package/apps/pwa/out/_next/static/chunks/app/consult/page-5e77cd1802567c89.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/app/control/{page-1d4901eb7c2d8822.js → page-41afec0b255ed2bb.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/app/design-check/{page-72d3e7ff35a8c954.js → page-4187666132fc98c4.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/app/editor/{page-60c7a8e1a4fe62ce.js → page-09328d499162bae4.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/app/exec/{page-2a52b316cb143d9c.js → page-29ff3a8f84f03b6a.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/app/field/{page-c3ce483c8d5db370.js → page-80ec7401bc83f511.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/app/inside/page-ab93b240f687d69a.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/app/intake/{page-96f074f6538e8a2c.js → page-fc7d86467291ae38.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/app/{layout-e97be5334d83a9f5.js → layout-de43a186e5ba5683.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/app/live/page-8b08cafad27759c9.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/app/loops/page-0e2d6985fb42cd2f.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/app/market/page-13e4108999f58d13.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e8296ee284aa1293.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/app/morning/{page-c1343f9499d86f3f.js → page-043a9111e74f6b24.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/app/{not-found-8739a2e0ae793130.js → not-found-23a4601ceb7f452e.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1ed1324b1dc36754.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-d23b12bb92242558.js → page-10d958605a77b3bd.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-166745e51ac0c7b0.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/app/ops/seats/{page-c7fea475488201a8.js → page-a04260b8ccc968d4.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/app/outputs/page-7a1d85e121065cc8.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/app/page-1f50e3d4e13435f4.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/app/reflection/{page-5efbf81124c474ae.js → page-12916918988ac97e.js} +1 -1
  38. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d8a3347a9d0c3f4a.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/app/sessions/page-a9117d2cd3093d36.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-06ee266953d9c879.js → page-5a64cb5208c6a8fd.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/app/settings/{page-153c2b3bcc89e8de.js → page-1407ec83ea64c1f9.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-1d824510df025d18.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/app/setup/page-6e878ebbe1737d00.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/app/share/{page-0d6d23b40263a7ea.js → page-7f49fe645d5132f7.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/app/showroom/page-81a4e7f8dbfe74cb.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/app/tasks/page-27d71f131acd9320.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/app/term/page-3ab59d19913b200e.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/today/page-bf85b2f5bf077925.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/trace/{page-73735b64bfe1ae67.js → page-424659bacfb8cdd7.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/app/vault/page-ab32a8f522a60371.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-f7e631e9b4daf66e.js → page-fc2df261f8a2c7df.js} +1 -1
  52. package/apps/pwa/out/_next/static/chunks/app/workflows/page-09461366af82ef13.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-9817c7f9007466cc.js → page-5d4fef9ccd7d406b.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ea90a8ac73ce2749.js +1 -0
  55. package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +1 -0
  56. package/apps/pwa/out/_next/static/css/{04dabcbcc4bfa6db.css → 085673d826b98b62.css} +1 -1
  57. package/apps/pwa/out/approvals/index.html +1 -1
  58. package/apps/pwa/out/approvals/index.txt +15 -15
  59. package/apps/pwa/out/autopilot/index.html +1 -1
  60. package/apps/pwa/out/autopilot/index.txt +15 -15
  61. package/apps/pwa/out/board/index.html +1 -1
  62. package/apps/pwa/out/board/index.txt +15 -15
  63. package/apps/pwa/out/botlab/index.html +1 -1
  64. package/apps/pwa/out/botlab/index.txt +15 -15
  65. package/apps/pwa/out/bots/index.html +1 -1
  66. package/apps/pwa/out/bots/index.txt +15 -15
  67. package/apps/pwa/out/ceo/index.html +1 -1
  68. package/apps/pwa/out/ceo/index.txt +15 -15
  69. package/apps/pwa/out/chat/index.html +1 -1
  70. package/apps/pwa/out/chat/index.txt +15 -15
  71. package/apps/pwa/out/consult/index.html +1 -1
  72. package/apps/pwa/out/consult/index.txt +15 -15
  73. package/apps/pwa/out/control/index.html +1 -1
  74. package/apps/pwa/out/control/index.txt +15 -15
  75. package/apps/pwa/out/design-check/index.html +1 -1
  76. package/apps/pwa/out/design-check/index.txt +15 -15
  77. package/apps/pwa/out/editor/index.html +1 -1
  78. package/apps/pwa/out/editor/index.txt +15 -15
  79. package/apps/pwa/out/exec/index.html +1 -1
  80. package/apps/pwa/out/exec/index.txt +15 -15
  81. package/apps/pwa/out/field/index.html +1 -1
  82. package/apps/pwa/out/field/index.txt +15 -15
  83. package/apps/pwa/out/healthz +1 -1
  84. package/apps/pwa/out/index.html +1 -1
  85. package/apps/pwa/out/index.txt +15 -15
  86. package/apps/pwa/out/inside/index.html +1 -1
  87. package/apps/pwa/out/inside/index.txt +15 -15
  88. package/apps/pwa/out/intake/index.html +1 -1
  89. package/apps/pwa/out/intake/index.txt +15 -15
  90. package/apps/pwa/out/live/index.html +1 -1
  91. package/apps/pwa/out/live/index.txt +15 -15
  92. package/apps/pwa/out/loops/index.html +1 -1
  93. package/apps/pwa/out/loops/index.txt +15 -15
  94. package/apps/pwa/out/market/index.html +1 -1
  95. package/apps/pwa/out/market/index.txt +15 -15
  96. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  97. package/apps/pwa/out/missions/placeholder/index.txt +15 -15
  98. package/apps/pwa/out/morning/index.html +1 -1
  99. package/apps/pwa/out/morning/index.txt +15 -15
  100. package/apps/pwa/out/observatory/index.html +1 -1
  101. package/apps/pwa/out/observatory/index.txt +15 -15
  102. package/apps/pwa/out/ops/checklist/index.html +1 -1
  103. package/apps/pwa/out/ops/checklist/index.txt +15 -15
  104. package/apps/pwa/out/ops/release/index.html +1 -1
  105. package/apps/pwa/out/ops/release/index.txt +15 -15
  106. package/apps/pwa/out/ops/seats/index.html +1 -1
  107. package/apps/pwa/out/ops/seats/index.txt +15 -15
  108. package/apps/pwa/out/outputs/index.html +1 -1
  109. package/apps/pwa/out/outputs/index.txt +15 -15
  110. package/apps/pwa/out/reflection/index.html +1 -1
  111. package/apps/pwa/out/reflection/index.txt +16 -16
  112. package/apps/pwa/out/scheduler/index.html +1 -1
  113. package/apps/pwa/out/scheduler/index.txt +15 -15
  114. package/apps/pwa/out/sessions/index.html +1 -1
  115. package/apps/pwa/out/sessions/index.txt +15 -15
  116. package/apps/pwa/out/settings/devices/index.html +1 -1
  117. package/apps/pwa/out/settings/devices/index.txt +15 -15
  118. package/apps/pwa/out/settings/index.html +1 -1
  119. package/apps/pwa/out/settings/index.txt +15 -15
  120. package/apps/pwa/out/setup/done/index.html +1 -1
  121. package/apps/pwa/out/setup/done/index.txt +15 -15
  122. package/apps/pwa/out/setup/index.html +1 -1
  123. package/apps/pwa/out/setup/index.txt +15 -15
  124. package/apps/pwa/out/share/index.html +1 -1
  125. package/apps/pwa/out/share/index.txt +15 -15
  126. package/apps/pwa/out/showroom/index.html +1 -1
  127. package/apps/pwa/out/showroom/index.txt +15 -15
  128. package/apps/pwa/out/tasks/index.html +1 -1
  129. package/apps/pwa/out/tasks/index.txt +15 -15
  130. package/apps/pwa/out/term/index.html +1 -1
  131. package/apps/pwa/out/term/index.txt +15 -15
  132. package/apps/pwa/out/today/index.html +1 -1
  133. package/apps/pwa/out/today/index.txt +15 -15
  134. package/apps/pwa/out/trace/index.html +1 -1
  135. package/apps/pwa/out/trace/index.txt +15 -15
  136. package/apps/pwa/out/vault/index.html +1 -1
  137. package/apps/pwa/out/vault/index.txt +15 -15
  138. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  139. package/apps/pwa/out/workflows/chat-ui/index.txt +15 -15
  140. package/apps/pwa/out/workflows/index.html +1 -1
  141. package/apps/pwa/out/workflows/index.txt +15 -15
  142. package/apps/pwa/out/workspace/index.html +1 -1
  143. package/apps/pwa/out/workspace/index.txt +15 -15
  144. package/apps/pwa/out/worktrees/index.html +1 -1
  145. package/apps/pwa/out/worktrees/index.txt +15 -15
  146. package/graphs/doc-gen/doc-gen.yaml +24 -0
  147. package/graphs/doc-gen/recipes.yaml +3 -0
  148. package/graphs/intake/intake-daily.yaml +9 -2
  149. package/graphs/intake/news-sources.yaml +4 -0
  150. package/graphs/intake/recipes.yaml +6 -1
  151. package/graphs/orchestrator/orchestrator.yaml +7 -0
  152. package/graphs/orchestrator/recipes.yaml +3 -0
  153. package/graphs/steward/recipes.yaml +2 -1
  154. package/package.json +1 -1
  155. package/scripts/__fixtures__/intake-news.xml +7 -0
  156. package/scripts/ci-public-export-import-gate.ts +154 -0
  157. package/scripts/ci-test-interference-gate.ts +5 -1
  158. package/scripts/ci-typecheck-changed.ts +34 -15
  159. package/scripts/docs/doc-rot.ts +164 -0
  160. package/scripts/docs/generate-graph-anatomy.ts +131 -9
  161. package/scripts/docs-cli-check.ts +4 -4
  162. package/scripts/goals/goal-census.ts +343 -0
  163. package/scripts/intake-news.ts +169 -0
  164. package/scripts/measure/author-section-contribution.ts +84 -0
  165. package/scripts/release-loop/cut-branch.ts +43 -13
  166. package/scripts/release-loop/docs-land-node.ts +69 -10
  167. package/scripts/release-loop/gate-node.ts +3 -1
  168. package/scripts/release-loop/publish-node.ts +2 -2
  169. package/scripts/release-loop/release-docs.ts +134 -0
  170. package/scripts/release-loop/vault-note-node.ts +19 -2
  171. package/scripts/release-loop/version-node.ts +7 -4
  172. package/scripts/release-story/draft.ts +42 -14
  173. package/scripts/rhythm/monthly.ts +97 -0
  174. package/src/acp/client.ts +17 -2
  175. package/src/agent-mission/driver.ts +104 -11
  176. package/src/agent-mission/supervisor-metrics-cli.ts +40 -0
  177. package/src/agent-mission/supervisor-metrics.ts +218 -0
  178. package/src/autopilot/track-agent-shadow.ts +2 -1
  179. package/src/autopilot/track-agent.ts +5 -3
  180. package/src/briefing/brief-items.ts +191 -36
  181. package/src/budget/usage-outcomes.ts +204 -0
  182. package/src/cli/autopilot-cli.ts +66 -0
  183. package/src/cli/brief-cli.ts +73 -0
  184. package/src/cli/decisions-cli.ts +4 -1
  185. package/src/cli/intake-cli.ts +1 -1
  186. package/src/cli/know-cli.ts +20 -0
  187. package/src/cli/log-event-names.ts +1 -0
  188. package/src/cli/logs-cli.ts +43 -1
  189. package/src/cli/pr-cli.ts +92 -13
  190. package/src/cli/provider-cli.ts +14 -0
  191. package/src/cli/release-cli.ts +11 -8
  192. package/src/cli/self-update-canary.ts +46 -0
  193. package/src/cli/self-update.ts +399 -1
  194. package/src/cli/usage-cli.ts +26 -0
  195. package/src/context-card/index.ts +45 -0
  196. package/src/context-card/task.ts +76 -0
  197. package/src/dashboard/slash-runtime/dashboard-handlers.ts +2 -0
  198. package/src/decisions/decision-ledger.ts +10 -1
  199. package/src/discord-self-message.ts +9 -0
  200. package/src/flow-loop/split.ts +24 -0
  201. package/src/harness/harness-cli-command.ts +178 -12
  202. package/src/harness/harness-pod-dispatch.ts +36 -55
  203. package/src/harness/harness-queue.ts +86 -7
  204. package/src/harness/harness-seams.ts +13 -3
  205. package/src/harness/helper-repair.ts +139 -8
  206. package/src/harness/helper-scan.ts +13 -2
  207. package/src/harness/nested-elanous-policy.ts +133 -0
  208. package/src/hq/fence-wrapper.ts +123 -0
  209. package/src/hq/hq.ts +16 -2
  210. package/src/hq/lease.ts +5 -3
  211. package/src/hq/transfer.ts +185 -0
  212. package/src/index.ts +168 -13
  213. package/src/intake-plane/digest.ts +85 -28
  214. package/src/knowledge/know-find.ts +105 -0
  215. package/src/llm.ts +75 -19
  216. package/src/loops/orchestrator/finish-rate.ts +14 -3
  217. package/src/loops/orchestrator/tick.ts +96 -25
  218. package/src/maturity/bot-slash-catalog.ts +11 -2
  219. package/src/maturity/feature-maturity.ts +2 -2
  220. package/src/maturity/tui-slash-availability.ts +9 -0
  221. package/src/nexus/api/grid.ts +61 -0
  222. package/src/nexus/api/http-server.ts +19 -1
  223. package/src/nexus/api/task-cards-api.ts +19 -0
  224. package/src/oauth/codex.ts +82 -2
  225. package/src/oauth/overload-failover-launch.ts +75 -0
  226. package/src/oauth/overload-failover.ts +137 -0
  227. package/src/release-loop/checklist.ts +10 -5
  228. package/src/release-loop/feature-store.ts +10 -9
  229. package/src/release-loop/landing-freeze.ts +18 -10
  230. package/src/release-loop/placement.ts +17 -8
  231. package/src/seat-dispatch/seat-ask.ts +33 -6
  232. package/src/seat-loop/seat-loop.ts +172 -21
  233. package/src/self-dev/ask-launch-flow.ts +48 -8
  234. package/src/self-dev/authored-goal-trace.ts +64 -0
  235. package/src/self-dev/dev-cli.ts +19 -1
  236. package/src/self-dev/dev-pipeline.ts +6 -5
  237. package/src/self-dev/entrance-registry.ts +10 -6
  238. package/src/self-dev/old-door.ts +73 -0
  239. package/src/self-dev/run-store.ts +5 -1
  240. package/src/self-dev/run-supervisor.ts +7 -1
  241. package/src/self-dev/supervisor-verdict-edges.ts +46 -0
  242. package/src/self-implement/app-api-budget.ts +166 -0
  243. package/src/self-implement/budget-gate.ts +7 -5
  244. package/src/self-implement/follow-up-goals.ts +289 -0
  245. package/src/self-implement/frozen-merges.ts +25 -20
  246. package/src/self-implement/goal-author-clarification.ts +81 -0
  247. package/src/self-implement/goal-author-cli.ts +33 -5
  248. package/src/self-implement/goal-author.ts +107 -25
  249. package/src/self-implement/goal-clarification-escalation.ts +37 -1
  250. package/src/self-implement/goal-document-write.ts +28 -0
  251. package/src/self-implement/heal-intake.ts +4 -0
  252. package/src/self-implement/heal-triage.ts +44 -0
  253. package/src/self-implement/host-regate.ts +3 -1
  254. package/src/self-implement/orchestrator.ts +157 -8
  255. package/src/self-implement/run-ledger.ts +4 -0
  256. package/src/self-implement/seams.ts +44 -15
  257. package/src/session-runtime/index.ts +2 -0
  258. package/src/session-runtime/retry-api.ts +87 -0
  259. package/src/session-runtime/retry-policy.ts +107 -6
  260. package/src/steward/working-backwards.ts +16 -1
  261. package/src/task-agent/actions.ts +118 -0
  262. package/src/task-agent/judge.ts +96 -0
  263. package/src/task-cards/card-cli.ts +25 -0
  264. package/src/task-cards/card-store.ts +9 -4
  265. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +33 -4
  266. package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
  267. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +4 -3
  268. package/src/task-orchestrator/surfaces/pod-ledger-prod-sink.ts +75 -0
  269. package/src/task-orchestrator/surfaces/pod-pool.ts +95 -18
  270. package/src/task-orchestrator/surfaces/pod-source-receive.ts +37 -1
  271. package/src/task-orchestrator/surfaces/self-implement-pod.ts +168 -37
  272. package/src/task-orchestrator/surfaces/self-implement.ts +2 -0
  273. package/src/telegram-commands.ts +6 -1
  274. package/src/telegram-loops-command.ts +21 -14
  275. package/src/telegram.ts +47 -0
  276. package/src/user-config.ts +59 -4
  277. package/src/version/packed-revision.json +1 -1
  278. package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +0 -1
  279. package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +0 -1
  280. package/apps/pwa/out/_next/static/chunks/9247-29d889b809288e65.js +0 -1
  281. package/apps/pwa/out/_next/static/chunks/app/board/page-f544338193a9a762.js +0 -1
  282. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5491c115b1f9a923.js +0 -1
  283. package/apps/pwa/out/_next/static/chunks/app/ceo/page-96398e364fbd4548.js +0 -1
  284. package/apps/pwa/out/_next/static/chunks/app/consult/page-28b9448091776c06.js +0 -1
  285. package/apps/pwa/out/_next/static/chunks/app/inside/page-13c7b53e0c2519a9.js +0 -1
  286. package/apps/pwa/out/_next/static/chunks/app/live/page-65e484302921a932.js +0 -1
  287. package/apps/pwa/out/_next/static/chunks/app/loops/page-34d08facaf08f556.js +0 -1
  288. package/apps/pwa/out/_next/static/chunks/app/market/page-955ec2da3be4c560.js +0 -1
  289. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-9f88fbc15d9058d1.js +0 -1
  290. package/apps/pwa/out/_next/static/chunks/app/observatory/page-c9fc5706b8abaa11.js +0 -1
  291. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8d47f45a0dc044ac.js +0 -1
  292. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e2ee2896811e98d0.js +0 -1
  293. package/apps/pwa/out/_next/static/chunks/app/page-83b19dae8619de05.js +0 -1
  294. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f1a1fc0a82738c.js +0 -1
  295. package/apps/pwa/out/_next/static/chunks/app/sessions/page-da6c08aae0f92768.js +0 -1
  296. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-87a11e6a05f15199.js +0 -1
  297. package/apps/pwa/out/_next/static/chunks/app/setup/page-7d4182964407c09c.js +0 -1
  298. package/apps/pwa/out/_next/static/chunks/app/showroom/page-7e8c39241f8eb6d0.js +0 -1
  299. package/apps/pwa/out/_next/static/chunks/app/tasks/page-008c1a96618a4887.js +0 -1
  300. package/apps/pwa/out/_next/static/chunks/app/term/page-f5597e894c02cd33.js +0 -1
  301. package/apps/pwa/out/_next/static/chunks/app/today/page-0337fdf7fb5e37b6.js +0 -1
  302. package/apps/pwa/out/_next/static/chunks/app/vault/page-8fcec4c9ea2e7f70.js +0 -1
  303. package/apps/pwa/out/_next/static/chunks/app/workflows/page-4881b8f9f63694b4.js +0 -1
  304. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-97f9f43172a3a90e.js +0 -1
  305. package/apps/pwa/out/_next/static/css/1f7c958c41ffa3b9.css +0 -1
  306. package/src/launch-head/seat-goal-queue-lock.fixture.ts +0 -15
  307. package/src/launch-head/seat-goal-queue.ts +0 -198
  308. /package/apps/pwa/out/_next/static/{LZcstaO9_NXypPFmujolv → yRA5ur6DcPl0YHSRheH2O}/_buildManifest.js +0 -0
  309. /package/apps/pwa/out/_next/static/{LZcstaO9_NXypPFmujolv → yRA5ur6DcPl0YHSRheH2O}/_ssgManifest.js +0 -0
@@ -1,9 +1,11 @@
1
1
  import { readFileSync, realpathSync } from 'node:fs';
2
+ import { writeGoalDocumentAtomic } from './goal-document-write.js';
2
3
  import { isAbsolute, relative, resolve } from 'node:path';
3
4
  import { debug } from '../debug/log.js';
5
+ import { getUserConfig } from '../user-config.js';
4
6
  import { parseAskProseTitle } from '../self-dev/launch-preflight.js';
5
7
  import { createGoalAuthorDecomposeSteps, readRecentStepCountsFailOpen, type RecentStepCountReader } from './goal-author-decompose.js';
6
- import { defaultGoalAuthorSelfResolve, parseGoalDocumentClarifications, seedGoalAuthorFromAnsweredClarification, seedGoalAuthorFromClarification } from './goal-author-clarification.js';
8
+ import { defaultGoalAuthorSelfResolve, parseGoalDocumentClarifications, seedGoalAuthorFromAnsweredClarification, seedGoalAuthorFromClarification, selfAnswerGoalDocumentClarifications } from './goal-author-clarification.js';
7
9
  import { classifyGoalInterviewRound, type GoalInterviewRoundStatus } from './goal-author-closure.js';
8
10
  import { recordGoalAsk } from './goal-ask-store.js';
9
11
  import { pressDecisionSignal } from './decision-signal-press.js';
@@ -15,6 +17,8 @@ import {
15
17
  verbatimOriginalAsk,
16
18
  writeAuthoredGoal,
17
19
  type GoalAuthorDeps,
20
+ type GoalAuthorGradeSelection,
21
+ resolveGoalAuthorGrade,
18
22
  type GoalType,
19
23
  type GoalFileLintFinding,
20
24
  } from './goal-author.js';
@@ -77,6 +81,7 @@ interface GoalAuthorCliOptions {
77
81
  supersedes?: string;
78
82
  rootIntent?: string;
79
83
  goalType?: string;
84
+ authorGrade?: GoalAuthorGradeSelection;
80
85
  selfResolveClarifications?: boolean;
81
86
  adversarialReview?: boolean;
82
87
  disableAdversarialReview?: boolean;
@@ -97,6 +102,7 @@ export interface GoalAuthorCliDeps {
97
102
  recentStepCountReader?: RecentStepCountReader;
98
103
  /** Resolver supplied only by the explicit CLI self-resolution opt-in. */
99
104
  selfResolveClarification?: NonNullable<GoalAuthorDeps['selfResolveClarification']>;
105
+ writeFile?: (path: string, document: string) => void;
100
106
  recordAsk?: typeof recordGoalAsk;
101
107
  }
102
108
 
@@ -268,8 +274,9 @@ export async function runGoalAuthorCli(
268
274
  : opts.reauthorFromAnsweredClarification
269
275
  ? { origin: 'answered-clarification-reauthor' }
270
276
  : { origin: 'direct-request' };
271
- const recentStepCounts = readRecentStepCountsFailOpen(deps.recentStepCountReader);
272
- const decomposeSteps = deps.decomposeSteps ?? (deps.createDecomposeSteps ?? createGoalAuthorDecomposeSteps)(undefined, {
277
+ const authorGrade = opts.authorGrade ?? resolveGoalAuthorGrade(undefined, getUserConfig().harness?.authorGrade);
278
+ const recentStepCounts = authorGrade.grade === 'lite' ? undefined : readRecentStepCountsFailOpen(deps.recentStepCountReader);
279
+ const decomposeSteps = authorGrade.grade === 'lite' ? undefined : deps.decomposeSteps ?? (deps.createDecomposeSteps ?? createGoalAuthorDecomposeSteps)(undefined, {
273
280
  ...(adversarialReview !== undefined ? { adversarialReview, adversarialReviewSource: 'cli' as const } : {}),
274
281
  ...(recentStepCounts !== undefined ? { recentStepCounts } : {}),
275
282
  });
@@ -283,13 +290,34 @@ export async function runGoalAuthorCli(
283
290
  debug.log('goal-author', 'goal-title-forwarded', proseTitle === undefined
284
291
  ? { passed: false }
285
292
  : { passed: true, titleChars: proseTitle.length });
293
+ const gradeDeps = authorGrade.grade === 'lite' || opts.authorGrade ? { authorGrade } : {};
286
294
  const authorDeps: Partial<GoalAuthorDeps> = parentGoalFile && parentQuestionId
287
- ? { parent: { goalFile: parentGoalFile, questionId: parentQuestionId }, parentDocument, clarificationAnswers, decomposeSteps, ...selfResolutionDeps, ...progressDeps, ...launchPreflightDeps, ...(opts.rootIntent !== undefined && { rootIntent: opts.rootIntent }), ...(goalType !== undefined && { goalType }), ...goalTitleDeps }
288
- : { ...(clarificationAnswers && { clarificationAnswers }), decomposeSteps, ...selfResolutionDeps, ...progressDeps, ...launchPreflightDeps, ...(opts.rootIntent !== undefined && { rootIntent: opts.rootIntent }), ...(goalType !== undefined && { goalType }), ...goalTitleDeps };
295
+ ? { parent: { goalFile: parentGoalFile, questionId: parentQuestionId }, parentDocument, clarificationAnswers, ...(decomposeSteps ? { decomposeSteps } : {}), ...gradeDeps, ...selfResolutionDeps, ...progressDeps, ...launchPreflightDeps, ...(opts.rootIntent !== undefined && { rootIntent: opts.rootIntent }), ...(goalType !== undefined && { goalType }), ...goalTitleDeps }
296
+ : { ...(clarificationAnswers && { clarificationAnswers }), ...(decomposeSteps ? { decomposeSteps } : {}), ...gradeDeps, ...selfResolutionDeps, ...progressDeps, ...launchPreflightDeps, ...(opts.rootIntent !== undefined && { rootIntent: opts.rootIntent }), ...(goalType !== undefined && { goalType }), ...goalTitleDeps };
289
297
  const write = deps.write ?? writeAuthoredGoal;
290
298
  const result = opts.groundingCwd === undefined
291
299
  ? await write(ask, opts.cwd, authorDeps, superseded ? { supersedes: superseded } : undefined)
292
300
  : await write(ask, opts.cwd, authorDeps, superseded ? { supersedes: superseded } : undefined, opts.groundingCwd);
301
+ if (opts.selfResolveClarifications) {
302
+ const rework = Boolean(supersededDocument || opts.reauthorFromAnsweredClarification);
303
+ {
304
+ try {
305
+ const resolved = await selfAnswerGoalDocumentClarifications(result.authored.document, {
306
+ path: rework ? 'rework' : 'say-first', ask, resolver: deps.selfResolveClarification ?? defaultGoalAuthorSelfResolve,
307
+ evidence: result.authored.facts
308
+ ? [...(result.authored.facts.persistentEvidence ?? []), ...result.authored.facts.codeFacts, ...result.authored.facts.documentFacts]
309
+ : undefined,
310
+ });
311
+ if (resolved.newlyAnswered > 0) {
312
+ (deps.writeFile ?? writeGoalDocumentAtomic)(result.path, resolved.document);
313
+ result.authored.document = resolved.document;
314
+ }
315
+ } catch (error) {
316
+ // The previous goal file is left intact (atomic replace); implementation proceeds from it with the questions deferred.
317
+ debug.log('goal-author.clarify', 'self-answer-deferred', { reason: error instanceof Error ? error.message : String(error) });
318
+ }
319
+ }
320
+ }
293
321
  try {
294
322
  const recorded = (deps.recordAsk ?? recordGoalAsk)({
295
323
  authorRunId: result.authored.authorRunId,
@@ -18,6 +18,17 @@ function observeGoalAuthor(
18
18
  debug.log(category === 'goal-author' ? 'harness.author' : 'harness.author.clarify', event, data);
19
19
  }
20
20
  import { getUserConfig } from '../user-config.js';
21
+
22
+ export type GoalAuthorGrade = 'full' | 'lite';
23
+ export type GoalAuthorGradeSource = 'flag' | 'config' | 'default';
24
+ export interface GoalAuthorGradeSelection { grade: GoalAuthorGrade; source: GoalAuthorGradeSource }
25
+
26
+ /** The flag is authoritative; malformed or absent configuration keeps the full pipeline. */
27
+ export function resolveGoalAuthorGrade(flag?: GoalAuthorGrade, configured?: unknown): GoalAuthorGradeSelection {
28
+ if (flag !== undefined) return { grade: flag, source: 'flag' };
29
+ if (configured === 'lite' || configured === 'full') return { grade: configured, source: 'config' };
30
+ return { grade: 'full', source: 'default' };
31
+ }
21
32
  import type { ObserveOnlySource } from './observe-only.js';
22
33
  import type { Question } from '../ask-user-question/types.js';
23
34
  import { requestTestScenario as defaultRequestTestScenario, type TestScenarioRequestInput, type TestScenarioRequestResult } from './test-scenario-request.js';
@@ -45,6 +56,7 @@ type GoalEnhancement = Omit<Pick<EnhanceResult, 'original' | 'checklist' | 'verb
45
56
  export interface GoalAuthorDeps {
46
57
  ground: (ask: string, groundingDeps?: GoalAuthorGroundingDeps) => Promise<CodebaseGrounding>;
47
58
  persistentGrounding?: GoalAuthorGroundingDeps;
59
+ authorGrade?: GoalAuthorGradeSelection;
48
60
  enhance: (ask: string, opts?: EnhanceOpts) => Promise<GoalEnhancement>;
49
61
  /** Additive enhancer options supplied by the file-writing entrypoint. */
50
62
  enhanceOpts?: EnhanceOpts;
@@ -4925,6 +4937,17 @@ async function authorGoalWithSupersededRootIntent(
4925
4937
  }
4926
4938
  // ⭐ 이 저작 «한 번»의 id. goalId 보다 «먼저» 있어야 ground·enhance 의 소요를 그 골에 붙일 수 있다.
4927
4939
  const authorRunId = generateGoalId();
4940
+ const authorGrade = deps.authorGrade ?? resolveGoalAuthorGrade(undefined, getUserConfig().harness?.authorGrade);
4941
+ const lite = authorGrade.grade === 'lite';
4942
+ // lite 는 판정선을 남기는 대신 단계를 덜 한다 — 요청에 반증 줄이 하나도 없으면 판정선 없는 골이 나가므로 시작 전에 멈춘다.
4943
+ if (lite && !ask.split(/\r?\n/u).some((line) => /판정선|판정 신호|반증|decision signal/iu.test(line))) {
4944
+ try { observeGoalAuthor('goal-author', 'author-grade-refused', { authorRunId, reason: 'lite-without-falsifiable-signal' }); }
4945
+ catch { /* observation is fail-soft */ }
4946
+ throw new Error('lite authoring needs a falsifiable signal line (판정선/반증) in the ask — add one or use --author-grade full');
4947
+ }
4948
+ const skippedPhases = lite ? ['adversarial-review', 'goal-steps-decomposed', 'persistent-grounding'] : [];
4949
+ try { observeGoalAuthor('goal-author', 'author-grade', { authorRunId, grade: authorGrade.grade, source: authorGrade.source, skippedPhases }); }
4950
+ catch { /* observation is fail-soft */ }
4928
4951
  const authorStartedAt = Date.now();
4929
4952
  const enhanceTokens: GoalAuthorTokens = { inputTokens: null, outputTokens: null };
4930
4953
  const onEnhanceUsage = (usage: LLMUsage): void => {
@@ -4934,18 +4957,20 @@ async function authorGoalWithSupersededRootIntent(
4934
4957
  };
4935
4958
  let facts: CodebaseGrounding | null = null;
4936
4959
  let groundingError = false;
4937
- const persistentGrounding = resolveGoalAuthorPersistentGrounding('persistentGrounding' in deps ? deps.persistentGrounding : undefined);
4938
- const groundStartedAt = startGoalAuthorPhase('ground', authorRunId, deps.onProgress);
4939
- try {
4940
- facts = await deps.ground(ask, persistentGrounding.deps);
4941
- } catch {
4942
- groundingError = true;
4943
- } finally {
4944
- endGoalAuthorPhase('ground', groundStartedAt, authorRunId, deps.onProgress);
4945
- observeGoalAuthorPersistentGroundingResult(
4946
- persistentGrounding.decision,
4947
- goalAuthorPersistentGroundingMetrics(facts, groundingError, authorRunId),
4948
- );
4960
+ if (!lite) {
4961
+ const persistentGrounding = resolveGoalAuthorPersistentGrounding('persistentGrounding' in deps ? deps.persistentGrounding : undefined);
4962
+ const groundStartedAt = startGoalAuthorPhase('ground', authorRunId, deps.onProgress);
4963
+ try {
4964
+ facts = await deps.ground(ask, persistentGrounding.deps);
4965
+ } catch {
4966
+ groundingError = true;
4967
+ } finally {
4968
+ endGoalAuthorPhase('ground', groundStartedAt, authorRunId, deps.onProgress);
4969
+ observeGoalAuthorPersistentGroundingResult(
4970
+ persistentGrounding.decision,
4971
+ goalAuthorPersistentGroundingMetrics(facts, groundingError, authorRunId),
4972
+ );
4973
+ }
4949
4974
  }
4950
4975
 
4951
4976
  const enhanceStartedAt = startGoalAuthorPhase('enhance', authorRunId, deps.onProgress);
@@ -4989,6 +5014,57 @@ async function authorGoalWithSupersededRootIntent(
4989
5014
  }
4990
5015
  enhancement = { ...enhancement, original: ask };
4991
5016
 
5017
+ if (lite) {
5018
+ const goalType = deps.goalType ?? 'implement';
5019
+ const goalId = deps.goalId ?? generateGoalId();
5020
+ const signal = decisionSignalSection(null, ask, enhancement.decisionSignal);
5021
+ const falsifiableSignal = signal.filled > 0 ? signal.lines : [
5022
+ ...signal.lines,
5023
+ ...ask.split(/\r?\n/u).filter((line) => /판정선|판정 신호|반증|decision signal/iu.test(line) && !signal.lines.some((rendered) => rendered.includes(line.trim()))),
5024
+ ];
5025
+ const targetPaths = [...new Set(declaredTargetPaths(ask))];
5026
+ const checklistIds = [...new Set(Array.from(ask.matchAll(/\b[A-Z][A-Z0-9]+-[A-Z0-9]+\b/g), (match) => match[0]))];
5027
+ const askFile = deps.askFile === undefined ? undefined : validateAskFile(deps.askFile);
5028
+ const inheritedRootIntent = deps.parentDocument === undefined ? null : parseRootIntent(deps.parentDocument);
5029
+ const rootIntent = validateRootIntent(deps.supersessionRootIntent ?? inheritedRootIntent ?? deps.rootIntent ?? goalSummary(ask));
5030
+ const document = [
5031
+ deps.goalTitle ?? goalSummary(ask),
5032
+ `- GoalId: ${goalId}`,
5033
+ `- RootIntent: ${rootIntent}`,
5034
+ `- GoalType: ${goalType}`,
5035
+ ...(askFile === undefined ? [] : [`- AskFile: ${askFile}`]),
5036
+ '',
5037
+ '## PROBLEM',
5038
+ `- 왜: ${enhancement.complication ?? goalSummary(ask)}`,
5039
+ '',
5040
+ '## WHAT TO BUILD',
5041
+ `- 무엇: ${enhancement.situation ?? goalSummary(ask)}`,
5042
+ ORIGINAL_ASK_MARKER,
5043
+ fenceFor(ask), ask, fenceFor(ask),
5044
+ '',
5045
+ '## ACCEPTANCE CRITERIA',
5046
+ ...enhancement.checklist.map(requestedCriterionLine),
5047
+ '',
5048
+ '## REQUIRED EVIDENCE',
5049
+ '- [requested] Verify the decision signal and the verbatim ask.',
5050
+ '',
5051
+ ...(goalType === 'implement' ? ['## TRACED PATHS', ...(targetPaths.length ? targetPaths.map((path) => `- ${path}`) : ['- Target paths: not declared in the ask.']), ''] : []),
5052
+ '## SCOPE BOUNDARY',
5053
+ `- 대상 경로: ${targetPaths.length ? targetPaths.join(' · ') : 'not declared'}`,
5054
+ `- 칸 id: ${checklistIds.length ? checklistIds.join(' · ') : 'not declared'}`,
5055
+ '',
5056
+ '## 답하지 못하는 것',
5057
+ '- No persistent grounding was performed in lite authoring.',
5058
+ '',
5059
+ '## 불변식',
5060
+ '- No persistent grounding was performed in lite authoring.',
5061
+ '',
5062
+ '## 판정 신호',
5063
+ ...falsifiableSignal,
5064
+ ].join('\n');
5065
+ return { document, facts: null, grounded: false, authorRunId };
5066
+ }
5067
+
4992
5068
  observeGoalAuthor('goal-author', 'constant-instruction-placement', {
4993
5069
  authorRunId,
4994
5070
  lines: CONSTANT_DOCUMENT_INSTRUCTION_POLICY.length,
@@ -5452,23 +5528,29 @@ async function authorGoalWithSupersededRootIntent(
5452
5528
  assembleCompleted = true;
5453
5529
  endGoalAuthorPhase('assemble', assembleStartedAt, authorRunId, deps.onProgress);
5454
5530
  const lintStartedAt = startGoalAuthorPhase('lint', authorRunId, deps.onProgress);
5531
+ let lintPassed = false;
5455
5532
  try {
5456
5533
  assertRequiredBlocks(document);
5534
+ lintPassed = true;
5457
5535
  } finally {
5458
- endGoalAuthorPhase('lint', lintStartedAt, authorRunId, deps.onProgress);
5536
+ try {
5537
+ endGoalAuthorPhase('lint', lintStartedAt, authorRunId, deps.onProgress);
5538
+ } finally {
5539
+ try {
5540
+ observeGoalAuthor('goal-author', 'summary', {
5541
+ authorRunId,
5542
+ elapsedMs: Date.now() - authorStartedAt,
5543
+ inputTokens: enhanceTokens.inputTokens,
5544
+ outputTokens: enhanceTokens.outputTokens,
5545
+ totalTokens: enhanceTokens.inputTokens === null || enhanceTokens.outputTokens === null
5546
+ ? null : enhanceTokens.inputTokens + enhanceTokens.outputTokens,
5547
+ goalChars: [...document].length,
5548
+ sectionChars: authoredGoalSectionChars(document),
5549
+ ...(!lintPassed ? { outcome: 'lint-failed' } : {}),
5550
+ });
5551
+ } catch { /* observation is fail-soft */ }
5552
+ }
5459
5553
  }
5460
- try {
5461
- observeGoalAuthor('goal-author', 'summary', {
5462
- authorRunId,
5463
- elapsedMs: Date.now() - authorStartedAt,
5464
- inputTokens: enhanceTokens.inputTokens,
5465
- outputTokens: enhanceTokens.outputTokens,
5466
- totalTokens: enhanceTokens.inputTokens === null || enhanceTokens.outputTokens === null
5467
- ? null : enhanceTokens.inputTokens + enhanceTokens.outputTokens,
5468
- goalChars: [...document].length,
5469
- sectionChars: authoredGoalSectionChars(document),
5470
- });
5471
- } catch { /* observation is fail-soft */ }
5472
5554
  return { document, facts, grounded: !groundingError && hasEvidence, authorRunId };
5473
5555
  } finally {
5474
5556
  endAssembleSubphase();
@@ -11,9 +11,13 @@ import {
11
11
  writePendingQuestion,
12
12
  } from '../ask-user-question/pending-questions.js';
13
13
  import { debug } from '../debug/log.js';
14
+ import { writeGoalDocumentAtomic } from './goal-document-write.js';
14
15
  import {
15
16
  applyClarificationReply,
16
17
  parseGoalDocumentClarifications,
18
+ selfAnswerGoalDocumentClarifications,
19
+ type GoalClarificationSelfResolver,
20
+ type GoalClarificationSelfAnswerPath,
17
21
  } from './goal-author-clarification.js';
18
22
  import type { HitlDelivery } from '../hitl/types.js';
19
23
 
@@ -49,6 +53,8 @@ export interface GoalClarificationEscalationInput {
49
53
  resolveOriginDelivery?: (sessionId: string) => HitlDelivery | undefined;
50
54
  /** Non-blocking terminal fallback for a non-TUI delivery with no installed resolver. */
51
55
  fallback?: (message: string) => void;
56
+ selfResolveClarification?: GoalClarificationSelfResolver;
57
+ selfAnswerPath?: GoalClarificationSelfAnswerPath;
52
58
  /** Fail-soft pending persistence for terminal fallbacks; injectable for focused tests. */
53
59
  pendingQuestionPersistence?: {
54
60
  create: typeof createPendingQuestion;
@@ -404,6 +410,7 @@ export async function escalateGoalDocumentClarifications(
404
410
  const dispatchDelivery = delivery ?? 'modal';
405
411
  const recordedDelivery = input.resolvedDelivery ?? dispatchDelivery;
406
412
  let answersWritten = 0;
413
+ let selfAnswered = 0;
407
414
  let questionIds: string[] = [];
408
415
  const observeEscalation = (event: GoalClarificationObservationEvent, data: Record<string, unknown>): void => {
409
416
  writeEscalationObservation(event, { ...data, deliverySource, answersWritten, questionIds });
@@ -430,6 +437,35 @@ export async function escalateGoalDocumentClarifications(
430
437
  return result;
431
438
  }
432
439
 
440
+ if (input.selfAnswerPath) {
441
+ try {
442
+ const resolution = await selfAnswerGoalDocumentClarifications(document, {
443
+ path: input.selfAnswerPath,
444
+ ask: document,
445
+ resolver: input.selfResolveClarification,
446
+ });
447
+ if (resolution.newlyAnswered > 0) {
448
+ writeGoalDocumentAtomic(input.goalFile, resolution.document);
449
+ answersWritten += resolution.newlyAnswered;
450
+ selfAnswered += resolution.newlyAnswered;
451
+ document = resolution.document;
452
+ clarifications = parseGoalDocumentClarifications(document);
453
+ unanswered = clarifications.filter((clarification) => !clarification.answered);
454
+ deliveryIds = mapClarificationDeliveryIds(clarifications);
455
+ questionIds = [...new Set(unanswered.map((clarification) => clarification.questionId))];
456
+ }
457
+ if (unanswered.length === 0) {
458
+ const result = { unanswered: 0, escalated: 0, delivery: recordedDelivery, outcome: 'skipped' as const, answeredBy: 'agent' as const };
459
+ observeEscalation(result.outcome, { goalFile: input.goalFile, ...result, reason: 'self-answered' });
460
+ return result;
461
+ }
462
+ } catch (error) {
463
+ debug.log(GOAL_CLARIFICATION_ESCALATION_CATEGORY, 'self-answer-failed', {
464
+ path: input.selfAnswerPath, reason: error instanceof Error ? error.message : String(error),
465
+ });
466
+ }
467
+ }
468
+
433
469
  const dispatch = input.dispatch ?? dispatchAskUserQuestion;
434
470
  const pendingQuestionPersistence = input.pendingQuestionPersistence ?? {
435
471
  create: createPendingQuestion,
@@ -444,7 +480,7 @@ export async function escalateGoalDocumentClarifications(
444
480
  // ⛔⭐⭐⭐ 여기서부터의 조기 반환·폴백은 이 «누적값»을 쓴다 — 'none' 을 하드코딩하면
445
481
  // 앞 배치가 답했는데 뒤 배치가 취소·실패했을 때 「아무도 안 답했다」는 «거짓»이 된다
446
482
  // (무인 리뷰 R2 must-fix · 실측 형태: 관측이 거짓말한다).
447
- const seenProvenance = { explicit: new Set<'human' | 'agent'>(), unmarkedAnswer: false };
483
+ const seenProvenance = { explicit: new Set<'human' | 'agent'>(selfAnswered > 0 ? ['agent' as const] : []), unmarkedAnswer: false };
448
484
  const aggregate = (): GoalClarificationAnsweredBy => {
449
485
  const { explicit, unmarkedAnswer } = seenProvenance;
450
486
  // ⭐ 표시 없는 답도 «한 출처»로 센다 — legacy 경로는 사람이다(레포 안 리졸버는 이제 전부 명시한다).
@@ -0,0 +1,28 @@
1
+ /** Atomic goal-document replacement for self-answered clarifications (POD-SELF-ANSWER). */
2
+ import { chmodSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
3
+
4
+ export interface GoalDocumentWriteIo {
5
+ writeFileSync: (path: string, data: string, options?: { mode?: number }) => void;
6
+ renameSync: (from: string, to: string) => void;
7
+ rmSync: (path: string, options: { force: boolean }) => void;
8
+ statSync: (path: string) => { mode: number };
9
+ chmodSync: (path: string, mode: number) => void;
10
+ }
11
+
12
+ const realIo: GoalDocumentWriteIo = { writeFileSync, renameSync, rmSync, statSync, chmodSync };
13
+
14
+ /** Replace a goal document atomically (temp file next to it + rename) so a failed write never leaves a torn goal.
15
+ * The existing file's permission bits are kept, so a 0600 goal stays 0600 after replacement. */
16
+ export function writeGoalDocumentAtomic(path: string, document: string, io: GoalDocumentWriteIo = realIo): void {
17
+ let mode: number | undefined;
18
+ try { mode = io.statSync(path).mode & 0o777; } catch { mode = undefined; }
19
+ const temporary = `${path}.self-answer-${process.pid}-${Date.now()}.tmp`;
20
+ try {
21
+ io.writeFileSync(temporary, document, mode === undefined ? undefined : { mode });
22
+ if (mode !== undefined) io.chmodSync(temporary, mode);
23
+ io.renameSync(temporary, path);
24
+ } catch (error) {
25
+ try { io.rmSync(temporary, { force: true }); } catch { /* best effort */ }
26
+ throw error;
27
+ }
28
+ }
@@ -68,6 +68,10 @@ function liveHealRuns(root: string): Set<string> {
68
68
  /** A test process must never start the real heal loop — it spawns external grounding (10-05 load 150 incident). */
69
69
  export async function startHealLoop(file: string, options: HealLoopOptions, env: NodeJS.ProcessEnv = process.env,
70
70
  run: StartHealLoop = async (graph, args) => (await import('../graph-runner/runner.js')).runGraph(graph, args)): Promise<unknown> {
71
+ if (env.ELANOUS_POD_NAME) {
72
+ debug.log('heal.intake', 'skipped-in-pod', { ref: options.input.failureEvent.ref });
73
+ return undefined;
74
+ }
71
75
  if (env.NODE_ENV === 'test' || env.ELANOUS_TEST_HOME) {
72
76
  debug.log('heal.intake', 'loop-start-skipped-test', { runId: options.runId });
73
77
  return undefined;
@@ -156,6 +156,50 @@ export interface HealTriageResult {
156
156
  readonly evidence: readonly string[];
157
157
  }
158
158
 
159
+ /** 수리 한도를 다 쓴 런의 결함 셋. 힐 루프가 이 셋 중 하나만 고른다. */
160
+ export type ReworkCapDefectClass = 'test-defect' | 'goal-defect' | 'code-defect';
161
+
162
+ /** 분류 뒤 힐 루프가 고르는 다음 행동. */
163
+ export type ReworkCapNextAction = 'harvest' | 'relaunch' | 'card';
164
+
165
+ export interface ReworkCapHealInput {
166
+ /** 게이트가 이번 diff 가 들여온 실패 수. 없으면 0. */
167
+ readonly introduced?: readonly string[];
168
+ /** 마지막 리뷰 must-fix. 없으면 빈 목록. */
169
+ readonly mustFix?: readonly string[];
170
+ readonly summary?: string;
171
+ }
172
+
173
+ export interface ReworkCapHealDecision {
174
+ readonly defectClass: ReworkCapDefectClass;
175
+ readonly nextAction: ReworkCapNextAction;
176
+ readonly evidence: readonly string[];
177
+ }
178
+
179
+ const GOAL_DEFECT = /골|goal|acceptance|수용 기준|요구가 모순|스펙|경계:/i;
180
+
181
+ /**
182
+ * 수리 한도 소진 런을 «시험 결함 · 골 결함 · 코드 결함» 중 하나로 가르고
183
+ * 수확·재발사·카드 중 하나를 고른다. 근거는 게이트 introduced 목록과 마지막 리뷰 지적이다.
184
+ * 도입 실패가 있으면 코드 결함(재발사). 리뷰가 골·수용 기준을 짚으면 골 결함(카드).
185
+ * 그 밖(리뷰만 있거나 근거가 비면)은 시험 결함(수확)이다.
186
+ */
187
+ export function classifyReworkCapExhaustion(input: ReworkCapHealInput): ReworkCapHealDecision {
188
+ const introduced = (input.introduced ?? []).map((item) => item.trim()).filter(Boolean);
189
+ const mustFix = (input.mustFix ?? []).map((item) => item.trim()).filter(Boolean);
190
+ const evidence = [
191
+ ...introduced.map((item) => `gate introduced: ${item}`),
192
+ ...mustFix.map((item) => `review must-fix: ${item}`),
193
+ ];
194
+ if (introduced.length > 0) {
195
+ return { defectClass: 'code-defect', nextAction: 'relaunch', evidence };
196
+ }
197
+ if (mustFix.some((item) => GOAL_DEFECT.test(item)) || (input.summary ? GOAL_DEFECT.test(input.summary) : false)) {
198
+ return { defectClass: 'goal-defect', nextAction: 'card', evidence };
199
+ }
200
+ return { defectClass: 'test-defect', nextAction: 'harvest', evidence };
201
+ }
202
+
159
203
  const UNTESTABLE_EXT = new Set(['.md', '.json', '.yaml', '.yml', '.txt']);
160
204
  const ENVIRONMENT_CLAIM = /할당량|자격|기판|quota|credential|substrate/i;
161
205
 
@@ -30,6 +30,8 @@ export type HostRegateDeps = {
30
30
  acquire?: (repoRoot: string) => Promise<() => void>;
31
31
  log?: (event: 'passed' | 'failed' | 'unmeasured' | 'base-raced', data: Record<string, unknown>) => void;
32
32
  freezeRoot?: string;
33
+ /** Test seam for the operational freeze authority; production always uses the host root. */
34
+ prodFreezeRoot?: string;
33
35
  runExposeGate?: typeof runExposeGate;
34
36
  syncMergedChecklist?: typeof import('../release-loop/merged-pr-checklist.js').syncMergedPrChecklist;
35
37
  };
@@ -241,7 +243,7 @@ export async function runHostRegate(input: HostRegateInput, deps: HostRegateDeps
241
243
  // --match-head-commit pins the head. gh has no base pin, so the base was re-read just
242
244
  // above; the seconds between that read and the merge are checked after the fact below.
243
245
  if (input.verifyOnly) return result('passed');
244
- const landing = admitLandingMerge({ prNumber: input.prNumber, headCommit: input.headCommit, repoRoot: input.repoRoot, ...(input.goalFile ? { goalFile: input.goalFile } : {}) }, deps.freezeRoot, {}, input.resumed ? undefined : { prNumber: input.prNumber, repoRoot: input.repoRoot, headCommit: input.headCommit });
246
+ const landing = admitLandingMerge({ prNumber: input.prNumber, headCommit: input.headCommit, repoRoot: input.repoRoot, ...(input.goalFile ? { goalFile: input.goalFile } : {}) }, deps.freezeRoot, {}, input.resumed ? undefined : { prNumber: input.prNumber, repoRoot: input.repoRoot, headCommit: input.headCommit }, { prodFreezeRoot: deps.prodFreezeRoot });
245
247
  if (landing.kind !== 'merge') {
246
248
  debug.log('harness.merge', 'frozen', { pr: input.prNumber, ...(landing.kind === 'held' ? { reason: landing.freeze.reason, until: landing.freeze.until } : { resumedElsewhere: true }) });
247
249
  return { passed: true, failures: [], os: process.platform, status: 'frozen' };