elanous 0.2.14 → 0.2.16

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 (350) 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-6e7e0377c1db0bdc.js → 1307-b46d45b705e8c9ae.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/{9103-7a3ae7f60af3b99f.js → 9103-60fbef33e66f0a46.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/app/approvals/page-79c3ed84baaedd03.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-7b2b4f378354869a.js → page-3cb52e5ea8fc2fa5.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/app/board/page-a424ef80885d1743.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/app/botlab/page-c1e20d7d338713f1.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/app/bots/{page-1512d91c7491ed62.js → page-482c5dbde699947c.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/app/ceo/page-1e962b31d1f11081.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/app/chat/{page-a627db94ec6904a0.js → page-8c2d9526164f5d09.js} +1 -1
  14. package/apps/pwa/out/_next/static/chunks/app/consult/page-ffff6d819fbc6e0f.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/app/control/{page-e6b84ab07d3567d5.js → page-a0e2a6d1bfb52fc5.js} +1 -1
  16. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c53598cfce6156f2.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/app/editor/{page-fed69f9759d248d0.js → page-13a63953f53c6a23.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/app/exec/{page-15374909d8f1aebd.js → page-5d3c8429d04f3831.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/app/field/{page-012a742f81218b01.js → page-3193bdc0bbab047a.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/app/inside/page-76270efaee638f17.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/app/intake/{page-99effd9d893a43dc.js → page-6107ca8ddd5e3bdd.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/app/{layout-938de57ae0315e46.js → layout-dce686e582c23937.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/app/live/page-d3d53b146416e422.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/app/loops/{page-160089123a40dd91.js → page-1a61c7ca1ceb3ae7.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/app/market/{page-629e1ede482ec6eb.js → page-51f811fa119308b6.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-dacff46049e1557e.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/app/morning/{page-27e99b4e54a849d4.js → page-4167348049166852.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/app/not-found-de52e8fdf9095f7a.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/app/observatory/page-36a7d994f4ca0299.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-32cde713be47cddb.js → page-ca3952cd78a83ca2.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-e7e10cd3386222e5.js → page-5b042736aa113756.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-acb749f1e432bcf3.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/app/outputs/page-cd78862707999911.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/app/page-54b9ef8afe6278fd.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/app/reflection/{page-e64caff084f7ce21.js → page-1ebfe049c640e171.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-db07eaffba0df7e3.js → page-57924393e3e4e539.js} +1 -1
  37. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9e0ce6c8129fa641.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-31fa1ce4c4aff9ae.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/app/settings/{page-86f91034bd5cabe5.js → page-0f5cd57ca928f42b.js} +1 -1
  40. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-abe8e3b74bea1ffc.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/app/setup/page-4364ef9f4e7c7f0f.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/app/share/{page-ce4d8a1215ce53a3.js → page-d28573d6792b4275.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/app/showroom/{page-58043db78ba519ae.js → page-59f03fda76c03d22.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/app/tasks/{page-357750dfb91bf960.js → page-d751de5f8062ff5e.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/app/term/{page-274703bc41b71333.js → page-fe1759f94003b32b.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/app/today/page-d64c984e855c8c68.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/app/trace/page-86914b0dee8ab7f8.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/vault/{page-3b7e821dc492bdfd.js → page-9afdee66b820c76e.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d4aef67abf264874.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/workflows/{page-f8da5dc6f3752276.js → page-1ea64acadd704ace.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-2f810b18d89ecba6.js → page-3544f154c87b43ee.js} +1 -1
  52. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-30c2073bfc21c004.js +1 -0
  53. package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +1 -0
  54. package/apps/pwa/out/_next/static/css/{04dabcbcc4bfa6db.css → 085673d826b98b62.css} +1 -1
  55. package/apps/pwa/out/_next/static/rv9cierV0jSOvDBm1g0XB/_buildManifest.js +1 -0
  56. package/apps/pwa/out/approvals/index.html +1 -1
  57. package/apps/pwa/out/approvals/index.txt +15 -15
  58. package/apps/pwa/out/autopilot/index.html +1 -1
  59. package/apps/pwa/out/autopilot/index.txt +15 -15
  60. package/apps/pwa/out/board/index.html +1 -1
  61. package/apps/pwa/out/board/index.txt +15 -15
  62. package/apps/pwa/out/botlab/index.html +1 -1
  63. package/apps/pwa/out/botlab/index.txt +15 -15
  64. package/apps/pwa/out/bots/index.html +1 -1
  65. package/apps/pwa/out/bots/index.txt +15 -15
  66. package/apps/pwa/out/ceo/index.html +1 -0
  67. package/apps/pwa/out/ceo/index.txt +33 -0
  68. package/apps/pwa/out/chat/index.html +1 -1
  69. package/apps/pwa/out/chat/index.txt +15 -15
  70. package/apps/pwa/out/consult/index.html +1 -1
  71. package/apps/pwa/out/consult/index.txt +15 -15
  72. package/apps/pwa/out/control/index.html +1 -1
  73. package/apps/pwa/out/control/index.txt +15 -15
  74. package/apps/pwa/out/design-check/index.html +1 -1
  75. package/apps/pwa/out/design-check/index.txt +15 -15
  76. package/apps/pwa/out/editor/index.html +1 -1
  77. package/apps/pwa/out/editor/index.txt +15 -15
  78. package/apps/pwa/out/exec/index.html +1 -1
  79. package/apps/pwa/out/exec/index.txt +15 -15
  80. package/apps/pwa/out/field/index.html +1 -1
  81. package/apps/pwa/out/field/index.txt +15 -15
  82. package/apps/pwa/out/healthz +1 -1
  83. package/apps/pwa/out/index.html +1 -1
  84. package/apps/pwa/out/index.txt +15 -15
  85. package/apps/pwa/out/inside/index.html +1 -1
  86. package/apps/pwa/out/inside/index.txt +15 -15
  87. package/apps/pwa/out/intake/index.html +1 -1
  88. package/apps/pwa/out/intake/index.txt +15 -15
  89. package/apps/pwa/out/live/index.html +1 -1
  90. package/apps/pwa/out/live/index.txt +15 -15
  91. package/apps/pwa/out/loops/index.html +1 -1
  92. package/apps/pwa/out/loops/index.txt +15 -15
  93. package/apps/pwa/out/market/index.html +1 -1
  94. package/apps/pwa/out/market/index.txt +15 -15
  95. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  96. package/apps/pwa/out/missions/placeholder/index.txt +15 -15
  97. package/apps/pwa/out/morning/index.html +1 -1
  98. package/apps/pwa/out/morning/index.txt +15 -15
  99. package/apps/pwa/out/observatory/index.html +1 -1
  100. package/apps/pwa/out/observatory/index.txt +15 -15
  101. package/apps/pwa/out/ops/checklist/index.html +1 -1
  102. package/apps/pwa/out/ops/checklist/index.txt +15 -15
  103. package/apps/pwa/out/ops/release/index.html +1 -1
  104. package/apps/pwa/out/ops/release/index.txt +15 -15
  105. package/apps/pwa/out/ops/seats/index.html +1 -1
  106. package/apps/pwa/out/ops/seats/index.txt +15 -15
  107. package/apps/pwa/out/outputs/index.html +1 -1
  108. package/apps/pwa/out/outputs/index.txt +15 -15
  109. package/apps/pwa/out/reflection/index.html +1 -1
  110. package/apps/pwa/out/reflection/index.txt +16 -16
  111. package/apps/pwa/out/scheduler/index.html +1 -1
  112. package/apps/pwa/out/scheduler/index.txt +15 -15
  113. package/apps/pwa/out/sessions/index.html +1 -1
  114. package/apps/pwa/out/sessions/index.txt +15 -15
  115. package/apps/pwa/out/settings/devices/index.html +1 -1
  116. package/apps/pwa/out/settings/devices/index.txt +15 -15
  117. package/apps/pwa/out/settings/index.html +1 -1
  118. package/apps/pwa/out/settings/index.txt +15 -15
  119. package/apps/pwa/out/setup/done/index.html +1 -1
  120. package/apps/pwa/out/setup/done/index.txt +15 -15
  121. package/apps/pwa/out/setup/index.html +1 -1
  122. package/apps/pwa/out/setup/index.txt +15 -15
  123. package/apps/pwa/out/share/index.html +1 -1
  124. package/apps/pwa/out/share/index.txt +15 -15
  125. package/apps/pwa/out/showroom/index.html +1 -1
  126. package/apps/pwa/out/showroom/index.txt +15 -15
  127. package/apps/pwa/out/tasks/index.html +1 -1
  128. package/apps/pwa/out/tasks/index.txt +15 -15
  129. package/apps/pwa/out/term/index.html +1 -1
  130. package/apps/pwa/out/term/index.txt +15 -15
  131. package/apps/pwa/out/today/index.html +1 -1
  132. package/apps/pwa/out/today/index.txt +15 -15
  133. package/apps/pwa/out/trace/index.html +1 -1
  134. package/apps/pwa/out/trace/index.txt +15 -15
  135. package/apps/pwa/out/vault/index.html +1 -1
  136. package/apps/pwa/out/vault/index.txt +15 -15
  137. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  138. package/apps/pwa/out/workflows/chat-ui/index.txt +15 -15
  139. package/apps/pwa/out/workflows/index.html +1 -1
  140. package/apps/pwa/out/workflows/index.txt +15 -15
  141. package/apps/pwa/out/workspace/index.html +1 -1
  142. package/apps/pwa/out/workspace/index.txt +15 -15
  143. package/apps/pwa/out/worktrees/index.html +1 -1
  144. package/apps/pwa/out/worktrees/index.txt +15 -15
  145. package/graphs/doc-gen/doc-gen.yaml +24 -0
  146. package/graphs/doc-gen/recipes.yaml +3 -0
  147. package/graphs/heal/heal-loop.yaml +1 -1
  148. package/graphs/implement-loop.yaml +1 -1
  149. package/graphs/orchestrator/orchestrator.yaml +7 -0
  150. package/graphs/orchestrator/recipes.yaml +3 -0
  151. package/graphs/release/recipes.yaml +3 -0
  152. package/graphs/release/release-loop.yaml +4 -2
  153. package/graphs/steward/recipes.yaml +2 -1
  154. package/package.json +1 -1
  155. package/scripts/brand/check.ts +7 -5
  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 +82 -31
  159. package/scripts/docs/doc-rot.ts +164 -0
  160. package/scripts/docs/generate-graph-anatomy.ts +437 -0
  161. package/scripts/docs-cli-check.ts +4 -4
  162. package/scripts/expose-rubric-suggest.ts +18 -12
  163. package/scripts/goals/goal-census.ts +343 -0
  164. package/scripts/lecture-note/node.ts +31 -11
  165. package/scripts/lessons/handbook-page.ts +30 -3
  166. package/scripts/marketing/generate-ax-brief.ts +140 -0
  167. package/scripts/marketing/generate-feature-map.ts +118 -0
  168. package/scripts/measure/author-section-contribution.ts +84 -0
  169. package/scripts/release-loop/checklist-gate-node.ts +53 -14
  170. package/scripts/release-loop/cut-branch.ts +43 -13
  171. package/scripts/release-loop/gate-node.ts +82 -14
  172. package/scripts/release-loop/vault-note-node.ts +257 -8
  173. package/scripts/release-story/draft.ts +57 -9
  174. package/scripts/rhythm/daily.ts +263 -76
  175. package/scripts/rhythm/monthly.ts +97 -0
  176. package/scripts/rhythm/weekly.ts +30 -9
  177. package/scripts/smart-merge/resync-shadow.ts +147 -0
  178. package/src/acp/client.ts +17 -2
  179. package/src/agent-env/profile.ts +161 -0
  180. package/src/agent-mission/driver.ts +51 -1
  181. package/src/agent-mission/supervisor-metrics-cli.ts +40 -0
  182. package/src/agent-mission/supervisor-metrics.ts +218 -0
  183. package/src/agent-substrate/pr-reviewer.ts +2 -0
  184. package/src/ask-user-question/pending-questions.ts +5 -0
  185. package/src/auth/github-app-token.ts +112 -13
  186. package/src/autopilot/build/llm-conflict-merge.ts +32 -6
  187. package/src/autopilot/track-agent-shadow.ts +2 -1
  188. package/src/briefing/brief-items.ts +276 -0
  189. package/src/budget/usage-outcomes.ts +204 -0
  190. package/src/claims/claims-render.ts +14 -5
  191. package/src/cli/agent-env-cli.ts +21 -0
  192. package/src/cli/brief-cli.ts +73 -0
  193. package/src/cli/decisions-cli.ts +9 -0
  194. package/src/cli/doctor-cli.ts +23 -1
  195. package/src/cli/doctor-node-modules.ts +147 -0
  196. package/src/cli/intake-cli.ts +46 -17
  197. package/src/cli/know-cli.ts +20 -0
  198. package/src/cli/logs-cli.ts +43 -1
  199. package/src/cli/pod-cli.ts +2 -0
  200. package/src/cli/pr-cli.ts +80 -12
  201. package/src/cli/release-cli.ts +66 -29
  202. package/src/cli/seat-requests-cli.ts +52 -0
  203. package/src/cli/self-update.ts +200 -1
  204. package/src/cli/usage-cli.ts +26 -0
  205. package/src/context-bus/context-now-public.ts +16 -6
  206. package/src/context-bus/context-now.ts +3 -1
  207. package/src/context-bus/coord-events.ts +6 -4
  208. package/src/decisions/decision-cards.ts +33 -7
  209. package/src/decisions/proact-meter.ts +286 -0
  210. package/src/decisions/proact1-lite.ts +86 -0
  211. package/src/decisions/web-push-decision-cards.ts +1 -1
  212. package/src/discord-self-message.ts +9 -0
  213. package/src/domains/alert-audit.ts +271 -0
  214. package/src/domains/core-tools.ts +4 -3
  215. package/src/domains/ops-facts-tool.ts +31 -1
  216. package/src/flow-loop/split.ts +24 -0
  217. package/src/harness/harness-cli-command.ts +147 -17
  218. package/src/harness/harness-incidents.ts +2 -0
  219. package/src/harness/harness-pod-dispatch.ts +67 -8
  220. package/src/harness/harness-queue.ts +380 -50
  221. package/src/harness/harness-seams.ts +13 -3
  222. package/src/harness/helper-repair.ts +218 -0
  223. package/src/harness/helper-scan.ts +27 -4
  224. package/src/harness/launch-stamp.ts +236 -0
  225. package/src/harness/ledger-write-guard-child.fixture.ts +12 -0
  226. package/src/harness/ledger-write-guard.ts +35 -0
  227. package/src/harness/nested-elanous-policy.ts +114 -0
  228. package/src/harness/pod-memory-policy.ts +15 -0
  229. package/src/harness/repository-name.ts +55 -0
  230. package/src/hq/fence-audit.ts +90 -0
  231. package/src/hq/hq.ts +70 -6
  232. package/src/hq/lease.ts +9 -7
  233. package/src/hq/move-plan.ts +126 -0
  234. package/src/hq/promote.ts +31 -0
  235. package/src/hq/transfer.ts +185 -0
  236. package/src/index.ts +189 -13
  237. package/src/intake-plane/check.ts +63 -0
  238. package/src/intake-plane/digest.ts +65 -21
  239. package/src/intake-plane/front-classifier.ts +6 -0
  240. package/src/intake-plane/items.ts +3 -2
  241. package/src/intake-plane/lens.ts +177 -0
  242. package/src/intake-plane/route.ts +145 -1
  243. package/src/knowledge/know-find.ts +105 -0
  244. package/src/llm.ts +75 -19
  245. package/src/loops/budget.ts +36 -5
  246. package/src/loops/checker.ts +2 -2
  247. package/src/loops/orchestrator/author-depth.ts +65 -9
  248. package/src/loops/orchestrator/author-input-check.ts +8 -3
  249. package/src/loops/orchestrator/author-ledger.ts +3 -1
  250. package/src/loops/orchestrator/finish-rate.ts +14 -3
  251. package/src/loops/orchestrator/seat-share.ts +56 -0
  252. package/src/loops/orchestrator/tick.ts +107 -29
  253. package/src/loops/orchestrator/traffic.ts +117 -11
  254. package/src/loops/registry.ts +142 -61
  255. package/src/maturity/bot-slash-catalog.ts +11 -2
  256. package/src/maturity/feature-maturity.ts +4 -3
  257. package/src/maturity/tui-slash-availability.ts +40 -0
  258. package/src/mss/logging/log-store.ts +35 -4
  259. package/src/nexus/api/http-server.ts +28 -14
  260. package/src/nexus/api/loop-edges.ts +173 -0
  261. package/src/nexus/api/schedules-read.ts +13 -0
  262. package/src/nexus/api/seat-requests.ts +79 -56
  263. package/src/oauth/overload-failover-launch.ts +75 -0
  264. package/src/oauth/overload-failover.ts +137 -0
  265. package/src/prompt-enhance/enhance.ts +6 -1
  266. package/src/release-loop/auto-start.ts +6 -3
  267. package/src/release-loop/checklist.ts +19 -5
  268. package/src/release-loop/feature-store.ts +59 -31
  269. package/src/release-loop/merged-pr-checklist.ts +125 -0
  270. package/src/release-loop/placement.ts +98 -29
  271. package/src/seat-dispatch/seat-ask.ts +33 -6
  272. package/src/seat-dispatch/seat-request-eligibility.ts +19 -0
  273. package/src/seat-dispatch/seat-request-ledger.ts +133 -0
  274. package/src/seat-loop/seat-loop.ts +215 -12
  275. package/src/self-dev/ask-launch-flow.ts +22 -1
  276. package/src/self-dev/authored-goal-trace.ts +64 -0
  277. package/src/self-dev/dev-cli.ts +19 -1
  278. package/src/self-dev/dev-pipeline.ts +14 -9
  279. package/src/self-dev/draft-sweep.ts +90 -10
  280. package/src/self-dev/draft-triage-rules.ts +25 -8
  281. package/src/self-dev/entrance-registry.ts +10 -6
  282. package/src/self-dev/old-door.ts +73 -0
  283. package/src/self-dev/orchestrate.ts +15 -1
  284. package/src/self-dev/review-provider-fallback.ts +6 -1
  285. package/src/self-dev/run-supervisor.ts +49 -2
  286. package/src/self-implement/app-api-budget.ts +166 -0
  287. package/src/self-implement/budget-gate.ts +7 -5
  288. package/src/self-implement/follow-up-goals.ts +289 -0
  289. package/src/self-implement/frozen-merges.ts +3 -2
  290. package/src/self-implement/goal-author.ts +50 -6
  291. package/src/self-implement/goal-clarification-escalation.ts +5 -0
  292. package/src/self-implement/heal-intake.ts +120 -2
  293. package/src/self-implement/heal-triage.ts +44 -0
  294. package/src/self-implement/host-regate.ts +9 -2
  295. package/src/self-implement/l8-merge-queue.ts +132 -0
  296. package/src/self-implement/orchestrator.ts +325 -47
  297. package/src/self-implement/pipeline-shape.ts +1 -1
  298. package/src/self-implement/revert-guard.ts +42 -7
  299. package/src/self-implement/run-ledger.ts +6 -0
  300. package/src/self-implement/run-status-mapping.ts +2 -0
  301. package/src/self-implement/seams.ts +45 -16
  302. package/src/self-implement/self-implement-cli.ts +1 -0
  303. package/src/self-implement/speed-claims.ts +338 -0
  304. package/src/session-runtime/index.ts +2 -0
  305. package/src/session-runtime/retry-api.ts +87 -0
  306. package/src/session-runtime/retry-policy.ts +107 -6
  307. package/src/steward/triage.ts +74 -3
  308. package/src/steward/working-backwards.ts +20 -2
  309. package/src/task-cards/card-cli.ts +25 -0
  310. package/src/task-cards/card-store.ts +5 -3
  311. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +63 -48
  312. package/src/task-orchestrator/surfaces/pod-command-job.ts +84 -9
  313. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +48 -0
  314. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +4 -3
  315. package/src/task-orchestrator/surfaces/pod-ledger-prod-sink.ts +75 -0
  316. package/src/task-orchestrator/surfaces/pod-pool.ts +70 -9
  317. package/src/task-orchestrator/surfaces/pod-source-receive.ts +37 -1
  318. package/src/task-orchestrator/surfaces/self-implement-pod.ts +166 -46
  319. package/src/task-orchestrator/surfaces/self-implement.ts +7 -1
  320. package/src/telegram-commands.ts +5 -0
  321. package/src/telegram.ts +72 -4
  322. package/src/user-config.ts +64 -7
  323. package/src/version/packed-revision.json +1 -1
  324. package/src/workflow-runtime/nodes/bash.ts +9 -1
  325. package/apps/pwa/out/_next/static/chunks/4562-071d8bac44a01069.js +0 -1
  326. package/apps/pwa/out/_next/static/chunks/5977-2df489622a52a33a.js +0 -1
  327. package/apps/pwa/out/_next/static/chunks/app/approvals/page-74383f890f075511.js +0 -1
  328. package/apps/pwa/out/_next/static/chunks/app/board/page-c496bb16da85385f.js +0 -1
  329. package/apps/pwa/out/_next/static/chunks/app/botlab/page-1abfe3aec3be6bdc.js +0 -1
  330. package/apps/pwa/out/_next/static/chunks/app/consult/page-fb260b9283dbf646.js +0 -1
  331. package/apps/pwa/out/_next/static/chunks/app/design-check/page-61ec1d2e92bdd50a.js +0 -1
  332. package/apps/pwa/out/_next/static/chunks/app/inside/page-fd7e200d4d83fbd7.js +0 -1
  333. package/apps/pwa/out/_next/static/chunks/app/live/page-d47266766766d227.js +0 -1
  334. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2ce5471926761fdd.js +0 -1
  335. package/apps/pwa/out/_next/static/chunks/app/not-found-e995d30f6800b6bf.js +0 -1
  336. package/apps/pwa/out/_next/static/chunks/app/observatory/page-39f89c53038a51d4.js +0 -1
  337. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-5a753bb4ec0cc511.js +0 -1
  338. package/apps/pwa/out/_next/static/chunks/app/outputs/page-04250f0e2c0d03df.js +0 -1
  339. package/apps/pwa/out/_next/static/chunks/app/page-341480ed8e3c1ea8.js +0 -1
  340. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8ac8d71c2adf9c8a.js +0 -1
  341. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e1e47d8d940aba3d.js +0 -1
  342. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-94dc383d3d54db1a.js +0 -1
  343. package/apps/pwa/out/_next/static/chunks/app/setup/page-b3759cc14da80908.js +0 -1
  344. package/apps/pwa/out/_next/static/chunks/app/today/page-194dce4a83143fce.js +0 -1
  345. package/apps/pwa/out/_next/static/chunks/app/trace/page-35bdeae2e2c17147.js +0 -1
  346. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-16bef3da05a900c3.js +0 -1
  347. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-134c1bc762aee62c.js +0 -1
  348. package/apps/pwa/out/_next/static/css/2e33713c444d5b39.css +0 -1
  349. package/apps/pwa/out/_next/static/x6mjI6vqOkVVu0jFuDkz1/_buildManifest.js +0 -1
  350. /package/apps/pwa/out/_next/static/{x6mjI6vqOkVVu0jFuDkz1 → rv9cierV0jSOvDBm1g0XB}/_ssgManifest.js +0 -0
@@ -21,8 +21,9 @@ import { resolveChildLlmEffort, resolveImplementationChildModel } from '../self-
21
21
  import { resolveHarnessTarget } from '../self-implement/harness-target-options.js';
22
22
  import { queryRunningRuns } from '../self-implement/running-runs.js';
23
23
  import { DevPipelineError } from '../self-dev/dev-pipeline.js';
24
- import { runDraftSweep, type DraftSweepAdapters, type DraftSweepResult, type SweepDraft, type SweepMergedPr } from '../self-dev/draft-sweep.js';
24
+ import { runDraftSweep, sweepFailureReason, type DraftSweepAdapters, type DraftSweepResult, type SweepDraft, type SweepMergedPr, type SweepReviewGate } from '../self-dev/draft-sweep.js';
25
25
  import { debug } from '../debug/log.js';
26
+ import { decideNestedElanousLaunch, readNestedElanousDepth } from './nested-elanous-policy.js';
26
27
  import { dispatchTask, type DispatchTaskInput, type DispatchTaskDeps } from '../execution-loop/dispatch-task.js';
27
28
  import { launchRequestId, preLaunchGate, type PreLaunchGateDeps } from '../execution-loop/launch-gate.js';
28
29
  import { PR_LABELS } from '../github/pr-labels.js';
@@ -30,8 +31,10 @@ import { CODEX_PROVIDER, GROK_PROVIDER, decideBudget, decideLaunchBudget, readBu
30
31
  import { DEFAULT_FALLBACK_CHAIN } from '../oauth/fallback-chain.js';
31
32
  import { installDeliverableVerifyCliCommand, type InstallDeliverableVerifyCliDeps } from './deliverable-verify-cli.js';
32
33
  import { getUserConfig } from '../user-config.js';
34
+ import { resolveRepositoryName } from './repository-name.js';
33
35
  import { installHarnessCliSinkHook } from './harness-cli-sink.js';
34
36
  import { addHarnessQueue, listHarnessQueue, queueSeatForCwd, reconcileHarnessQueue, removeHarnessQueue, tickHarnessQueue, type HarnessQueueDeps, type QueueSeat } from './harness-queue.js';
37
+ import { parseDoorSince, queryLaunchDoors, renderLaunchDoors, type DoorTable } from './launch-stamp.js';
35
38
  import { resolveHarnessSubstrate, type ResolvedHarnessSubstrate } from './harness-substrate-default.js';
36
39
  import { runHarnessPlanRfc } from './harness-plan-rfc.js';
37
40
  import { classifyGarbage, isGarbageProcessTarget, type GarbageProcess } from './process-garbage.js';
@@ -108,6 +111,8 @@ export interface HarnessAskSayOptions {
108
111
  supervisorSource?: HarnessSupervisorSource;
109
112
  goalType?: GoalType;
110
113
  correlation?: string;
114
+ /** Depth 0 only. At depth >= 1 this flag is ignored and the launch stays refused. */
115
+ nestedElanous?: 'allow';
111
116
  }
112
117
 
113
118
  export interface ResolvedHarnessSupervisor {
@@ -172,7 +177,8 @@ function registerHarnessCommonOptions(command: Command): Command {
172
177
  .option('--merge-by-host', 'Pod: merge-ready 까지 실행하고 병합은 발사 호스트가 재게이트')
173
178
  .option('--observe-only', 'elanous: child boot부터 SelfImplement 호출을 기록만 한다')
174
179
  .addOption(new Option('--no-supervise', 'self: supervisor 재개를 끔').hideHelp())
175
- .option('--dry-run', '변경 없이 발사 계획만 출력');
180
+ .option('--dry-run', '변경 없이 발사 계획만 출력')
181
+ .addOption(new Option('--nested-elanous <policy>', '깊이 0만: 중첩 elanous 발사를 허용(allow). 깊이 1 이상은 무시되고 거부가 유지된다').choices(['allow']));
176
182
  }
177
183
 
178
184
  type HarnessDryRunOpts = { dryRun?: boolean };
@@ -297,9 +303,33 @@ function normalizeHarnessCommonOptions(opts: HarnessAskSayOptions): HarnessAskSa
297
303
  ...(opts.observeOnly ? { observeOnly: true } : {}),
298
304
  ...(opts.goalType !== undefined ? { goalType: opts.goalType } : {}),
299
305
  ...resolveHarnessSupervisor(opts),
306
+ ...resolveNestedElanousOption(opts),
300
307
  };
301
308
  }
302
309
 
310
+ export class NestedElanousRefused extends Error {
311
+ constructor(readonly depth: number) {
312
+ super(`nested elanous refused (allow-ignored, depth ${depth})`);
313
+ this.name = 'NestedElanousRefused';
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Depth 0 may keep `--nested-elanous allow`.
319
+ * Depth >= 1 cannot flip the refusal: the flag is ignored, logged, and the launch stops.
320
+ * No flag means an ordinary launch — unset depth is 0 and nothing is refused here.
321
+ */
322
+ export function resolveNestedElanousOption(
323
+ opts: Pick<HarnessAskSayOptions, 'nestedElanous'>,
324
+ env: Record<string, string | undefined> = process.env,
325
+ ): { nestedElanous?: 'allow' } {
326
+ if (opts.nestedElanous !== 'allow') return {};
327
+ const decision = decideNestedElanousLaunch({ depth: readNestedElanousDepth(env), allow: true });
328
+ if (decision.reason === 'allow-ignored') throw new NestedElanousRefused(decision.depth);
329
+ if (!decision.allowed) return {};
330
+ return { nestedElanous: 'allow' };
331
+ }
332
+
303
333
  function normalizeHarnessAskSayOptions(opts: HarnessAskSayChildLlmOptions): HarnessAskSayChildLlmOptions {
304
334
  return {
305
335
  ...normalizeHarnessCommonOptions(opts),
@@ -333,7 +363,7 @@ function assertHarnessChildLlmModel(opts: HarnessAskSayChildLlmOptions): void {
333
363
  }
334
364
 
335
365
  /** Shared post-parse gate: validate child model before any ask/say early return (including `--dry-run`). */
336
- type HarnessSubstrateOpts = { substrate?: 'local' | 'pod'; podPool?: string; podMemory?: string; after?: string; autoMerge?: boolean; base?: string; json?: boolean; target?: string; source?: string; seat?: QueueSeat };
366
+ type HarnessSubstrateOpts = { substrate?: 'local' | 'pod'; podPool?: string; podMemory?: 'lite' | 'standard' | 'high'; after?: string; autoMerge?: boolean; base?: string; json?: boolean; target?: string; source?: string; seat?: QueueSeat };
337
367
  function resolveLaunchSubstrate(opts: HarnessSubstrateOpts): ResolvedHarnessSubstrate {
338
368
  const resolved = resolveHarnessSubstrate({ flag: opts, config: getUserConfig(), env: process.env });
339
369
  debug.log('harness.substrate', 'resolved', resolved);
@@ -552,9 +582,23 @@ function hasHarnessPodJobApplied(runId: string | undefined, output: string): boo
552
582
  } finally { store.close(); }
553
583
  }
554
584
 
585
+ /** 10-05 PODPROVIDER — say which child provider a local run will use (an unnamed choice follows config). */
586
+ function announceLocalChildProvider(opts: unknown): void {
587
+ const child = opts as HarnessAskSayChildLlmOptions;
588
+ if (!child.childLlmProvider?.trim()) return;
589
+ console.error(`child provider 요청 = ${child.childLlmProvider.trim()}${child.childLlmModel?.trim() ? `/${child.childLlmModel.trim()}` : ''} (local)`);
590
+ }
591
+
592
+ /** `harness.authorOnPod` — 명시 true 만 켠다. 읽기 실패는 끔(호스트 저작)으로 둔다. */
593
+ function harnessAuthorOnPod(): boolean {
594
+ try { return getUserConfig().harness?.authorOnPod === true; }
595
+ catch { return false; }
596
+ }
597
+
555
598
  /** ⭐ 런 계약의 실행 칸 = pod — 호스트는 그래프를 안 돌리고 Pod 로 보낸다(harness-pod-dispatch.ts). */
556
599
  async function onPod(opts: unknown, entrance: 'cli-harness-ask' | 'cli-harness-say', input: string, pool: string,
557
- recordDispatch: (input: DispatchTaskInput, deps?: DispatchTaskDeps) => ReturnType<typeof dispatchTask> = dispatchTask): Promise<void> {
600
+ recordDispatch: (input: DispatchTaskInput, deps?: DispatchTaskDeps) => ReturnType<typeof dispatchTask> = dispatchTask,
601
+ authorOnPod = false): Promise<void> {
558
602
  const o = opts as HarnessSubstrateOpts;
559
603
  if (o.target !== undefined) {
560
604
  debug.log('harness.pod', 'target-refused', { target: o.target });
@@ -588,7 +632,13 @@ async function onPod(opts: unknown, entrance: 'cli-harness-ask' | 'cli-harness-s
588
632
  const { dispatchHarnessOnPod } = await import('./harness-pod-dispatch.js');
589
633
  let output = '';
590
634
  let runId: string | undefined;
591
- const status = await dispatchHarnessOnPod({ entrance, input, podPool: pool, ...(dispatchRecorded ? { dispatchRecorded: true } : {}), ...(o.podMemory ? { podMemory: o.podMemory } : {}), ...(o.after ? { after: o.after } : {}), ...(o.autoMerge === false ? { autoMerge: false } : {}), ...(o.base ? { base: o.base } : {}), ...(o.json ? { json: true } : {}), ...(o.source ? { source: o.source } : {}), ...(o.seat ? { seat: o.seat } : {}) },
635
+ const child = opts as HarnessAskSayChildLlmOptions;
636
+ // 10-05 PODPROVIDER: say which child provider the Pod will use when the launch named one.
637
+ if (child.childLlmProvider?.trim()) console.error(`child provider 요청 = ${child.childLlmProvider.trim()}${child.childLlmModel?.trim() ? `/${child.childLlmModel.trim()}` : ''} (pod · 자격 없으면 발사 전 거부)`);
638
+ const status = await dispatchHarnessOnPod({ entrance, input, podPool: pool, ...(authorOnPod && entrance === 'cli-harness-say' ? { authorOnPod: true } : {}),
639
+ ...(child.childLlmProvider?.trim() ? { childLlmProvider: child.childLlmProvider.trim() } : {}),
640
+ ...(child.childLlmModel?.trim() ? { childLlmModel: child.childLlmModel.trim() } : {}),
641
+ ...(child.childLlmEffort?.trim() ? { childLlmEffort: child.childLlmEffort.trim() } : {}), ...(dispatchRecorded ? { dispatchRecorded: true } : {}), ...(o.podMemory ? { podMemory: o.podMemory } : {}), ...((opts as HarnessAskSayChildLlmOptions).goalType ? { goalType: (opts as HarnessAskSayChildLlmOptions).goalType } : {}), ...(o.after ? { after: o.after } : {}), ...(o.autoMerge === false ? { autoMerge: false } : {}), ...(o.base ? { base: o.base } : {}), ...(o.json ? { json: true } : {}), ...(o.source ? { source: o.source } : {}), ...(o.seat ? { seat: o.seat } : {}) },
592
642
  { onOutput: (text) => {
593
643
  runId ??= harnessPodRunId(output + text);
594
644
  output = (output + text).slice(-16_000);
@@ -682,7 +732,13 @@ async function dispatchHarnessAskSay(
682
732
  const podSeat = resolved.substrate === 'pod' && ['OP', 'TC', 'MK', 'UX'].includes(inheritedSeat ?? '')
683
733
  ? inheritedSeat as QueueSeat : undefined;
684
734
  const stampedSeat = resolved.substrate === 'pod' ? opts.seat ?? queueSeat ?? podSeat ?? assigned : assigned;
685
- const stampedOpts = stampedSeat ? { ...opts, seat: stampedSeat } : opts;
735
+ // Depth >= 1 cannot re-allow. Drop the flag here so the launch sees the refusal, not the raw argv.
736
+ const nested = resolveNestedElanousOption(opts);
737
+ const stampedOpts = {
738
+ ...opts,
739
+ ...(stampedSeat ? { seat: stampedSeat } : {}),
740
+ ...(nested.nestedElanous ? { nestedElanous: nested.nestedElanous } : { nestedElanous: undefined }),
741
+ };
686
742
  const launch = async () => {
687
743
  const previous = process.env.ELANOUS_HARNESS_SEAT;
688
744
  if (stampedSeat) process.env.ELANOUS_HARNESS_SEAT = stampedSeat;
@@ -1631,6 +1687,12 @@ export async function runHarnessBudget(opts: { json?: boolean } = {}, io: {
1631
1687
 
1632
1688
  const DRAFT_SWEEP_REPOSITORY = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
1633
1689
 
1690
+ /** A review body still names a must-fix. «must-fix 0» and «must-fix: 0» are a cleared list, not a remaining one. */
1691
+ function mustFixRemains(text: string): boolean {
1692
+ if (!/(?:^|\n)\s*(?:[-*]\s*)?(?:must-fix|must fix)\b/i.test(text)) return false;
1693
+ return !/(?:^|\n)\s*(?:[-*]\s*)?(?:must-fix|must fix)\s*[:=]?\s*0\b/i.test(text);
1694
+ }
1695
+
1634
1696
  type GithubPull = {
1635
1697
  number: number;
1636
1698
  title: string;
@@ -1814,6 +1876,36 @@ export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: Dr
1814
1876
  }
1815
1877
  return undefined;
1816
1878
  };
1879
+ const reviewGateForDraft = (draft: SweepDraft, repository: string): SweepReviewGate | undefined => {
1880
+ const head = ghJson<{ head?: { sha?: string } }>(['api', `repos/${repository}/pulls/${draft.number}`], execute);
1881
+ const sha = head?.head?.sha;
1882
+ if (!sha) return undefined;
1883
+ const comments: string[] = [];
1884
+ for (let page = 1; page <= 100; page++) {
1885
+ const batch = ghJson<Array<{ body?: string }>>(['api', `repos/${repository}/issues/${draft.number}/comments?per_page=100&page=${page}`], execute);
1886
+ if (!Array.isArray(batch) || batch.length > 100) throw new Error('Incomplete review comment inventory');
1887
+ comments.push(...batch.map((comment) => comment.body ?? ''));
1888
+ if (batch.length < 100) break;
1889
+ if (page === 100) throw new Error('Review comment inventory exceeded pagination limit');
1890
+ }
1891
+ const reviews = ghJson<Array<{ state?: string; body?: string }>>(['api', `repos/${repository}/pulls/${draft.number}/reviews?per_page=100`], execute);
1892
+ if (!Array.isArray(reviews) || reviews.length > 100) throw new Error('Incomplete review inventory');
1893
+ const text = [...comments, ...reviews.map((review) => review.body ?? '')].join('\n');
1894
+ const status = ghJson<{ state?: string }>(['api', `repos/${repository}/commits/${sha}/status`], execute);
1895
+ const checkRuns = ghJson<{ check_runs?: Array<{ conclusion?: string | null }> }>(
1896
+ ['api', `repos/${repository}/commits/${sha}/check-runs?per_page=100`], execute);
1897
+ if (!checkRuns || !Array.isArray(checkRuns.check_runs)) throw new Error('Incomplete check-run inventory');
1898
+ const conclusions = checkRuns.check_runs.map((run) => run.conclusion ?? null);
1899
+ const gatePass = (status?.state === 'success' || status?.state === undefined)
1900
+ && conclusions.length > 0 && conclusions.every((conclusion) => conclusion === 'success' || conclusion === 'skipped' || conclusion === 'neutral');
1901
+ const gateFail = status?.state === 'failure' || status?.state === 'error'
1902
+ || conclusions.some((conclusion) => conclusion === 'failure' || conclusion === 'cancelled' || conclusion === 'timed_out' || conclusion === 'action_required');
1903
+ return {
1904
+ ...(reviews.some((review) => review.state === 'APPROVED') || /(?:^|\n)\s*VERDICT:\s*PASS\b/i.test(text) ? { review: 'pass' as const } : {}),
1905
+ ...(mustFixRemains(text) ? { mustFix: true } : {}),
1906
+ ...(gatePass && !gateFail ? { gate: 'pass' as const } : gateFail ? { gate: 'fail' as const } : {}),
1907
+ };
1908
+ };
1817
1909
  const landingCommentsFor = (repository: string, number: number): string[] => {
1818
1910
  const comments: string[] = [];
1819
1911
  for (let page = 1; page <= 100; page++) {
@@ -1902,6 +1994,7 @@ export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: Dr
1902
1994
  execute(['pr', 'close', String(number), '--repo', repository, '--comment', comment]);
1903
1995
  },
1904
1996
  getClaimOwner: async (repository, number) => claimCommentOwner(repository, number, execute),
1997
+ getReviewGate: async (draft, repository) => reviewGateForDraft(draft, repository),
1905
1998
  };
1906
1999
  }
1907
2000
 
@@ -1936,7 +2029,10 @@ function installHarnessDraftSweepCommand(harnessCmd: Command, deps: HarnessDraft
1936
2029
  .action(async (number: string, opts: { owner?: string; note?: string; release?: boolean; repo?: string }) => {
1937
2030
  try {
1938
2031
  const execute = deps.execute ?? executeGh;
1939
- const repository = opts.repo ?? deps.repository?.() ?? execute(['repo', 'view', '--json', 'nameWithOwner', '--jq', '.nameWithOwner']).trim();
2032
+ const repository = resolveRepositoryName({
2033
+ repo: opts.repo ?? deps.repository?.(),
2034
+ executeGh: (args) => execute(args),
2035
+ });
1940
2036
  if (!DRAFT_SWEEP_REPOSITORY.test(repository) || repository.includes('..')) throw new HarnessCliInputError(`invalid --repo (expected owner/name): ${repository}`);
1941
2037
  if (!/^[1-9]\d*$/.test(number) || !Number.isSafeInteger(Number(number))) throw new HarnessCliInputError(`invalid PR number: ${number}`);
1942
2038
  const owner = opts.owner?.trim();
@@ -1973,21 +2069,32 @@ function installHarnessDraftSweepCommand(harnessCmd: Command, deps: HarnessDraft
1973
2069
  .action(async (opts: { apply?: boolean; json?: boolean; repo?: string }) => {
1974
2070
  try {
1975
2071
  const write = deps.write ?? console.log;
1976
- const repository = opts.repo ?? deps.repository?.() ?? execFileSync('gh', ['repo', 'view', '--json', 'nameWithOwner', '--jq', '.nameWithOwner'],
1977
- { encoding: 'utf8', timeout: 30_000, stdio: ['ignore', 'pipe', 'pipe'], env: process.env }).trim();
2072
+ const execute = deps.execute ?? executeGh;
2073
+ const repository = resolveRepositoryName({
2074
+ repo: opts.repo ?? deps.repository?.(),
2075
+ executeGh: (args) => execute(args),
2076
+ });
1978
2077
  if (!DRAFT_SWEEP_REPOSITORY.test(repository) || repository.includes('..')) {
1979
2078
  throw new HarnessCliInputError(`invalid --repo (expected owner/name): ${repository}`);
1980
2079
  }
1981
2080
  const result: DraftSweepResult = await runDraftSweep({ repository, apply: opts.apply === true, adapters: deps.adapters ?? githubDraftSweepAdapters(deps.execute) });
1982
- if (opts.json) write(JSON.stringify(result));
2081
+ const reason = result.error ? sweepFailureReason(result.error) : undefined;
2082
+ if (opts.json) write(JSON.stringify(reason ? { ...result, error: reason } : result));
1983
2083
  else {
1984
- write(`draft sweep ${result.repository}: ${result.complete ? 'complete' : `incomplete (${result.error})`} · ${result.apply ? 'apply' : 'dry-run'}`);
1985
- for (const entry of result.entries) write(`#${entry.number} ${entry.action}: ${entry.reason}${entry.statusLabel ? ` → ${entry.statusLabel}` : ''}${entry.error ? ` ERROR: ${entry.error}` : ''}`);
1986
- if (result.complete) write(`못 본 초안 ${result.unobserved ?? 0} · 이번에 닫음 ${result.closed ?? 0}${result.apply ? '' : '(dry-run)'} · 처리 중 ${result.claimed ?? 0} · 표식 만료 ${result.claimExpired ?? 0}`);
2084
+ write(`draft sweep ${result.repository}: ${result.complete ? 'complete' : `incomplete (${reason})`} · ${result.apply ? 'apply' : 'dry-run'}`);
2085
+ for (const entry of result.entries) write(`#${entry.number} ${entry.action}: ${entry.reason}${entry.statusLabel ? ` → ${entry.statusLabel}` : ''}${entry.error ? ` ERROR: ${sweepFailureReason(entry.error)}` : ''}`);
2086
+ if (result.complete) {
2087
+ const daily = result.daily
2088
+ ? ` · 24h 넘음 ${result.daily.over24h} · 정리 대상 ${result.daily.closable} · 수확 대기 ${result.daily.harvestable} · 막힘 ${result.daily.blocked}`
2089
+ : '';
2090
+ write(`못 본 초안 ${result.unobserved ?? 0} · 이번에 닫음 ${result.closed ?? 0}${result.apply ? '' : '(dry-run)'} · 처리 중 ${result.claimed ?? 0} · 표식 만료 ${result.claimExpired ?? 0}${daily}`);
2091
+ }
2092
+ if (reason) write(reason);
1987
2093
  }
1988
2094
  if (!result.complete || result.entries.some((entry) => entry.error)) process.exitCode = 1;
1989
2095
  } catch (error) {
1990
2096
  console.error(humanErrorLine(error));
2097
+ try { debug.log('drafts.cleanup', 'failed', { reason: sweepFailureReason(error) }); } catch { /* observation is fail-soft */ }
1991
2098
  process.exitCode = 1;
1992
2099
  }
1993
2100
  });
@@ -2248,6 +2355,27 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
2248
2355
  .command('harness')
2249
2356
  .description('dev-harness worktree 수명 — 워크트리 생성(worktree add)·조회(worktrees)·정리(clean)·프로세스 관찰(processes)');
2250
2357
  installHarnessCliSinkHook(harnessCmd, deps.registerSink, deps.resolveSurface);
2358
+ harnessCmd.command('doors').description('기간 안 런을 입구×대기열 경유 표로 읽는다')
2359
+ .option('--since <window>', '조회 창 (30m · 12h · 1d, 기본 1d)', '1d')
2360
+ .option('--json', '구조화 출력')
2361
+ .action((opts: { since?: string; json?: boolean }) => {
2362
+ const parsed = parseDoorSince(opts.since);
2363
+ if ('error' in parsed) {
2364
+ console.error(`❌ ${parsed.error}`);
2365
+ process.exitCode = 2;
2366
+ return;
2367
+ }
2368
+ let table: DoorTable;
2369
+ try {
2370
+ table = queryLaunchDoors({ sinceMs: parsed.sinceMs });
2371
+ } catch (error) {
2372
+ console.error(`❌ doors: ${error instanceof Error ? error.message : String(error)}`);
2373
+ process.exitCode = 1;
2374
+ return;
2375
+ }
2376
+ if (opts.json) console.log(JSON.stringify(table));
2377
+ else console.log(renderLaunchDoors(table));
2378
+ });
2251
2379
  harnessCmd.command('incidents').description('최근 하니스 Pod 종료 사고 원장을 읽는다')
2252
2380
  .option('--since <minutes>', '최근 몇 분의 종료를 볼지 (기본 15분)', '15')
2253
2381
  .option('--json', '구조화 출력')
@@ -2294,7 +2422,7 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
2294
2422
  console.log(`${row.id} ${row.seat} ${row.kind} queued`);
2295
2423
  }));
2296
2424
  queue.command('list').description('대기·발사 원장 조회').action(() => queueAction(async () => {
2297
- for (const row of listHarnessQueue(queueDeps)) console.log(`${row.id} ${row.seat} ${row.status} ${row.kind} ${row.input}`);
2425
+ for (const row of listHarnessQueue(queueDeps)) console.log(`${row.id} ${row.seat} ${row.status} ${row.kind} ${row.input}${row.waitingReason ? ` · ${row.waitingReason}` : ''}`);
2298
2426
  }));
2299
2427
  queue.command('remove <id>').description('대기 중 또는 종료 확인된 항목 제거').action((id: string) => queueAction(async () => {
2300
2428
  if (!await removeHarnessQueue(id, queueDeps)) throw new Error(`queue item active or not found: ${id}`);
@@ -2303,7 +2431,7 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
2303
2431
  queue.command('reconcile <id>').description('불확정 발사를 확인하고 종료 또는 미발사 증거가 있으면 예약 해소').action((id: string) => queueAction(async () => {
2304
2432
  console.log(`${id} ${await reconcileHarnessQueue(id, queueDeps)}`);
2305
2433
  }));
2306
- queue.command('tick').description('맨 앞 한 건의 자리 몫과 Pod 풀 여유를 확인하고 발사').action(() => queueAction(async () => {
2434
+ queue.command('tick').description('자리별 맨 앞 한 건을 라운드로빈으로 돌며 자리 몫·Pod 풀 여유·마무리 관문을 확인하고 한 건 발사').action(() => queueAction(async () => {
2307
2435
  const result = await tickHarnessQueue(queueDeps);
2308
2436
  console.log(`${result.outcome}${result.item ? ` ${result.item.id}` : ''}: ${result.reason}`);
2309
2437
  }));
@@ -2328,7 +2456,7 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
2328
2456
  process.exitCode = 2;
2329
2457
  return Promise.resolve();
2330
2458
  }
2331
- return resolved.substrate === 'pod' ? onPod(stampedOpts, 'cli-harness-ask', goalPath, resolved.pool!, deps.podDispatchTask) : ask(goalPath, normalizeHarnessAskSayOptions(stampedOpts));
2459
+ return resolved.substrate === 'pod' ? onPod(stampedOpts, 'cli-harness-ask', goalPath, resolved.pool!, deps.podDispatchTask) : (announceLocalChildProvider(stampedOpts), ask(goalPath, normalizeHarnessAskSayOptions(stampedOpts)));
2332
2460
  },
2333
2461
  deps.launchGate,
2334
2462
  );
@@ -2353,7 +2481,9 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
2353
2481
  process.exitCode = 2;
2354
2482
  return Promise.resolve();
2355
2483
  }
2356
- return resolved.substrate === 'pod' ? onPod(stampedOpts, 'cli-harness-say', sentence.join(' '), resolved.pool!, deps.podDispatchTask) : say(sentence, normalizeHarnessAskSayOptions(stampedOpts));
2484
+ return resolved.substrate === 'pod'
2485
+ ? onPod(stampedOpts, 'cli-harness-say', sentence.join(' '), resolved.pool!, deps.podDispatchTask, harnessAuthorOnPod())
2486
+ : (announceLocalChildProvider(stampedOpts), say(sentence, normalizeHarnessAskSayOptions(stampedOpts)));
2357
2487
  },
2358
2488
  deps.launchGate,
2359
2489
  );
@@ -2,6 +2,7 @@ import { Database } from 'bun:sqlite';
2
2
  import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { redactSecretText } from '../debug/log.js';
5
+ import { refuseProductionLedgerWriteInTest } from './ledger-write-guard.js';
5
6
 
6
7
  export interface RunExit {
7
8
  runId: string;
@@ -83,6 +84,7 @@ export function readRunExits(root: string): RunExit[] {
83
84
 
84
85
  /** SQLite's process-owned write lock serializes ledger checks and appends across processes. */
85
86
  export function recordRunExit(row: RunExit, root: string): void {
87
+ if (refuseProductionLedgerWriteInTest(root, 'incidents')) return;
86
88
  if (!row.runId?.trim()) return;
87
89
  const at = Date.parse(row.at);
88
90
  if (!Number.isFinite(at)) throw new Error('invalid incident exit time');
@@ -7,13 +7,23 @@
7
7
  * 매니페스트가 실은 런 계약(`ELANOUS_RUN_CONTRACT`)으로 자기가 Pod 인 줄 안다(graph-run-contract.ts).
8
8
  */
9
9
  import { spawn } from 'node:child_process';
10
+ import { createHash, randomUUID } from 'node:crypto';
11
+ import { hostname } from 'node:os';
10
12
  import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
11
13
  import { isAbsolute, join, relative, resolve, sep } from 'node:path';
12
14
  import { selfDevRunsDir } from '../self-dev/run-store.js';
13
15
  import { findGitDir } from '../git-fs/locate.js';
16
+ import { logsDbPath } from '../mss/logging/log-store.js';
17
+ import { POD_REEMIT_LOGS_DB_ENV } from '../task-orchestrator/surfaces/pod-ledger-prod-sink.js';
14
18
  import { debug } from '../debug/log.js';
15
19
  import { ELANOUS_ENTRY_SCRIPT } from '../self-implement/seams.js';
16
20
  import { parsePodSourceSpec } from '../task-orchestrator/surfaces/pod-source-spec.js';
21
+ import { declaredGoalType, type GoalType } from '../self-implement/goal-author.js';
22
+ import { appendRunLedgerEntry } from '../self-implement/run-ledger.js';
23
+ import { HARNESS_RUN_ID_ENV } from './harness-space.js';
24
+ import { podMemoryLimitFor, type PodMemoryTier } from '../task-orchestrator/surfaces/self-implement-pod.js';
25
+ import { oldDoorInternalEnv } from '../self-dev/old-door.js';
26
+ import { selectPodMemoryTier } from './pod-memory-policy.js';
17
27
 
18
28
  export interface HarnessPodDispatchInput {
19
29
  readonly entrance: 'cli-harness-ask' | 'cli-harness-say';
@@ -23,8 +33,9 @@ export interface HarnessPodDispatchInput {
23
33
  readonly seat?: 'OP' | 'TC' | 'MK' | 'UX';
24
34
  /** Host already recorded the observe-only dispatch; suppress a second decision in the Pod. */
25
35
  readonly dispatchRecorded?: boolean;
26
- /** Pod 메모리 등급(standard|high) — 오케스트레이터 환경 `ELANOUS_POD_MEMORY_TIER` 로 Job 까지 간다. */
27
- readonly podMemory?: string;
36
+ /** Pod 메모리 등급(lite|standard|high) — 오케스트레이터 환경 `ELANOUS_POD_MEMORY_TIER` 로 Job 까지 간다. */
37
+ readonly podMemory?: PodMemoryTier;
38
+ readonly goalType?: GoalType;
28
39
  /** L7c — Pod queue predecessor (goal ID or PR) — `ELANOUS_POD_AFTER` carries it to every Pod Job admission. */
29
40
  readonly after?: string;
30
41
  readonly autoMerge?: boolean;
@@ -32,6 +43,12 @@ export interface HarnessPodDispatchInput {
32
43
  readonly json?: boolean;
33
44
  /** 사람이 고른 원천 spec — `commit:` · `pr:` · `worktree:` · `files:`. 검증은 발사 전. */
34
45
  readonly source?: string;
46
+ /** `--child-llm-provider/--child-llm-model/--child-llm-effort` — carried to `self orchestrate` so the Pod child uses them (10-05 PODPROVIDER). */
47
+ readonly childLlmProvider?: string;
48
+ readonly childLlmModel?: string;
49
+ readonly childLlmEffort?: string;
50
+ /** `harness.authorOnPod` — say 문장을 Pod 안에서 저작부터 돌린다. 호스트는 영수증만 남긴다. */
51
+ readonly authorOnPod?: boolean;
35
52
  }
36
53
 
37
54
  export function podOrchestrateArgs(input: HarnessPodDispatchInput, goalFile: string): string[] {
@@ -44,6 +61,9 @@ export function podOrchestrateArgs(input: HarnessPodDispatchInput, goalFile: str
44
61
  ...(input.base ? ['--base', input.base] : []),
45
62
  ...(input.json ? ['--json'] : []),
46
63
  ...(input.source ? ['--pod-source', input.source] : []),
64
+ ...(input.childLlmProvider?.trim() ? ['--child-llm-provider', input.childLlmProvider.trim()] : []),
65
+ ...(input.childLlmModel?.trim() ? ['--child-llm-model', input.childLlmModel.trim()] : []),
66
+ ...(input.childLlmEffort?.trim() ? ['--child-llm-effort', input.childLlmEffort.trim()] : []),
47
67
  '--concurrency', '1',
48
68
  ];
49
69
  }
@@ -63,31 +83,69 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
63
83
  return 2;
64
84
  }
65
85
  }
86
+ const env = { ...process.env, ...oldDoorInternalEnv('self-orchestrate') };
87
+ // POD-OBS(10-06): 자식 orchestrate 는 트리 파생 우주에서 돈다 — Pod 원장 재방출을 «발사한 집»의 logs.db 에도 남기게 경로를 넘긴다.
88
+ env[POD_REEMIT_LOGS_DB_ENV] = logsDbPath();
66
89
  let tempDir: string | undefined;
67
- let goalFile: string;
68
- let goalChars: number;
90
+ let goalFile = '';
91
+ let goalText: string;
69
92
  if (input.entrance === 'cli-harness-ask') {
70
93
  goalFile = resolve(cwd, input.input);
71
- goalChars = (deps.readFile ?? ((p) => readFileSync(p, 'utf8')))(goalFile).length;
94
+ goalText = (deps.readFile ?? ((p) => readFileSync(p, 'utf8')))(goalFile);
95
+ } else if (input.authorOnPod) {
96
+ // AUTHOR-POD2 (10-06) — the Pod runs `harness say` on the verbatim sentence itself (podJobManifest
97
+ // authorSentence branch). No wrapper goal and no host-side file under docs/goals: the 10-06 live run
98
+ // showed a wrapper goal is implemented as code by the Pod child instead of being executed.
99
+ goalText = input.input;
100
+ const runsDir = selfDevRunsDir();
101
+ mkdirSync(runsDir, { recursive: true });
102
+ tempDir = mkdtempSync(join(runsDir, 'pod-author-'));
103
+ goalFile = join(tempDir, 'sentence.txt');
104
+ writeFileSync(goalFile, input.input, { mode: 0o600 });
105
+ const runId = env[HARNESS_RUN_ID_ENV]?.trim() || `run-${randomUUID()}`;
106
+ env[HARNESS_RUN_ID_ENV] = runId;
107
+ const receipt = { entrance: input.entrance, host: hostname(), runId, authorOnPod: true,
108
+ sentenceChars: input.input.length, sentenceSha256: createHash('sha256').update(input.input).digest('hex') };
109
+ debug.log('harness.substrate', 'author-on-pod-receipt', receipt);
110
+ try { appendRunLedgerEntry({ runId, event: 'author-on-pod-receipt', data: receipt }); }
111
+ catch (error) { debug.log('harness.substrate', 'author-on-pod-receipt-unwritten', { reason: error instanceof Error ? error.message : String(error) }); }
72
112
  } else {
73
113
  const goal = input.input;
114
+ goalText = goal;
74
115
  const runsDir = selfDevRunsDir();
75
116
  mkdirSync(runsDir, { recursive: true });
76
117
  tempDir = mkdtempSync(join(runsDir, 'pod-goal-'));
77
118
  goalFile = join(tempDir, 'goal.txt');
78
119
  writeFileSync(goalFile, goal, { mode: 0o600 });
79
- goalChars = goal.length;
80
120
  }
121
+ const goalChars = goalText.length;
81
122
  const args = podOrchestrateArgs(input, goalFile);
82
123
  debug.log('harness.substrate', 'goal-file', { entrance: input.entrance, mode: tempDir ? 'temp' : 'path' });
83
- const env = { ...process.env };
124
+ const goalType = input.goalType ?? declaredGoalType(goalText);
125
+ // A process-level memory tier is already an explicit selection; do not replace it with a goal-type default.
126
+ const existing = podMemoryLimitFor(goalText, env);
127
+ const selection = !input.podMemory && ['option', 'goal-line', 'pwa-auto', 'advise'].includes(existing.source)
128
+ ? { tier: existing.tier, reason: 'existing-tier' as const }
129
+ : goalType || input.podMemory ? selectPodMemoryTier(goalType ?? 'implement', input.podMemory, existing.tier) : undefined;
130
+ if (selection) {
131
+ env.ELANOUS_POD_MEMORY_TIER = selection.tier;
132
+ env.ELANOUS_POD_MEMORY_REASON = selection.reason;
133
+ } else {
134
+ delete env.ELANOUS_POD_MEMORY_REASON;
135
+ }
136
+ if (goalType) env.ELANOUS_POD_GOAL_TYPE = goalType;
137
+ else delete env.ELANOUS_POD_GOAL_TYPE;
84
138
  if (input.seat) env.ELANOUS_HARNESS_SEAT = input.seat;
85
139
  delete env.ELANOUS_POD_GOAL_DOC;
86
140
  delete env.ELANOUS_DISPATCH_RECORDED;
87
141
  if (input.dispatchRecorded) env.ELANOUS_DISPATCH_RECORDED = '1';
88
- if (input.podMemory) env.ELANOUS_POD_MEMORY_TIER = input.podMemory;
142
+ debug.log('harness.substrate', 'memory-selected', { entrance: input.entrance, goalType,
143
+ tier: selection?.tier ?? existing.tier, reason: selection?.reason ?? existing.source,
144
+ memoryLimit: podMemoryLimitFor(goalText, env).limit });
89
145
  delete env.ELANOUS_POD_AFTER;
90
146
  if (input.after) env.ELANOUS_POD_AFTER = input.after;
147
+ if (input.authorOnPod) env.ELANOUS_POD_AUTHOR_ON_POD = '1';
148
+ else delete env.ELANOUS_POD_AUTHOR_ON_POD;
91
149
  if (input.entrance === 'cli-harness-ask') {
92
150
  const root = findGitDir(cwd)?.root;
93
151
  const path = resolve(cwd, input.input);
@@ -100,6 +158,7 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
100
158
  }
101
159
  debug.log('harness.substrate', 'dispatch-pod', {
102
160
  entrance: input.entrance, podPool: input.podPool ?? null, podMemory: input.podMemory ?? null, after: input.after ?? null, autoMerge: input.autoMerge !== false,
161
+ childLlmProvider: input.childLlmProvider ?? null, childLlmModel: input.childLlmModel ?? null,
103
162
  goalChars, ...(input.entrance === 'cli-harness-ask' ? { goalPath: input.input } : {}),
104
163
  });
105
164
  const run = deps.run ?? ((cmd: string, a: readonly string[], childEnv: NodeJS.ProcessEnv) => new Promise<number>((resolveStatus) => {