elanous 0.2.0 → 0.2.5

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 (1249) hide show
  1. package/.env.example +6 -0
  2. package/README.md +17 -15
  3. package/apps/pwa/out/404/index.html +1 -1
  4. package/apps/pwa/out/404.html +1 -1
  5. package/apps/pwa/out/_next/static/chunks/06ef2eba-d1b99ac6d2ea663c.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1413-7179a49332db5a80.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/150-25c277137a9638ab.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1640-bc99ec23bbe29d12.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/1751.50b96ea9c37b49b6.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2300-de059d0ab2a16630.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2684-05b0a81e75298c16.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3026-2ed7e317d9b02102.js +25 -0
  13. package/apps/pwa/out/_next/static/chunks/3611-77496ada38cd6358.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3717-68957c4dc9ceec90.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3929-46ba9af6f9d895cc.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/4015-62c5a3744698a8da.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/4217-3c4317a7905f9eeb.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/4240-3230f230fae2d7d5.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/4271-e53e075ebd48593b.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4377.3b125fef79576dfd.js +5 -0
  21. package/apps/pwa/out/_next/static/chunks/4440-18bb160d95819f4e.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4853-35fdbe6bdbcdc0fc.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{2a79f15a-2013e4d421d6df88.js → 4daa2798-1363d725c79f3593.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/5007-6a3b30e23ff68a6e.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/5244-12b424c42070f5ff.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5348-bbf838e119661eee.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5391-8793f88b03b30161.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5611-df00af3e4e4a61bb.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/5890-dca2321773be829a.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6123-37c9dc57ddaa7ab0.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/6588-b7975304a302ab91.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6604-c03961962b6273b6.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/7109-cf8c87e968e83a65.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7178-30f77877525a2efb.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7262-871563fc9663730b.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7294-f0eeebb92aa93459.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/7429-881af44deed6958f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{5927.8378481a12cc8044.js → 7527.943753b6ed829f09.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/764-a01e858525a190c0.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/7868-e35d5f7985ecd3f1.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8320-51484af7b01fdfa5.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{6804.8ed6ab492bc5fc0a.js → 8617.465ca22a319c95b3.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/{320-d7013ec072863e5e.js → 8918-482b30ce2a8ebf4c.js} +4 -4
  44. package/apps/pwa/out/_next/static/chunks/9131-52f5fad51cceca04.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{2598.814f64e3268634e7.js → 9238.2cd5f47f4bf7a2c3.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/9704-3221c102623c8d73.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-70c404c7bb6d7f0f.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3ffd80166b1050aa.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f89e9a303515a033.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/board/page-4f403cd060442c95.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/botlab/page-0ac5d053f0444d21.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/bots/page-4bcc63e272ae8205.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/chat/page-880734bd07d62882.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/control/page-72bd384898d88955.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1018bbc9586ecae5.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/editor/page-de86f8c38076dd7b.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/healthz/route-70c404c7bb6d7f0f.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/intake/page-cd6447196d8bafe6.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/layout-e733630c47fa102b.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/live/page-d1c1a8357b161875.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/market/page-60c514128e81d787.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8b637b7e325e13c1.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/morning/page-bccce0babceae30f.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/not-found-63301d11dbe73836.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/observatory/page-a8cf0dc472060db2.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/page-02fba54881ccfa49.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d5e8e90f0038f8de.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-b1ef6824f494466a.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d589bb0f233b1009.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c9bbaebef4cda059.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/settings/page-3639ce7916b92fed.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7450ae7478955653.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/setup/layout-70c404c7bb6d7f0f.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/setup/page-b41ca4abfd618452.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/share/page-b333dd79ebee3fa9.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/showroom/page-8be1227492793655.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6e03e9371b552e0d.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/term/page-911411e9fca18d03.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/trace/page-792170e649b37088.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/vault/page-c40463466937bc91.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-509c798b80384536.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/workflows/page-1cac2aa21d77c417.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9626799d9b4a2cd1.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-84cd419494e16b0f.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/f6f3850d-7f324c6566002113.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/framework-361487d2da603917.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/main-app-607f5beb94cb2e07.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/main-d0222d219e29dddf.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/pages/_app-a26980a31126decc.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/pages/_error-edb2b37decf23e4d.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/webpack-2bf59c720fe9542c.js +1 -0
  92. package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +1 -0
  93. package/apps/pwa/out/_next/static/ktMqfrBbf8BMGac0jqLrb/_buildManifest.js +1 -0
  94. package/apps/pwa/out/approvals/index.html +1 -0
  95. package/apps/pwa/out/approvals/index.txt +32 -0
  96. package/apps/pwa/out/autopilot/index.html +1 -1
  97. package/apps/pwa/out/autopilot/index.txt +29 -26
  98. package/apps/pwa/out/board/index.html +1 -0
  99. package/apps/pwa/out/board/index.txt +32 -0
  100. package/apps/pwa/out/botlab/index.html +1 -1
  101. package/apps/pwa/out/botlab/index.txt +26 -23
  102. package/apps/pwa/out/bots/index.html +1 -1
  103. package/apps/pwa/out/bots/index.txt +26 -23
  104. package/apps/pwa/out/chat/index.html +1 -2
  105. package/apps/pwa/out/chat/index.txt +26 -23
  106. package/apps/pwa/out/control/index.html +1 -1
  107. package/apps/pwa/out/control/index.txt +29 -26
  108. package/apps/pwa/out/design-check/index.html +1 -1
  109. package/apps/pwa/out/design-check/index.txt +29 -26
  110. package/apps/pwa/out/editor/index.html +1 -0
  111. package/apps/pwa/out/editor/index.txt +33 -0
  112. package/apps/pwa/out/healthz +1 -1
  113. package/apps/pwa/out/icons/elanous-16.png +0 -0
  114. package/apps/pwa/out/icons/elanous-180.png +0 -0
  115. package/apps/pwa/out/icons/elanous-192.png +0 -0
  116. package/apps/pwa/out/icons/elanous-32.png +0 -0
  117. package/apps/pwa/out/icons/elanous-512.png +0 -0
  118. package/apps/pwa/out/index.html +1 -1
  119. package/apps/pwa/out/index.txt +26 -23
  120. package/apps/pwa/out/intake/index.html +1 -1
  121. package/apps/pwa/out/intake/index.txt +29 -26
  122. package/apps/pwa/out/live/index.html +1 -0
  123. package/apps/pwa/out/live/index.txt +32 -0
  124. package/apps/pwa/out/manifest.webmanifest +5 -2
  125. package/apps/pwa/out/market/index.html +1 -0
  126. package/apps/pwa/out/market/index.txt +29 -0
  127. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  128. package/apps/pwa/out/missions/placeholder/index.txt +26 -23
  129. package/apps/pwa/out/morning/index.html +1 -1
  130. package/apps/pwa/out/morning/index.txt +29 -26
  131. package/apps/pwa/out/observatory/index.html +1 -1
  132. package/apps/pwa/out/observatory/index.txt +29 -26
  133. package/apps/pwa/out/reflection/index.html +1 -1
  134. package/apps/pwa/out/reflection/index.txt +27 -24
  135. package/apps/pwa/out/scheduler/index.html +1 -1
  136. package/apps/pwa/out/scheduler/index.txt +29 -26
  137. package/apps/pwa/out/sessions/index.html +1 -1
  138. package/apps/pwa/out/sessions/index.txt +26 -23
  139. package/apps/pwa/out/settings/devices/index.html +1 -1
  140. package/apps/pwa/out/settings/devices/index.txt +29 -26
  141. package/apps/pwa/out/settings/index.html +1 -1
  142. package/apps/pwa/out/settings/index.txt +29 -26
  143. package/apps/pwa/out/setup/done/index.html +1 -1
  144. package/apps/pwa/out/setup/done/index.txt +29 -26
  145. package/apps/pwa/out/setup/index.html +1 -1
  146. package/apps/pwa/out/setup/index.txt +29 -26
  147. package/apps/pwa/out/share/index.html +1 -1
  148. package/apps/pwa/out/share/index.txt +29 -26
  149. package/apps/pwa/out/showroom/index.html +1 -1
  150. package/apps/pwa/out/showroom/index.txt +26 -23
  151. package/apps/pwa/out/sw-strategies.js +44 -0
  152. package/apps/pwa/out/sw.js +6 -44
  153. package/apps/pwa/out/tasks/index.html +1 -1
  154. package/apps/pwa/out/tasks/index.txt +29 -26
  155. package/apps/pwa/out/term/index.html +1 -1
  156. package/apps/pwa/out/term/index.txt +29 -26
  157. package/apps/pwa/out/trace/index.html +1 -0
  158. package/apps/pwa/out/trace/index.txt +32 -0
  159. package/apps/pwa/out/vault/index.html +1 -1
  160. package/apps/pwa/out/vault/index.txt +29 -26
  161. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  162. package/apps/pwa/out/workflows/chat-ui/index.txt +29 -26
  163. package/apps/pwa/out/workflows/index.html +1 -1
  164. package/apps/pwa/out/workflows/index.txt +29 -27
  165. package/apps/pwa/out/workspace/index.html +1 -1
  166. package/apps/pwa/out/workspace/index.txt +29 -26
  167. package/apps/pwa/out/worktrees/index.html +1 -1
  168. package/apps/pwa/out/worktrees/index.txt +29 -26
  169. package/catalog/resources.yaml +14 -17
  170. package/docs/design/systems/LICENSE +201 -0
  171. package/docs/design/systems/NOTICE.md +29 -0
  172. package/docs/design/systems/SOURCE.json +291 -0
  173. package/docs/design/systems/application/DESIGN.md +71 -0
  174. package/docs/design/systems/application/manifest.json +54 -0
  175. package/docs/design/systems/application/tokens.css +63 -0
  176. package/docs/design/systems/artistic/DESIGN.md +71 -0
  177. package/docs/design/systems/artistic/manifest.json +54 -0
  178. package/docs/design/systems/artistic/tokens.css +63 -0
  179. package/docs/design/systems/bento/DESIGN.md +71 -0
  180. package/docs/design/systems/bento/manifest.json +54 -0
  181. package/docs/design/systems/bento/tokens.css +63 -0
  182. package/docs/design/systems/bold/DESIGN.md +71 -0
  183. package/docs/design/systems/bold/manifest.json +54 -0
  184. package/docs/design/systems/bold/tokens.css +63 -0
  185. package/docs/design/systems/brutalism/DESIGN.md +71 -0
  186. package/docs/design/systems/brutalism/manifest.json +54 -0
  187. package/docs/design/systems/brutalism/tokens.css +63 -0
  188. package/docs/design/systems/cafe/DESIGN.md +71 -0
  189. package/docs/design/systems/cafe/manifest.json +54 -0
  190. package/docs/design/systems/cafe/tokens.css +63 -0
  191. package/docs/design/systems/claymorphism/DESIGN.md +71 -0
  192. package/docs/design/systems/claymorphism/manifest.json +54 -0
  193. package/docs/design/systems/claymorphism/tokens.css +63 -0
  194. package/docs/design/systems/clean/DESIGN.md +71 -0
  195. package/docs/design/systems/clean/manifest.json +54 -0
  196. package/docs/design/systems/clean/tokens.css +63 -0
  197. package/docs/design/systems/colorful/DESIGN.md +71 -0
  198. package/docs/design/systems/colorful/manifest.json +54 -0
  199. package/docs/design/systems/colorful/tokens.css +63 -0
  200. package/docs/design/systems/contemporary/DESIGN.md +71 -0
  201. package/docs/design/systems/contemporary/manifest.json +54 -0
  202. package/docs/design/systems/contemporary/tokens.css +63 -0
  203. package/docs/design/systems/corporate/DESIGN.md +71 -0
  204. package/docs/design/systems/corporate/manifest.json +54 -0
  205. package/docs/design/systems/corporate/tokens.css +63 -0
  206. package/docs/design/systems/cosmic/DESIGN.md +71 -0
  207. package/docs/design/systems/cosmic/manifest.json +54 -0
  208. package/docs/design/systems/cosmic/tokens.css +63 -0
  209. package/docs/design/systems/creative/DESIGN.md +71 -0
  210. package/docs/design/systems/creative/manifest.json +54 -0
  211. package/docs/design/systems/creative/tokens.css +63 -0
  212. package/docs/design/systems/dashboard/DESIGN.md +71 -0
  213. package/docs/design/systems/dashboard/manifest.json +54 -0
  214. package/docs/design/systems/dashboard/tokens.css +63 -0
  215. package/docs/design/systems/default/DESIGN.md +62 -0
  216. package/docs/design/systems/default/manifest.json +69 -0
  217. package/docs/design/systems/default/tokens.css +200 -0
  218. package/docs/design/systems/dithered/DESIGN.md +71 -0
  219. package/docs/design/systems/dithered/manifest.json +54 -0
  220. package/docs/design/systems/dithered/tokens.css +63 -0
  221. package/docs/design/systems/doodle/DESIGN.md +71 -0
  222. package/docs/design/systems/doodle/manifest.json +54 -0
  223. package/docs/design/systems/doodle/tokens.css +63 -0
  224. package/docs/design/systems/dramatic/DESIGN.md +71 -0
  225. package/docs/design/systems/dramatic/manifest.json +54 -0
  226. package/docs/design/systems/dramatic/tokens.css +63 -0
  227. package/docs/design/systems/editorial/DESIGN.md +71 -0
  228. package/docs/design/systems/editorial/manifest.json +54 -0
  229. package/docs/design/systems/editorial/tokens.css +63 -0
  230. package/docs/design/systems/elegant/DESIGN.md +71 -0
  231. package/docs/design/systems/elegant/manifest.json +54 -0
  232. package/docs/design/systems/elegant/tokens.css +63 -0
  233. package/docs/design/systems/energetic/DESIGN.md +72 -0
  234. package/docs/design/systems/energetic/manifest.json +54 -0
  235. package/docs/design/systems/energetic/tokens.css +63 -0
  236. package/docs/design/systems/enterprise/DESIGN.md +71 -0
  237. package/docs/design/systems/enterprise/manifest.json +54 -0
  238. package/docs/design/systems/enterprise/tokens.css +63 -0
  239. package/docs/design/systems/expressive/DESIGN.md +71 -0
  240. package/docs/design/systems/expressive/manifest.json +54 -0
  241. package/docs/design/systems/expressive/tokens.css +63 -0
  242. package/docs/design/systems/fantasy/DESIGN.md +71 -0
  243. package/docs/design/systems/fantasy/manifest.json +54 -0
  244. package/docs/design/systems/fantasy/tokens.css +63 -0
  245. package/docs/design/systems/flat/DESIGN.md +71 -0
  246. package/docs/design/systems/flat/manifest.json +54 -0
  247. package/docs/design/systems/flat/tokens.css +63 -0
  248. package/docs/design/systems/friendly/DESIGN.md +71 -0
  249. package/docs/design/systems/friendly/manifest.json +54 -0
  250. package/docs/design/systems/friendly/tokens.css +63 -0
  251. package/docs/design/systems/glassmorphism/DESIGN.md +71 -0
  252. package/docs/design/systems/glassmorphism/manifest.json +54 -0
  253. package/docs/design/systems/glassmorphism/tokens.css +63 -0
  254. package/docs/design/systems/gradient/DESIGN.md +71 -0
  255. package/docs/design/systems/gradient/manifest.json +54 -0
  256. package/docs/design/systems/gradient/tokens.css +63 -0
  257. package/docs/design/systems/luxury/DESIGN.md +71 -0
  258. package/docs/design/systems/luxury/manifest.json +54 -0
  259. package/docs/design/systems/luxury/tokens.css +63 -0
  260. package/docs/design/systems/minimal/DESIGN.md +71 -0
  261. package/docs/design/systems/minimal/manifest.json +54 -0
  262. package/docs/design/systems/minimal/tokens.css +63 -0
  263. package/docs/design/systems/modern/DESIGN.md +71 -0
  264. package/docs/design/systems/modern/manifest.json +54 -0
  265. package/docs/design/systems/modern/tokens.css +63 -0
  266. package/docs/design/systems/mono/DESIGN.md +71 -0
  267. package/docs/design/systems/mono/manifest.json +54 -0
  268. package/docs/design/systems/mono/tokens.css +63 -0
  269. package/docs/design/systems/neobrutalism/DESIGN.md +71 -0
  270. package/docs/design/systems/neobrutalism/manifest.json +54 -0
  271. package/docs/design/systems/neobrutalism/tokens.css +63 -0
  272. package/docs/design/systems/neon/DESIGN.md +71 -0
  273. package/docs/design/systems/neon/manifest.json +54 -0
  274. package/docs/design/systems/neon/tokens.css +63 -0
  275. package/docs/design/systems/neumorphism/DESIGN.md +71 -0
  276. package/docs/design/systems/neumorphism/manifest.json +54 -0
  277. package/docs/design/systems/neumorphism/tokens.css +63 -0
  278. package/docs/design/systems/paper/DESIGN.md +71 -0
  279. package/docs/design/systems/paper/manifest.json +54 -0
  280. package/docs/design/systems/paper/tokens.css +63 -0
  281. package/docs/design/systems/perspective/DESIGN.md +71 -0
  282. package/docs/design/systems/perspective/manifest.json +54 -0
  283. package/docs/design/systems/perspective/tokens.css +63 -0
  284. package/docs/design/systems/premium/DESIGN.md +71 -0
  285. package/docs/design/systems/premium/manifest.json +54 -0
  286. package/docs/design/systems/premium/tokens.css +63 -0
  287. package/docs/design/systems/professional/DESIGN.md +71 -0
  288. package/docs/design/systems/professional/manifest.json +54 -0
  289. package/docs/design/systems/professional/tokens.css +63 -0
  290. package/docs/design/systems/publication/DESIGN.md +71 -0
  291. package/docs/design/systems/publication/manifest.json +54 -0
  292. package/docs/design/systems/publication/tokens.css +63 -0
  293. package/docs/design/systems/refined/DESIGN.md +71 -0
  294. package/docs/design/systems/refined/manifest.json +54 -0
  295. package/docs/design/systems/refined/tokens.css +63 -0
  296. package/docs/design/systems/retro/DESIGN.md +71 -0
  297. package/docs/design/systems/retro/manifest.json +54 -0
  298. package/docs/design/systems/retro/tokens.css +63 -0
  299. package/docs/design/systems/shadcn/DESIGN.md +71 -0
  300. package/docs/design/systems/shadcn/manifest.json +54 -0
  301. package/docs/design/systems/shadcn/tokens.css +255 -0
  302. package/docs/design/systems/simple/DESIGN.md +71 -0
  303. package/docs/design/systems/simple/manifest.json +54 -0
  304. package/docs/design/systems/simple/tokens.css +63 -0
  305. package/docs/design/systems/skeumorphism/DESIGN.md +71 -0
  306. package/docs/design/systems/skeumorphism/manifest.json +54 -0
  307. package/docs/design/systems/skeumorphism/tokens.css +63 -0
  308. package/docs/design/systems/sleek/DESIGN.md +71 -0
  309. package/docs/design/systems/sleek/manifest.json +54 -0
  310. package/docs/design/systems/sleek/tokens.css +63 -0
  311. package/docs/design/systems/spacious/DESIGN.md +71 -0
  312. package/docs/design/systems/spacious/manifest.json +54 -0
  313. package/docs/design/systems/spacious/tokens.css +63 -0
  314. package/docs/design/systems/storytelling/DESIGN.md +71 -0
  315. package/docs/design/systems/storytelling/manifest.json +54 -0
  316. package/docs/design/systems/storytelling/tokens.css +63 -0
  317. package/docs/design/systems/tom-modern/DESIGN.md +361 -0
  318. package/docs/design/systems/tom-modern/manifest.json +16 -0
  319. package/docs/design/systems/tom-modern/tokens.css +99 -0
  320. package/docs/design/systems/vibrant/DESIGN.md +71 -0
  321. package/docs/design/systems/vibrant/manifest.json +54 -0
  322. package/docs/design/systems/vibrant/tokens.css +63 -0
  323. package/docs/design/systems/vintage/DESIGN.md +71 -0
  324. package/docs/design/systems/vintage/manifest.json +54 -0
  325. package/docs/design/systems/vintage/tokens.css +63 -0
  326. package/docs/design/systems/warm-editorial/DESIGN.md +65 -0
  327. package/docs/design/systems/warm-editorial/manifest.json +54 -0
  328. package/docs/design/systems/warm-editorial/tokens.css +63 -0
  329. package/docs/goal-context/01-goal-authoring-checks.md +18 -0
  330. package/docs/goal-context/steward-directives-2026-09-28.md +42 -0
  331. package/graphs/catalog/catalog.yaml +615 -0
  332. package/graphs/default-loop.yaml +1 -1
  333. package/graphs/document-loop.yaml +1 -1
  334. package/graphs/examples/stale-draft-digest/digest.ts +26 -0
  335. package/graphs/examples/stale-draft-digest/recipes.yaml +8 -0
  336. package/graphs/examples/stale-draft-digest/stale-draft-digest.yaml +22 -0
  337. package/graphs/heal/heal-loop.yaml +155 -0
  338. package/graphs/heal/recipes.yaml +19 -0
  339. package/graphs/implement-loop.yaml +2 -2
  340. package/graphs/intake/intake-daily.yaml +55 -0
  341. package/graphs/intake/recipes.yaml +16 -0
  342. package/graphs/landing/landing-heal.yaml +22 -0
  343. package/graphs/landing/recipes.yaml +8 -0
  344. package/graphs/launch/launch-head.yaml +66 -0
  345. package/graphs/launch/recipes.yaml +8 -0
  346. package/graphs/operate-loop.yaml +1 -1
  347. package/graphs/ops/docs-publish.yaml +31 -0
  348. package/graphs/ops/recipes.yaml +8 -0
  349. package/graphs/release/recipes.yaml +45 -0
  350. package/graphs/release/release-loop.yaml +45 -0
  351. package/graphs/research-loop.yaml +1 -1
  352. package/graphs/steward/recipes.yaml +12 -0
  353. package/graphs/steward/steward.yaml +45 -0
  354. package/graphs/video/README.md +1 -0
  355. package/graphs/video/broll-line.yaml +54 -0
  356. package/graphs/video/explainer-line.yaml +58 -0
  357. package/package.json +9 -5
  358. package/plugins/job-coach/.agents/plugins/marketplace.json +12 -0
  359. package/plugins/job-coach/.codex-plugin/plugin.json +23 -0
  360. package/plugins/job-coach/.mcp.json +9 -0
  361. package/plugins/job-coach/README.md +32 -0
  362. package/plugins/job-coach/connectors/ncs/server.ts +90 -0
  363. package/plugins/job-coach/examples/interview-sample.md +11 -0
  364. package/plugins/job-coach/graphs/course-links.ts +46 -0
  365. package/plugins/job-coach/graphs/gap-judge.ts +44 -0
  366. package/plugins/job-coach/graphs/recipes.yaml +45 -0
  367. package/plugins/job-coach/graphs/report-enterprise.yaml +28 -0
  368. package/plugins/job-coach/graphs/report.yaml +20 -0
  369. package/plugins/job-coach/graphs/run-step.ts +302 -0
  370. package/plugins/job-coach/plugin.json +26 -0
  371. package/plugins/job-coach/plugin.ts +6 -0
  372. package/plugins/job-coach/skills/career-report/SKILL.md +6 -0
  373. package/plugins/job-coach/skills/enterprise-ai-fit/SKILL.md +8 -0
  374. package/plugins/job-coach/skills/enterprise-competency/SKILL.md +8 -0
  375. package/plugins/job-coach/skills/enterprise-needs/SKILL.md +8 -0
  376. package/plugins/job-coach/skills/enterprise-roadmap/SKILL.md +8 -0
  377. package/plugins/job-coach/skills/enterprise-task-analysis/SKILL.md +8 -0
  378. package/plugins/job-coach/skills/interview-to-profile/SKILL.md +23 -0
  379. package/plugins/job-coach/skills/run-report/SKILL.md +15 -0
  380. package/scripts/backup/elanous-backup.sh +143 -14
  381. package/scripts/backup/elanous-restore.sh +122 -0
  382. package/scripts/build-docs-site.ts +4 -3
  383. package/scripts/ci-daemon-port-gate.ts +164 -0
  384. package/scripts/ci-typecheck-changed.ts +15 -1
  385. package/scripts/cli-json-exit-scan.ts +126 -0
  386. package/scripts/codex-quota-alert-format.ts +52 -0
  387. package/scripts/codex-quota-alert.ts +63 -13
  388. package/scripts/continuation-dogfood.ts +2 -1
  389. package/scripts/coord-channel-watch.sh +28 -9
  390. package/scripts/coord-post.sh +49 -12
  391. package/scripts/coord-tracks.json +6 -5
  392. package/scripts/cron-run.ts +37 -16
  393. package/scripts/daemon-port-baseline.txt +9 -0
  394. package/scripts/design/extract-corpus-bench.ts +469 -0
  395. package/scripts/design/extract-corpus-score.ts +510 -0
  396. package/scripts/design/vendor-open-design-systems.ts +100 -0
  397. package/scripts/docs-lint.ts +1 -1
  398. package/scripts/eval-bot-vs-grok.ts +79 -0
  399. package/scripts/eval-grok-live-baseline.ts +36 -0
  400. package/scripts/fixtures/front-route-corpus.sample.json +17 -0
  401. package/scripts/fleet/node-setup.sh +80 -7
  402. package/scripts/heal/run-role.ts +328 -0
  403. package/scripts/install-role-watch.sh +95 -0
  404. package/scripts/install.ps1 +11 -1
  405. package/scripts/install.sh +81 -9
  406. package/scripts/isolation-hardcode-baseline.txt +1 -1
  407. package/scripts/landing-heal/must-fix-match.ts +63 -0
  408. package/scripts/landing-heal/run-mission.ts +195 -0
  409. package/scripts/lib/front-route-measurement.ts +131 -0
  410. package/scripts/lib/pwa-scenarios/acp-replay.ts +79 -0
  411. package/scripts/lib/pwa-scenarios/cdp-driver.ts +67 -0
  412. package/scripts/lib/pwa-scenarios/runner.ts +200 -0
  413. package/scripts/lib/pwa-scenarios/scenarios.ts +202 -0
  414. package/scripts/lib/tui-sim-keys.ts +42 -0
  415. package/scripts/market/db-check.ts +212 -0
  416. package/scripts/market-posture-cycle.ts +63 -4
  417. package/scripts/measure-front-route-classifier.ts +56 -0
  418. package/scripts/media/ocr-leak-scan.sh +21 -0
  419. package/scripts/nightly-docops.ts +1 -1
  420. package/scripts/ops/channel-bot-token-migrate.ts +146 -0
  421. package/scripts/ops-health-check.ts +15 -3
  422. package/scripts/pty-scenarios/run.ts +272 -0
  423. package/scripts/public-export.ts +2 -3
  424. package/scripts/public-import-pr.ts +80 -6
  425. package/scripts/public-leak-baseline.txt +0 -7
  426. package/scripts/publish-internal-dist.ts +118 -0
  427. package/scripts/pwa-scenarios.ts +106 -0
  428. package/scripts/rebrand-elanous.ts +1 -1
  429. package/scripts/red-sweep-diff.ts +1 -1
  430. package/scripts/release-loop/auto-approve-node.ts +72 -0
  431. package/scripts/release-loop/cutoff.ts +139 -0
  432. package/scripts/release-loop/docs-land-node.ts +65 -0
  433. package/scripts/release-loop/docs-node.ts +172 -0
  434. package/scripts/release-loop/gate-diff.ts +29 -0
  435. package/scripts/release-loop/gate-node.ts +641 -0
  436. package/scripts/release-loop/node-verdict.ts +85 -0
  437. package/scripts/release-loop/prepare-node.ts +31 -0
  438. package/scripts/release-loop/publish-node.ts +61 -0
  439. package/scripts/release-loop/pwa-node-verdict.ts +45 -0
  440. package/scripts/release-loop/pwa-scenarios-node.ts +140 -0
  441. package/scripts/release-loop/release-docs.ts +109 -0
  442. package/scripts/release-loop/test-durations.ts +63 -0
  443. package/scripts/release-loop/tui-node-checks.ts +29 -0
  444. package/scripts/release-loop/tui-sim-node.ts +113 -0
  445. package/scripts/release-loop/upgrade-node.ts +26 -0
  446. package/scripts/release-loop/verify-node.ts +21 -0
  447. package/scripts/release-loop/version-node.ts +147 -0
  448. package/scripts/release-upgrade-check.sh +53 -0
  449. package/scripts/se-mission-prepare.ts +9 -15
  450. package/scripts/test-audit-coverage-per-file.sh +16 -0
  451. package/scripts/test-audit-meaningless.ts +88 -0
  452. package/scripts/test-audit-overlap-and-weak.ts +73 -0
  453. package/scripts/test-deterministic.ts +29 -6
  454. package/scripts/tui-sim.ts +59 -14
  455. package/scripts/uninstall.sh +10 -3
  456. package/scripts/ux/bump-installed.sh +20 -0
  457. package/scripts/ux/lib/cdp.ts +72 -0
  458. package/scripts/ux/record-page.ts +50 -0
  459. package/scripts/video-broll-line.ts +89 -0
  460. package/scripts/waitlist-daily-digest.ts +108 -0
  461. package/scripts/window-landings.sh +1 -1
  462. package/skills/explainer-video/SKILL.md +99 -0
  463. package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -0
  464. package/skills/explainer-video/engine/build.mjs +431 -0
  465. package/skills/explainer-video/engine/vo.ts +37 -0
  466. package/skills/explainer-video/examples/elanous-0.2.5/script.json +155 -0
  467. package/skills/motion-broll/LICENSE +25 -0
  468. package/skills/motion-broll/SKILL.md +150 -0
  469. package/skills/motion-broll/SOURCE.md +6 -0
  470. package/skills/motion-broll/engine/base.css +19 -0
  471. package/skills/motion-broll/engine/beats.js +11 -0
  472. package/skills/motion-broll/engine/build.py +21 -0
  473. package/skills/motion-broll/engine/fonts/Geist-Variable.woff2 +0 -0
  474. package/skills/motion-broll/engine/fonts/GeistMono-Medium.woff2 +0 -0
  475. package/skills/motion-broll/engine/fonts/OFL-Geist.txt +92 -0
  476. package/skills/motion-broll/engine/motion.js +146 -0
  477. package/skills/motion-broll/engine/render.js +22 -0
  478. package/skills/motion-broll/examples/opus-aoe2/01-opus-drop.html +41 -0
  479. package/skills/motion-broll/examples/opus-aoe2/02-pip-builds.html +110 -0
  480. package/skills/motion-broll/examples/opus-aoe2/03-effort-slider.html +38 -0
  481. package/skills/motion-broll/examples/opus-aoe2/04-master-prompt.html +56 -0
  482. package/skills/motion-broll/examples/opus-aoe2/05-low-vs-max.html +49 -0
  483. package/skills/motion-broll/examples/opus-aoe2/06-chapter.html +18 -0
  484. package/skills/motion-broll/examples/opus-aoe2/plan.json +14 -0
  485. package/skills/motion-broll/reference/engine-api.md +106 -0
  486. package/skills/motion-broll/scripts/composite.py +14 -0
  487. package/skills/motion-broll/scripts/inspect_video.py +34 -0
  488. package/skills/motion-broll/scripts/make_pages.py +34 -0
  489. package/skills/motion-broll/scripts/setup.sh +16 -0
  490. package/skills/motion-broll/scripts/words.py +13 -0
  491. package/skills/motion-broll/templates/compare.html +135 -0
  492. package/skills/motion-broll/templates/viewer.html +97 -0
  493. package/skills/omni-digest/SKILL.md +260 -0
  494. package/skills/omni-digest/digest.md +197 -0
  495. package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +32 -0
  496. package/skills/omni-digest/package-lock.json +558 -0
  497. package/skills/omni-digest/package.json +13 -0
  498. package/skills/omni-digest/scripts/main.ts +404 -0
  499. package/skills/omni-digest/src/delegate.ts +34 -0
  500. package/skills/omni-digest/src/detect.ts +46 -0
  501. package/skills/omni-digest/src/diagram.ts +72 -0
  502. package/skills/omni-digest/src/domain-staging.ts +50 -0
  503. package/skills/omni-digest/src/env.ts +38 -0
  504. package/skills/omni-digest/src/fetch.ts +237 -0
  505. package/skills/omni-digest/src/media.ts +180 -0
  506. package/skills/omni-digest/src/obsidian.ts +69 -0
  507. package/skills/omni-digest/src/ocr.ts +149 -0
  508. package/skills/omni-digest/src/router.ts +60 -0
  509. package/skills/omni-digest/src/summarize.ts +87 -0
  510. package/skills/omni-digest/src/types.ts +124 -0
  511. package/skills/omni-digest/src/util.ts +34 -0
  512. package/skills/omni-digest/src/visual.ts +129 -0
  513. package/skills/omni-digest/src/x-api.ts +151 -0
  514. package/skills/omni-digest/tsconfig.json +13 -0
  515. package/src/a2a/agent-card.ts +29 -0
  516. package/src/a2a/server.ts +173 -0
  517. package/src/acp/auto-persist.ts +3 -6
  518. package/src/acp/backend-registry.ts +6 -10
  519. package/src/acp/channel-browser-shell.ts +1 -535
  520. package/src/acp/client.ts +106 -36
  521. package/src/acp/fs-roots.ts +20 -4
  522. package/src/acp/obsidian-tags.ts +6 -3
  523. package/src/acp/server.ts +189 -32
  524. package/src/agent/nested-agent-env.ts +1 -0
  525. package/src/agent/pty-binding.ts +1 -1
  526. package/src/agent/spawn-embodied-agent-in-vw.ts +5 -336
  527. package/src/agent/subagent-callable.ts +39 -1
  528. package/src/agent-mission/browser-login.ts +241 -0
  529. package/src/agent-mission/capabilities-cli.ts +33 -0
  530. package/src/agent-mission/capability-matrix.ts +31 -0
  531. package/src/agent-mission/capability-readers.ts +79 -0
  532. package/src/agent-mission/capability-types.ts +15 -0
  533. package/src/agent-mission/claude-headless.ts +131 -0
  534. package/src/agent-mission/claude-subscription.ts +57 -0
  535. package/src/agent-mission/doc-guided-install.ts +185 -0
  536. package/src/agent-mission/driver.ts +900 -69
  537. package/src/agent-mission/env-profile.ts +68 -0
  538. package/src/agent-mission/handoff.ts +128 -0
  539. package/src/agent-mission/in-agent-plugin.ts +311 -0
  540. package/src/agent-mission/mission-cli.ts +25 -1
  541. package/src/agent-mission/parse.ts +9 -4
  542. package/src/agent-mission/pr-review-watch.ts +62 -13
  543. package/src/agent-mission/resource-ladder.ts +235 -0
  544. package/src/agent-mission/tool-install.ts +249 -0
  545. package/src/agent-mission/tool-ladder.ts +37 -0
  546. package/src/agent-room/room-builder.ts +6 -600
  547. package/src/agent-substrate/review-intent.ts +43 -1
  548. package/src/auth/acp-token.ts +16 -0
  549. package/src/auth/github-app-token.ts +112 -0
  550. package/src/auth/scope.ts +8 -4
  551. package/src/auth/temp-tokens.ts +131 -0
  552. package/src/auto-research/obsidian-bridge.ts +2 -0
  553. package/src/autopilot/build/integrity-gate.ts +27 -4
  554. package/src/autopilot/build/isolated-instance.ts +2 -1
  555. package/src/autopilot/build/llm-conflict-merge.ts +27 -0
  556. package/src/autopilot/gh-rest-fallback.ts +177 -0
  557. package/src/autopilot/llm-control-brain.ts +54 -12
  558. package/src/autopilot/mission-engine.ts +15 -1
  559. package/src/autopilot/mission-notify.ts +4 -2
  560. package/src/autopilot/mission-origin.ts +5 -5
  561. package/src/autopilot/mission-phase-track.ts +52 -0
  562. package/src/autopilot/mission-tool.ts +1 -1
  563. package/src/autopilot/pr-manager.ts +51 -4
  564. package/src/autopilot/pty-control-loop.ts +94 -2
  565. package/src/autopilot/track-agent.ts +138 -0
  566. package/src/autopilot/track-courier.ts +153 -0
  567. package/src/boot/acp-server.ts +18 -18
  568. package/src/boot/check-same-origin.ts +19 -5
  569. package/src/boot/daemon-multi-llm-runtime.ts +14 -8
  570. package/src/boot/daemon-prompt-turn.ts +2 -0
  571. package/src/boot/daemon-runtime.ts +36 -14
  572. package/src/boot/daemon-tools/index.ts +16 -0
  573. package/src/boot/daemon-tools/self-implement.ts +4 -0
  574. package/src/boot/daemon-tools/types.ts +3 -0
  575. package/src/boot/daemon-tools/web-search.ts +2 -1
  576. package/src/boot/ws-bridge.ts +11 -0
  577. package/src/browser-cdp/chrome-flags.ts +7 -0
  578. package/src/browser-cdp/client.ts +2 -0
  579. package/src/browser-pane/mount.ts +1 -246
  580. package/src/budget/codex-reset-credit-state.ts +15 -0
  581. package/src/budget/fetchers/codex.ts +2 -1
  582. package/src/budget/run-usage-rollup.ts +11 -4
  583. package/src/budget/unified-usage.ts +2 -1
  584. package/src/capture/tui-self-report.ts +10 -0
  585. package/src/channel-bot-token.ts +126 -0
  586. package/src/chat/index.ts +57 -52
  587. package/src/chat/input-text-key.ts +2 -2
  588. package/src/chat/log-scroll-key.ts +12 -0
  589. package/src/chat/mode/manual.ts +2 -4
  590. package/src/chat/pickers/state.ts +10 -27
  591. package/src/chat/search/modal.ts +14 -2
  592. package/src/chat/submit-trace.ts +30 -0
  593. package/src/chat/tool-render/types.ts +1 -1
  594. package/src/chat/turn-typeahead.ts +2 -1
  595. package/src/chat/wrap.ts +6 -8
  596. package/src/cli/__fixtures__/agent-help-before/agent.txt +18 -0
  597. package/src/cli/__fixtures__/agent-help-before/registry.txt +13 -0
  598. package/src/cli/__fixtures__/agent-help-before/root.txt +100 -0
  599. package/src/cli/__fixtures__/agent-help-before/tier.txt +15 -0
  600. package/src/cli/a2a-cli.ts +52 -0
  601. package/src/cli/agent-cli.ts +726 -0
  602. package/src/cli/autopilot-cli.ts +739 -0
  603. package/src/cli/bg-launch.ts +20 -4
  604. package/src/cli/claude-plugin-setup.ts +199 -0
  605. package/src/cli/config-test-sync.ts +94 -10
  606. package/src/cli/connector-cli.ts +204 -0
  607. package/src/cli/control-cli.ts +220 -0
  608. package/src/cli/control-join-cli.ts +142 -0
  609. package/src/cli/decisions-cli.ts +94 -0
  610. package/src/cli/docs-cli.ts +38 -0
  611. package/src/cli/doctor-cli.ts +262 -77
  612. package/src/cli/doctor-distro.ts +17 -1
  613. package/src/cli/doctor-fix.ts +145 -17
  614. package/src/cli/doctor-llm-assist.ts +71 -0
  615. package/src/cli/doctor-private-files.ts +66 -0
  616. package/src/cli/doctor-readiness.ts +23 -28
  617. package/src/cli/fleet-cli.ts +63 -0
  618. package/src/cli/g6a-registration-probe.ts +16 -0
  619. package/src/cli/git-install-plan.ts +51 -0
  620. package/src/cli/hooks-cli.ts +44 -0
  621. package/src/cli/ingest-token-cli.ts +21 -0
  622. package/src/cli/intake-cli.ts +416 -0
  623. package/src/cli/labels-cli.ts +74 -0
  624. package/src/cli/leader-cli.ts +10 -159
  625. package/src/cli/live-cli.ts +48 -0
  626. package/src/cli/llm-detect-cli.ts +130 -0
  627. package/src/cli/logs-cli.ts +231 -7
  628. package/src/cli/machine-cli.ts +38 -0
  629. package/src/cli/mcp-call.ts +52 -13
  630. package/src/cli/mcp-gateway-cli.ts +94 -0
  631. package/src/cli/mcp-login.ts +116 -8
  632. package/src/cli/mcp-reload.ts +20 -3
  633. package/src/cli/nexus-dist.ts +18 -13
  634. package/src/cli/nexus-ios-bind.ts +20 -7
  635. package/src/cli/ops-cli.ts +225 -0
  636. package/src/cli/plugin-cli.ts +201 -0
  637. package/src/cli/pod-cli.ts +83 -0
  638. package/src/cli/port-lease-local.ts +124 -0
  639. package/src/cli/pr-cli.ts +12 -1
  640. package/src/cli/pr-lineage.ts +2 -1
  641. package/src/cli/provider-cli.ts +720 -0
  642. package/src/cli/pty-record-cli.ts +63 -0
  643. package/src/cli/pty-takeover-cli.ts +57 -40
  644. package/src/cli/pty-web-address.ts +52 -0
  645. package/src/cli/publish-cli.ts +44 -0
  646. package/src/cli/pwa-build.ts +18 -12
  647. package/src/cli/pwa-dev.ts +13 -8
  648. package/src/cli/pwa-registry.ts +6 -0
  649. package/src/cli/pwa-share.ts +65 -22
  650. package/src/cli/pwa-show.ts +20 -4
  651. package/src/cli/pwa-start.ts +102 -27
  652. package/src/cli/pwa-test.ts +201 -96
  653. package/src/cli/release-cli.ts +177 -7
  654. package/src/cli/remotes-cli.ts +20 -1
  655. package/src/cli/remotes.ts +2 -1
  656. package/src/cli/repo-cli.ts +315 -36
  657. package/src/cli/research-cli.ts +66 -0
  658. package/src/cli/role-cli.ts +320 -0
  659. package/src/cli/schedule-cli.ts +246 -0
  660. package/src/cli/self-update.ts +103 -12
  661. package/src/cli/setup-cli.ts +64 -2
  662. package/src/cli/shadow-cli.ts +188 -0
  663. package/src/cli/share-auto-mount.ts +12 -8
  664. package/src/cli/start-cli.ts +240 -0
  665. package/src/cli/stdout-flush.ts +8 -0
  666. package/src/cli/storage-cli.ts +334 -0
  667. package/src/cli/tailscale-serve.ts +34 -19
  668. package/src/cli/tasks-cli.ts +176 -0
  669. package/src/cli/test-state-dir-flag.ts +1 -1
  670. package/src/cli/usage-cli.ts +15 -4
  671. package/src/cli/where-cli.ts +22 -55
  672. package/src/code-edit/diff-render.ts +6 -32
  673. package/src/code-edit/source-delta-browser.ts +0 -1
  674. package/src/codex/models.ts +1 -1
  675. package/src/config.ts +8 -13
  676. package/src/connectors/event-ledger.ts +41 -0
  677. package/src/connectors/linear-projector.ts +88 -0
  678. package/src/connectors/linear.ts +143 -0
  679. package/src/connectors/types.ts +19 -0
  680. package/src/control-plane/lease-holder.ts +41 -0
  681. package/src/control-plane/ledger.ts +146 -0
  682. package/src/control-plane/light-member.ts +164 -0
  683. package/src/control-plane/member-tokens.ts +88 -0
  684. package/src/control-plane/member.ts +159 -0
  685. package/src/control-plane/port-lease-heartbeat.ts +101 -0
  686. package/src/control-plane/ports.ts +40 -0
  687. package/src/control-plane/primary.ts +169 -0
  688. package/src/control-plane/server.ts +216 -0
  689. package/src/dashboard/acp-boot.ts +14 -38
  690. package/src/dashboard/assistant-render-state-runtime.ts +2 -2
  691. package/src/dashboard/assistant-sample-runtime.ts +2 -2
  692. package/src/dashboard/auto-compact-runtime.ts +11 -16
  693. package/src/dashboard/browser-help-runtime.ts +2 -3
  694. package/src/dashboard/chat/acp-chat.ts +2 -5
  695. package/src/dashboard/code-edit-post-turn-runtime.ts +1 -2
  696. package/src/dashboard/compact-surface-assembly.ts +0 -14
  697. package/src/dashboard/compact-surface-dispatch.ts +1 -38
  698. package/src/dashboard/compact-surface-inventory.ts +0 -8
  699. package/src/dashboard/compact-surface-runtime.ts +0 -14
  700. package/src/dashboard/context-menu-provider-boot.ts +0 -9
  701. package/src/dashboard/context-window-runtime-boot.ts +0 -37
  702. package/src/dashboard/index.ts +331 -2562
  703. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +0 -6
  704. package/src/dashboard/input/chat-main-slash-command.ts +2 -2
  705. package/src/dashboard/input/dashboard-priority-key-route.ts +1 -43
  706. package/src/dashboard/input/mouse-modal-surface-runtime.ts +1 -5
  707. package/src/dashboard/input/mouse-wiring.ts +2 -3
  708. package/src/dashboard/input/no-provider-reply.ts +13 -0
  709. package/src/dashboard/layout-display-runtime-registration.ts +0 -10
  710. package/src/dashboard/modals/pane-multi.ts +1 -1
  711. package/src/dashboard/replay-preview.ts +1 -1
  712. package/src/dashboard/runtime/approvers.ts +0 -1
  713. package/src/dashboard/runtime/state-snapshot.ts +0 -90
  714. package/src/dashboard/scenario-runtime-boot.ts +16 -16
  715. package/src/dashboard/slash-runtime/dashboard-handlers.ts +134 -1456
  716. package/src/dashboard/slash-runtime/design-pick.ts +96 -0
  717. package/src/dashboard/slash-runtime/help-from-registry.ts +77 -0
  718. package/src/dashboard/slash-runtime/unknown-slash-reply.ts +78 -0
  719. package/src/dashboard/stale-install-check.ts +77 -0
  720. package/src/dashboard/surface-registry-wiring.ts +2 -15
  721. package/src/dashboard/turn-message-runtime.ts +0 -4
  722. package/src/dashboard/turn-preamble.ts +1 -1
  723. package/src/dashboard/turn-stream-formatter.ts +2 -2
  724. package/src/dashboard/turn-stream-runtime.ts +2 -2
  725. package/src/dashboard-pane-context-menu.ts +0 -14
  726. package/src/debug/log.ts +7 -0
  727. package/src/decide/boundary-shadow.ts +131 -0
  728. package/src/decisions/decision-ledger.ts +404 -0
  729. package/src/design/apply-direction.ts +209 -0
  730. package/src/design/css-root-tokens.ts +89 -0
  731. package/src/design/custom-system-create.ts +230 -0
  732. package/src/design/design-directions.ts +61 -41
  733. package/src/design/design-gate.ts +241 -0
  734. package/src/design/design-library.ts +57 -0
  735. package/src/design/design-previews.ts +138 -0
  736. package/src/design/design-systems.ts +61 -0
  737. package/src/design/lint-artifact-run.ts +46 -6
  738. package/src/design/lint-artifact.ts +5 -1
  739. package/src/design/open-design-client.ts +247 -0
  740. package/src/design/system-from-extract.ts +767 -0
  741. package/src/design/system-schema.ts +123 -0
  742. package/src/discord-slash-wire.ts +2 -1
  743. package/src/discord-test-runner.ts +2 -1
  744. package/src/discord-voice-wire.ts +2 -1
  745. package/src/discord.ts +1 -1
  746. package/src/dispatch/opportunistic-launcher.ts +24 -1
  747. package/src/domains/ops-status.ts +35 -2
  748. package/src/domains/outbound-alert.ts +24 -6
  749. package/src/domains/repeated-failure.ts +89 -0
  750. package/src/domains/schedule-manage-tool.ts +28 -8
  751. package/src/domains/schedule-migrate.ts +22 -4
  752. package/src/domains/schedule-registry.ts +88 -33
  753. package/src/domains/schedule-runs.ts +132 -0
  754. package/src/domains/schedule-state.ts +152 -0
  755. package/src/domains/telegram-kind-route.ts +21 -0
  756. package/src/element-registry/address.ts +1 -3
  757. package/src/execution-loop/dispatch-task.ts +139 -0
  758. package/src/execution-loop/gate-decision-summary.ts +29 -0
  759. package/src/execution-loop/gates.ts +197 -0
  760. package/src/git-fs/gh-cli.ts +47 -17
  761. package/src/git-fs/retry.ts +1 -0
  762. package/src/git-fs/runner.ts +1 -0
  763. package/src/git-fs/worktree.ts +6 -5
  764. package/src/github/pr-labels.ts +68 -0
  765. package/src/graph-kinds/installed-plugin-nodes.ts +95 -0
  766. package/src/graph-kinds/plugin-nodes.ts +68 -0
  767. package/src/graph-kinds/registry.ts +118 -0
  768. package/src/graph-runner/graph-cli.ts +103 -0
  769. package/src/graph-runner/graph-notify.ts +220 -0
  770. package/src/graph-runner/graph-tick.ts +119 -0
  771. package/src/graph-runner/release-manifest.ts +93 -0
  772. package/src/graph-runner/runner.ts +487 -0
  773. package/src/grok/credential.ts +158 -5
  774. package/src/grounding/ensure-grounding.ts +131 -0
  775. package/src/grounding/mirror-export.ts +89 -0
  776. package/src/grounding/mirror-manifest.ts +252 -0
  777. package/src/grounding/sources-cli.ts +209 -0
  778. package/src/grounding/sources.ts +333 -0
  779. package/src/grounding/token.ts +121 -0
  780. package/src/harness/harness-cli-command.ts +415 -23
  781. package/src/harness/harness-pod-dispatch.ts +116 -0
  782. package/src/harness/harness-stop.ts +260 -0
  783. package/src/harness/harness-substrate-default.ts +40 -0
  784. package/src/harness/harness-worktrees.ts +1 -1
  785. package/src/harness/harness-write-boundary.ts +2 -0
  786. package/src/harness/llm-decompose.ts +2 -1
  787. package/src/harness/self-send-decide.ts +233 -0
  788. package/src/harness/self-send-target.ts +22 -1
  789. package/src/harness/shell-relay.ts +5 -0
  790. package/src/harness/worktree-branch-prefix.ts +4 -3
  791. package/src/hooks/providers.ts +77 -0
  792. package/src/hooks/queue.ts +73 -0
  793. package/src/hooks/receiver.ts +133 -0
  794. package/src/index.ts +712 -3409
  795. package/src/input-core/dispatcher.ts +1 -1
  796. package/src/input-core/drag-esc-interceptor.ts +1 -1
  797. package/src/instance/current.ts +5 -5
  798. package/src/instance/leader.ts +10 -326
  799. package/src/instance/nexus-run-refusal.ts +27 -92
  800. package/src/instance/project-local-exclude.ts +27 -0
  801. package/src/instance/resolve.ts +46 -175
  802. package/src/intake-plane/capture.ts +14 -1
  803. package/src/intake-plane/check.ts +34 -14
  804. package/src/intake-plane/collect-github.ts +258 -0
  805. package/src/intake-plane/collect-pod.ts +100 -0
  806. package/src/intake-plane/collect-telegram-saved.ts +91 -0
  807. package/src/intake-plane/digest.ts +111 -0
  808. package/src/intake-plane/enrich-plugins.ts +1 -1
  809. package/src/intake-plane/front-classifier.ts +56 -0
  810. package/src/intake-plane/front-route-classifier.ts +80 -0
  811. package/src/intake-plane/front-route-rules.ts +152 -0
  812. package/src/intake-plane/grounding-docs.ts +185 -0
  813. package/src/intake-plane/harness-target.ts +20 -0
  814. package/src/intake-plane/intake-to-tasks.ts +303 -0
  815. package/src/intake-plane/items.ts +247 -0
  816. package/src/intake-plane/link-ledger.ts +27 -0
  817. package/src/intake-plane/route.ts +104 -0
  818. package/src/intake-plane/runtime-callables.ts +3 -1
  819. package/src/intake-plane/sketch-ledger.ts +34 -0
  820. package/src/intake-plane/slash.ts +30 -2
  821. package/src/intake-plane/submit-intake-work.ts +160 -0
  822. package/src/intake-plane/telegram-work.ts +56 -0
  823. package/src/iul/sidebar-shell.ts +0 -165
  824. package/src/launch-head/capability-check.ts +162 -0
  825. package/src/launch-head/launch-head-cli.ts +242 -0
  826. package/src/launch-head/load-balance.ts +81 -0
  827. package/src/live/detail-switch.ts +180 -0
  828. package/src/llm/provider-detect.ts +247 -0
  829. package/src/llm/provider-probe.ts +57 -0
  830. package/src/llm/usable-llm.ts +32 -0
  831. package/src/llm.ts +55 -23
  832. package/src/log-entry.ts +1 -1
  833. package/src/log-pane/attachment-popup.ts +1 -2
  834. package/src/loops/loop-cli.ts +37 -0
  835. package/src/loops/registry.ts +196 -0
  836. package/src/market/official-keys.ts +5 -0
  837. package/src/market/publish.ts +329 -0
  838. package/src/market/signed-index.ts +156 -0
  839. package/src/market/tgz.ts +121 -0
  840. package/src/mcp/client.ts +1 -1
  841. package/src/mcp/mcp-oauth.ts +40 -5
  842. package/src/mcp/server.ts +75 -7
  843. package/src/mcp-gateway/gateway.ts +128 -0
  844. package/src/mcp-gateway/pat-store.ts +124 -0
  845. package/src/mss/logging/log-store.ts +91 -2
  846. package/src/mss/logging/scoped-level.ts +5 -9
  847. package/src/native-tool-catalog.ts +66 -345
  848. package/src/nexus/api/connect-info.ts +23 -25
  849. package/src/nexus/api/context-url.ts +1 -1
  850. package/src/nexus/api/design-check.ts +90 -59
  851. package/src/nexus/api/design-previews-route.ts +182 -0
  852. package/src/nexus/api/design-system-create-route.ts +123 -0
  853. package/src/nexus/api/graph-approvals.ts +125 -0
  854. package/src/nexus/api/graph-kinds.ts +69 -0
  855. package/src/nexus/api/graphs-api.ts +221 -0
  856. package/src/nexus/api/harness-api.ts +31 -2
  857. package/src/nexus/api/health.ts +15 -0
  858. package/src/nexus/api/http-server.ts +328 -43
  859. package/src/nexus/api/image-generate.ts +3 -0
  860. package/src/nexus/api/ingest-token.ts +175 -0
  861. package/src/nexus/api/intake-ledger-api.ts +54 -0
  862. package/src/nexus/api/intake-route.ts +111 -0
  863. package/src/nexus/api/json-response.ts +33 -0
  864. package/src/nexus/api/live-detail.ts +47 -0
  865. package/src/nexus/api/live-shipped.ts +78 -0
  866. package/src/nexus/api/log-fabric.ts +42 -2
  867. package/src/nexus/api/markdown-publish.ts +3 -2
  868. package/src/nexus/api/mcp-http.ts +14 -9
  869. package/src/nexus/api/mcp-oauth-hint.ts +31 -0
  870. package/src/nexus/api/mcp-public-allowlist.ts +33 -0
  871. package/src/nexus/api/merge-approvals-gate.ts +79 -0
  872. package/src/nexus/api/merge-approvals.ts +307 -0
  873. package/src/nexus/api/meta-api.ts +18 -0
  874. package/src/nexus/api/next-fluent-wiring.ts +7 -9
  875. package/src/nexus/api/plugins-credentials-api.ts +47 -0
  876. package/src/nexus/api/plugins-market.ts +209 -0
  877. package/src/nexus/api/pod-credential-api.ts +187 -0
  878. package/src/nexus/api/public-routes.ts +87 -0
  879. package/src/nexus/api/rest-route-paths.ts +15 -0
  880. package/src/nexus/api/schedules-action.ts +12 -3
  881. package/src/nexus/api/schedules-read.ts +228 -0
  882. package/src/nexus/api/sessions-store.ts +8 -2
  883. package/src/nexus/api/setup-answer-priority.ts +130 -0
  884. package/src/nexus/api/setup-channel-bot.ts +56 -0
  885. package/src/nexus/api/setup-child-llm.ts +228 -0
  886. package/src/nexus/api/setup-obsidian-skills.ts +93 -0
  887. package/src/nexus/api/task-cards-api.ts +34 -0
  888. package/src/nexus/api/tasks-create.ts +136 -0
  889. package/src/nexus/api/telegram-trigger-bot.ts +3 -3
  890. package/src/nexus/api/terminals.ts +204 -18
  891. package/src/nexus/api/trace.ts +405 -0
  892. package/src/nexus/api/vault-api.ts +140 -7
  893. package/src/nexus/api/worktrees.ts +18 -2
  894. package/src/nexus/boot/register-mcp-clients.ts +135 -16
  895. package/src/nexus/daemon-endpoint.ts +85 -0
  896. package/src/nexus/default-port.ts +1 -0
  897. package/src/nexus/index.ts +362 -143
  898. package/src/nexus/onboarding/pwa-share-prompt.ts +31 -8
  899. package/src/nexus/onboarding/tailscale-probe.ts +9 -1
  900. package/src/nexus/outbound/router.ts +1 -1
  901. package/src/nexus/setup-status.ts +58 -0
  902. package/src/nexus/supervisor/lock.ts +8 -0
  903. package/src/nexus/webterm/pty.ts +15 -0
  904. package/src/oauth/codex-account-rotation.ts +122 -16
  905. package/src/oauth/codex-account-store.ts +88 -19
  906. package/src/oauth/codex-quota-policy.ts +55 -0
  907. package/src/oauth/store.ts +28 -25
  908. package/src/obsidian/default-vault.ts +17 -0
  909. package/src/obsidian/vault-write-guard.ts +46 -0
  910. package/src/onboarding/help/llm.md +2 -2
  911. package/src/onboarding.ts +27 -4
  912. package/src/panes/alt-skip-predicate.ts +4 -3
  913. package/src/panes/external-terminal-pane.ts +3 -4
  914. package/src/panes/factory.ts +1 -18
  915. package/src/panes/index.ts +1 -5
  916. package/src/panes/pane-cycle.ts +1 -1
  917. package/src/panes/types.ts +1 -1
  918. package/src/platform/env-literal.ts +4 -0
  919. package/src/plugin-hooks/dispatcher.ts +10 -4
  920. package/src/plugins/core/host.ts +108 -4
  921. package/src/plugins/core/manifest.ts +104 -7
  922. package/src/plugins/install/market-fetch.ts +250 -0
  923. package/src/plugins/install/plugin-credentials.ts +106 -0
  924. package/src/plugins/install/plugin-install.ts +518 -0
  925. package/src/policy/claude-subscription-guard.ts +25 -0
  926. package/src/preview/terminal.ts +24 -1
  927. package/src/preview-pane/mount.ts +1 -142
  928. package/src/prompt/references.ts +4 -51
  929. package/src/prompt-library/universal-preamble.ts +8 -2
  930. package/src/pty-shell/pty-control-ipc.ts +57 -3
  931. package/src/pty-shell/pty-mouse.ts +75 -0
  932. package/src/pty-shell/pty-recording.ts +108 -0
  933. package/src/pty-shell/registry.ts +53 -3
  934. package/src/python/resolve-python.ts +1 -1
  935. package/src/release-loop/checklist.ts +191 -0
  936. package/src/release-loop/manifest.ts +65 -0
  937. package/src/release-loop/release-note.ts +177 -0
  938. package/src/roles/lease-cas.ts +52 -0
  939. package/src/roles/machine-name.ts +48 -0
  940. package/src/roles/machine-profile.ts +65 -0
  941. package/src/roles/role-lease-read.ts +81 -0
  942. package/src/roles/role-lease.ts +63 -0
  943. package/src/roles/role-watch.ts +69 -0
  944. package/src/self-dev/ask-launch-flow.ts +39 -22
  945. package/src/self-dev/ask-launch-io.ts +1 -1
  946. package/src/self-dev/dev-cli.ts +290 -159
  947. package/src/self-dev/dev-pipeline.ts +157 -9
  948. package/src/self-dev/draft-sweep.ts +231 -0
  949. package/src/self-dev/draft-triage-rules.ts +42 -0
  950. package/src/self-dev/entrance-baseline.ts +156 -4
  951. package/src/self-dev/fabric-decompose-adapter.ts +10 -0
  952. package/src/self-dev/launch-preflight.ts +1 -1
  953. package/src/self-dev/orchestrate.ts +297 -20
  954. package/src/self-dev/repair-signals.ts +6 -0
  955. package/src/self-dev/run-store.ts +20 -5
  956. package/src/self-dev/run-supervisor.ts +43 -3
  957. package/src/self-implement/abandoned-classification.ts +15 -1
  958. package/src/self-implement/blocked-draft-policy.ts +6 -0
  959. package/src/self-implement/budget-gate.ts +236 -0
  960. package/src/self-implement/child-llm-preference.ts +84 -0
  961. package/src/self-implement/decision-events.ts +57 -0
  962. package/src/self-implement/decision-signal-press.ts +5 -2
  963. package/src/self-implement/dependency-change-gate.ts +90 -0
  964. package/src/self-implement/gate-baseline.ts +35 -2
  965. package/src/self-implement/gate-cli.ts +29 -7
  966. package/src/self-implement/gate-scope.ts +7 -1
  967. package/src/self-implement/goal-author-decompose.ts +22 -4
  968. package/src/self-implement/goal-author.ts +41 -3
  969. package/src/self-implement/goal-boundary.ts +65 -0
  970. package/src/self-implement/goal-clarification-escalation.ts +1 -0
  971. package/src/self-implement/goal-documents-dir.ts +6 -1
  972. package/src/self-implement/goal-execution-records.ts +58 -0
  973. package/src/self-implement/goal-run-store.ts +42 -24
  974. package/src/self-implement/graph-authority.ts +13 -28
  975. package/src/self-implement/graph-catalog.ts +48 -0
  976. package/src/self-implement/graph-run-contract.ts +127 -0
  977. package/src/self-implement/graph-templates.ts +14 -7
  978. package/src/self-implement/graph-yaml.ts +35 -6
  979. package/src/self-implement/harness-policy-gates.ts +42 -0
  980. package/src/self-implement/headless-elanous-driver.ts +30 -6
  981. package/src/self-implement/heal-triage.ts +229 -0
  982. package/src/self-implement/host-regate.ts +244 -0
  983. package/src/self-implement/non-git-consent.ts +23 -0
  984. package/src/self-implement/orchestrator.ts +488 -134
  985. package/src/self-implement/pipeline-shape.ts +1 -1
  986. package/src/self-implement/pr-evidence-artifact.ts +6 -19
  987. package/src/self-implement/prior-draft-findings.ts +128 -0
  988. package/src/self-implement/pwa-import-graph.ts +65 -0
  989. package/src/self-implement/repo-provision.ts +18 -21
  990. package/src/self-implement/report-origin.ts +39 -0
  991. package/src/self-implement/rework-policy.ts +21 -0
  992. package/src/self-implement/run-ledger-compact.ts +438 -0
  993. package/src/self-implement/run-ledger.ts +212 -29
  994. package/src/self-implement/run-report.ts +24 -0
  995. package/src/self-implement/run-status-mapping.ts +2 -0
  996. package/src/self-implement/running-runs.ts +112 -14
  997. package/src/self-implement/scoped-typecheck-config.ts +49 -0
  998. package/src/self-implement/seams.ts +207 -40
  999. package/src/self-implement/self-implement-cli.ts +17 -2
  1000. package/src/self-implement/shadow-repo.ts +350 -0
  1001. package/src/self-implement/supervision-vocabulary.ts +7 -0
  1002. package/src/shell-runner/dispatch.ts +3 -0
  1003. package/src/shell-runner/index.ts +0 -7
  1004. package/src/skills/runner.ts +0 -69
  1005. package/src/skills/tools/agent-room-slash.ts +2 -1
  1006. package/src/skills/tools/agent-room.ts +8 -140
  1007. package/src/skills/tools/agent.ts +5 -3
  1008. package/src/skills/tools/context.ts +5 -140
  1009. package/src/skills/tools/control.ts +4 -188
  1010. package/src/skills/tools/dashboard-slash.ts +3 -11
  1011. package/src/skills/tools/dashboard-state.ts +3 -5
  1012. package/src/skills/tools/dev-harness.ts +45 -2
  1013. package/src/skills/tools/omni-search.ts +29 -1
  1014. package/src/skills/tools/shell.ts +11 -29
  1015. package/src/skills/tools/spawn-coding-agent-headless.ts +6 -9
  1016. package/src/ssh/ssh-picker-modal.ts +1 -1
  1017. package/src/steward/directive.ts +99 -0
  1018. package/src/steward/steward-cards.ts +45 -0
  1019. package/src/steward/triage.ts +239 -0
  1020. package/src/storage/cli-bin.ts +67 -0
  1021. package/src/storage/object-store-visibility.ts +169 -0
  1022. package/src/storage/object-store.ts +452 -0
  1023. package/src/storage/s3.ts +53 -10
  1024. package/src/storage/storage-detect.ts +337 -0
  1025. package/src/surface/address.ts +3 -5
  1026. package/src/surface/index.ts +0 -6
  1027. package/src/surface/llm-tools.ts +1 -2
  1028. package/src/surface/shell-runner-boot.ts +4 -89
  1029. package/src/task-cards/card-cli.ts +64 -0
  1030. package/src/task-cards/card-store.ts +241 -0
  1031. package/src/task-orchestrator/boot.ts +27 -1
  1032. package/src/task-orchestrator/dispatcher.ts +49 -7
  1033. package/src/task-orchestrator/external-fingerprint.ts +10 -0
  1034. package/src/task-orchestrator/external-policy.ts +86 -0
  1035. package/src/task-orchestrator/feedback-loop.ts +4 -2
  1036. package/src/task-orchestrator/graph.ts +18 -1
  1037. package/src/task-orchestrator/runtimes/create.ts +128 -0
  1038. package/src/task-orchestrator/store.ts +78 -18
  1039. package/src/task-orchestrator/surface-registry.ts +5 -2
  1040. package/src/task-orchestrator/surfaces/external-exec.ts +180 -0
  1041. package/src/task-orchestrator/surfaces/idea-approval-pr.ts +118 -0
  1042. package/src/task-orchestrator/surfaces/index.ts +4 -3
  1043. package/src/task-orchestrator/surfaces/pod-account-broker.ts +60 -5
  1044. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +194 -0
  1045. package/src/task-orchestrator/surfaces/pod-command-job.ts +369 -0
  1046. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +207 -0
  1047. package/src/task-orchestrator/surfaces/pod-pool.ts +128 -12
  1048. package/src/task-orchestrator/surfaces/pod-skills.ts +11 -3
  1049. package/src/task-orchestrator/surfaces/pod-source-bundle.ts +147 -0
  1050. package/src/task-orchestrator/surfaces/pod-source-receive.ts +129 -0
  1051. package/src/task-orchestrator/surfaces/pod-source-spec.ts +77 -0
  1052. package/src/task-orchestrator/surfaces/self-implement-pod.ts +930 -45
  1053. package/src/task-orchestrator/surfaces/self-implement.ts +8 -1
  1054. package/src/task-orchestrator/tox-loop.ts +204 -0
  1055. package/src/task-orchestrator/types.ts +21 -1
  1056. package/src/telegram-commands.ts +8 -0
  1057. package/src/telegram-report.ts +14 -7
  1058. package/src/telegram-run.ts +18 -5
  1059. package/src/telegram.ts +92 -22
  1060. package/src/tool-runtime/acp-session-runtime.ts +28 -7
  1061. package/src/tool-runtime/agent-runtime.ts +1 -0
  1062. package/src/tool-runtime/context-runtime.ts +18 -35
  1063. package/src/tool-runtime/control-runtime.ts +8 -21
  1064. package/src/tool-runtime/dashboard-state-runtime.ts +1 -5
  1065. package/src/tool-runtime/elanous-asana-runtimes.ts +205 -0
  1066. package/src/tool-runtime/elanous-control-runtimes.ts +16 -2
  1067. package/src/tool-runtime/elanous-task-submit-runtime.ts +124 -0
  1068. package/src/tool-runtime/index.ts +4 -1
  1069. package/src/tool-runtime/scenario-runtimes.ts +22 -21
  1070. package/src/tool-runtime/scenario-target-mount.ts +6 -32
  1071. package/src/tool-runtime/types.ts +8 -0
  1072. package/src/tui/chat/attachment-summary.ts +4 -4
  1073. package/src/tui-client/acp-transport-ws-client.ts +72 -5
  1074. package/src/tui-client/headless-core-guard.ts +0 -1
  1075. package/src/tui.ts +11 -7
  1076. package/src/typecheck-ratchet.ts +15 -0
  1077. package/src/ui/hover-presenter.ts +3 -7
  1078. package/src/user-config.ts +453 -190
  1079. package/src/util/spawn-sync-output.ts +15 -0
  1080. package/src/version/code-revision.ts +34 -9
  1081. package/src/version/packed-revision.json +1 -1
  1082. package/src/video-pipeline/broll-agent.ts +102 -0
  1083. package/src/video-pipeline/recipes/broll.ts +263 -0
  1084. package/src/video-pipeline/walk-line.ts +2 -1
  1085. package/src/views/scratch-image-size.ts +10 -0
  1086. package/src/voice/channel-adapters/pwa-voice-adapter.ts +2 -18
  1087. package/src/voice/channel-adapters/telegram-voice-adapter.ts +1 -6
  1088. package/src/voice/voice-tts-singleton.ts +46 -8
  1089. package/src/web-push/vapid-keys.ts +1 -1
  1090. package/src/web-search/free.ts +77 -0
  1091. package/src/web-search/index.ts +7 -5
  1092. package/src/web-terminal/preview-tap-registry.ts +152 -43
  1093. package/src/workflow-runtime/deps-bridge.ts +4 -3
  1094. package/src/workflow-runtime/executor.ts +18 -22
  1095. package/src/workflow-runtime/node-catalog.ts +20 -1
  1096. package/src/workflow-runtime/nodes/bash.ts +1 -0
  1097. package/src/workflow-runtime/nodes/task.ts +74 -0
  1098. package/src/workflow-runtime/nodes/triggers.ts +24 -1
  1099. package/src/workflow-runtime/plugin-kind-node.ts +166 -0
  1100. package/src/workflow-runtime/schema.ts +98 -2
  1101. package/src/workflow-runtime/triggers/webhook-router.ts +43 -3
  1102. package/src/workflow-runtime/triggers/webhook-source.ts +19 -1
  1103. package/src/workflow-runtime/types.ts +76 -5
  1104. package/apps/pwa/out/_next/static/Ksn99fVf2HUWhSyV1-FC8/_buildManifest.js +0 -1
  1105. package/apps/pwa/out/_next/static/chunks/1176-4943bd83b00e53a2.js +0 -25
  1106. package/apps/pwa/out/_next/static/chunks/1380-9c652e1002032c86.js +0 -1
  1107. package/apps/pwa/out/_next/static/chunks/1863-2ea170dfec26b88b.js +0 -1
  1108. package/apps/pwa/out/_next/static/chunks/2091-2d6b7f4f16300f83.js +0 -1
  1109. package/apps/pwa/out/_next/static/chunks/2347-366617ec73babe3b.js +0 -1
  1110. package/apps/pwa/out/_next/static/chunks/3089-e60cc8f5d35ee239.js +0 -1
  1111. package/apps/pwa/out/_next/static/chunks/3158-c77ed9ea34f9cc9f.js +0 -1
  1112. package/apps/pwa/out/_next/static/chunks/3607-f0b5c5ee18fcf56a.js +0 -1
  1113. package/apps/pwa/out/_next/static/chunks/3659-05b2d5d971b42dbc.js +0 -1
  1114. package/apps/pwa/out/_next/static/chunks/3736-b6a7bfdcb8f56ec6.js +0 -1
  1115. package/apps/pwa/out/_next/static/chunks/3839-eebf298e89a7bb77.js +0 -1
  1116. package/apps/pwa/out/_next/static/chunks/4012.832a2824b978e7ee.js +0 -5
  1117. package/apps/pwa/out/_next/static/chunks/4706-d85d7f3345f3ff91.js +0 -1
  1118. package/apps/pwa/out/_next/static/chunks/526-17a6a2e0e6dc4498.js +0 -1
  1119. package/apps/pwa/out/_next/static/chunks/5508-676ac75f2757ad40.js +0 -1
  1120. package/apps/pwa/out/_next/static/chunks/5583-8a0317f4b8e68db9.js +0 -1
  1121. package/apps/pwa/out/_next/static/chunks/6258-b58f722b10e8d31d.js +0 -1
  1122. package/apps/pwa/out/_next/static/chunks/6820-32fd097e6186fdc9.js +0 -1
  1123. package/apps/pwa/out/_next/static/chunks/6852-983db7ca958634b7.js +0 -1
  1124. package/apps/pwa/out/_next/static/chunks/7235-e583e4a015e159b9.js +0 -1
  1125. package/apps/pwa/out/_next/static/chunks/7482-7b417330b24a996a.js +0 -1
  1126. package/apps/pwa/out/_next/static/chunks/7701-99b7d4dedb955bf8.js +0 -1
  1127. package/apps/pwa/out/_next/static/chunks/77f1928d-bd3777589042d3ea.js +0 -1
  1128. package/apps/pwa/out/_next/static/chunks/8366-36956cafc5e33614.js +0 -1
  1129. package/apps/pwa/out/_next/static/chunks/8370-23d0de995be666f8.js +0 -1
  1130. package/apps/pwa/out/_next/static/chunks/8617-307421f3b0e8b2a2.js +0 -1
  1131. package/apps/pwa/out/_next/static/chunks/8837-e45de46a9fedf1f5.js +0 -1
  1132. package/apps/pwa/out/_next/static/chunks/9058-0e8055a5ea3ebdd6.js +0 -1
  1133. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-84b84eca12acada4.js +0 -1
  1134. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1f23568c29e88f7a.js +0 -1
  1135. package/apps/pwa/out/_next/static/chunks/app/botlab/page-bf6fc9aafd6135a7.js +0 -1
  1136. package/apps/pwa/out/_next/static/chunks/app/bots/page-3f8539ae4b719d2e.js +0 -1
  1137. package/apps/pwa/out/_next/static/chunks/app/chat/page-d2900febb74ecf32.js +0 -1
  1138. package/apps/pwa/out/_next/static/chunks/app/control/page-e82dec647dd79c36.js +0 -1
  1139. package/apps/pwa/out/_next/static/chunks/app/dashboard/page-096ec743a8ee955a.js +0 -1
  1140. package/apps/pwa/out/_next/static/chunks/app/design-check/page-255c2ceded4b3493.js +0 -1
  1141. package/apps/pwa/out/_next/static/chunks/app/healthz/route-84b84eca12acada4.js +0 -1
  1142. package/apps/pwa/out/_next/static/chunks/app/intake/page-2db61b2f9efba61f.js +0 -1
  1143. package/apps/pwa/out/_next/static/chunks/app/layout-e11ee17f221aaa9b.js +0 -1
  1144. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e075974e029ce4c4.js +0 -1
  1145. package/apps/pwa/out/_next/static/chunks/app/morning/page-ec5b68a9af3366a0.js +0 -1
  1146. package/apps/pwa/out/_next/static/chunks/app/not-found-986c177afb4adae6.js +0 -1
  1147. package/apps/pwa/out/_next/static/chunks/app/observatory/page-a72781461af2f2a3.js +0 -1
  1148. package/apps/pwa/out/_next/static/chunks/app/page-92781cbaafc487ad.js +0 -1
  1149. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2c14d2a1f2930f33.js +0 -1
  1150. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-22ee4bf8070b2b4d.js +0 -1
  1151. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9c06e4a8297942a8.js +0 -1
  1152. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d0cd32f6d373798f.js +0 -1
  1153. package/apps/pwa/out/_next/static/chunks/app/settings/page-0c1642018d87ebb8.js +0 -1
  1154. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-93e5e97d614df487.js +0 -1
  1155. package/apps/pwa/out/_next/static/chunks/app/setup/layout-84b84eca12acada4.js +0 -1
  1156. package/apps/pwa/out/_next/static/chunks/app/setup/page-b1ce871940d7393e.js +0 -1
  1157. package/apps/pwa/out/_next/static/chunks/app/share/page-ae154addf345febe.js +0 -1
  1158. package/apps/pwa/out/_next/static/chunks/app/showroom/page-90af3aa813d2053c.js +0 -1
  1159. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f3f962fda428a738.js +0 -1
  1160. package/apps/pwa/out/_next/static/chunks/app/term/page-1c1f7cc1d5def06d.js +0 -1
  1161. package/apps/pwa/out/_next/static/chunks/app/vault/page-09d4cbdaaacf06c1.js +0 -1
  1162. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e877b8e8ca90b27f.js +0 -1
  1163. package/apps/pwa/out/_next/static/chunks/app/workflows/page-71d902f463dea526.js +0 -1
  1164. package/apps/pwa/out/_next/static/chunks/app/workspace/page-40ea576cefa25fe6.js +0 -1
  1165. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a56a3f178c3831f6.js +0 -1
  1166. package/apps/pwa/out/_next/static/chunks/bcc499d1-804a270d878e0842.js +0 -1
  1167. package/apps/pwa/out/_next/static/chunks/framework-b25b7c5501c59b6d.js +0 -1
  1168. package/apps/pwa/out/_next/static/chunks/main-a9ec9da43387afff.js +0 -1
  1169. package/apps/pwa/out/_next/static/chunks/main-app-aa2c05954aaa6754.js +0 -1
  1170. package/apps/pwa/out/_next/static/chunks/pages/_app-bb3768fb4b84aebb.js +0 -1
  1171. package/apps/pwa/out/_next/static/chunks/pages/_error-2820ba75b87b2f5e.js +0 -1
  1172. package/apps/pwa/out/_next/static/chunks/webpack-58c73b145f189b1c.js +0 -1
  1173. package/apps/pwa/out/_next/static/css/effec8adf767aa75.css +0 -1
  1174. package/apps/pwa/out/dashboard/index.html +0 -1
  1175. package/apps/pwa/out/dashboard/index.txt +0 -26
  1176. package/src/acp/resident-shell.ts +0 -244
  1177. package/src/agent/spawn-local-llm-in-vw.ts +0 -240
  1178. package/src/dashboard/agent-spawn-tools-boot.ts +0 -14
  1179. package/src/dashboard/dock-picker-inventory.ts +0 -41
  1180. package/src/dashboard/goal-plan-hud-bridge.ts +0 -112
  1181. package/src/dashboard/hud-mirror.ts +0 -207
  1182. package/src/dashboard/input/mouse-dock-runtime.ts +0 -156
  1183. package/src/dashboard/input/mouse-hover-runtime.ts +0 -46
  1184. package/src/dashboard/input/mouse-pill-context-runtime.ts +0 -74
  1185. package/src/dashboard/input/mouse-workspace-restore-runtime.ts +0 -64
  1186. package/src/dashboard/input/scratch-actions.ts +0 -36
  1187. package/src/dashboard/input/virtual-window-key-router.ts +0 -24
  1188. package/src/dashboard/rich-scratch-viewers.ts +0 -77
  1189. package/src/dashboard/scratch-slash-runtime.ts +0 -36
  1190. package/src/dashboard/scratch-state-runtime.ts +0 -42
  1191. package/src/dashboard/scratch-widget-runtime.ts +0 -37
  1192. package/src/dashboard/sim-shell.ts +0 -313
  1193. package/src/dashboard/virtual-window-control-runtime.ts +0 -57
  1194. package/src/dashboard/virtual-window-help-runtime.ts +0 -113
  1195. package/src/dashboard/virtual-window-input-runtime.ts +0 -99
  1196. package/src/dashboard/virtual-window-mutation-runtime.ts +0 -102
  1197. package/src/dashboard/virtual-window-split-runtime.ts +0 -70
  1198. package/src/dashboard/vw-popup-openers.ts +0 -126
  1199. package/src/dashboard/window-picker-popup.ts +0 -74
  1200. package/src/dashboard/window-slash-runtime.ts +0 -108
  1201. package/src/dashboard/windowing/companion-slash.ts +0 -78
  1202. package/src/dashboard/windowing/fast-switch.ts +0 -138
  1203. package/src/dashboard/windowing/lifecycle.ts +0 -185
  1204. package/src/dashboard/windowing/virtual-windows.ts +0 -259
  1205. package/src/dashboard/windowing/visibility-chord.ts +0 -77
  1206. package/src/iul/resident-vw.ts +0 -55
  1207. package/src/panes/content-adapter.ts +0 -162
  1208. package/src/prompt/vw-reference.ts +0 -153
  1209. package/src/shell-runner/external-terminal-pane.ts +0 -157
  1210. package/src/sim/resident-vw.ts +0 -48
  1211. package/src/skills/tools/spawn-coding-agent-vw.ts +0 -181
  1212. package/src/skills/tools/virtual-windows.ts +0 -632
  1213. package/src/surface/adapters/window-surface-adapter.ts +0 -141
  1214. package/src/tool-runtime/layout-runtimes.ts +0 -81
  1215. package/src/tool-runtime/scenario-window-mount.ts +0 -207
  1216. package/src/views/ui-mode.ts +0 -100
  1217. package/src/virtual-window-context-menu.ts +0 -97
  1218. package/src/virtual-windows/addressing.ts +0 -195
  1219. package/src/virtual-windows/benchmark-preset.ts +0 -119
  1220. package/src/virtual-windows/event-bus.ts +0 -202
  1221. package/src/virtual-windows/layout/apply-planner.ts +0 -189
  1222. package/src/virtual-windows/layout/index.ts +0 -68
  1223. package/src/virtual-windows/layout/layout-commands.ts +0 -186
  1224. package/src/virtual-windows/layout/layout-tools.ts +0 -262
  1225. package/src/virtual-windows/layout/persistence.ts +0 -219
  1226. package/src/virtual-windows/layout/presets.ts +0 -114
  1227. package/src/virtual-windows/layout/restore-planner.ts +0 -223
  1228. package/src/virtual-windows/layout/serializer.ts +0 -197
  1229. package/src/virtual-windows/layout/tree.ts +0 -147
  1230. package/src/virtual-windows/layout/types.ts +0 -63
  1231. package/src/virtual-windows/layout-tree.ts +0 -389
  1232. package/src/virtual-windows/navigation.ts +0 -251
  1233. package/src/virtual-windows/pane-capture.ts +0 -142
  1234. package/src/virtual-windows/pane-content.ts +0 -611
  1235. package/src/virtual-windows/pane-spawner.ts +0 -278
  1236. package/src/virtual-windows/pty-tail-content.ts +0 -291
  1237. package/src/virtual-windows/resident-window.ts +0 -59
  1238. package/src/virtual-windows/secondary-action.ts +0 -25
  1239. package/src/virtual-windows/terminal-slot-content.ts +0 -165
  1240. package/src/virtual-windows/virtual-window.ts +0 -1301
  1241. package/src/virtual-windows/vw-local-input-target-popup.ts +0 -110
  1242. package/src/virtual-windows/vw-rename-modal.ts +0 -77
  1243. package/src/virtual-windows/vw-selector-popup.ts +0 -177
  1244. package/src/virtual-windows/window-registry.ts +0 -519
  1245. package/src/voice/channel-adapters/discord-voice-adapter.ts +0 -202
  1246. package/src/voice/voice-pwa-dispatch.ts +0 -245
  1247. package/src/window-picker-modal.ts +0 -135
  1248. /package/apps/pwa/out/_next/static/{Ksn99fVf2HUWhSyV1-FC8 → ktMqfrBbf8BMGac0jqLrb}/_ssgManifest.js +0 -0
  1249. /package/src/dashboard/{companion-slash-runtime.ts → companion-messages-runtime.ts} +0 -0
@@ -19,6 +19,7 @@ import {
19
19
  type PrEvidenceInput,
20
20
  } from './pr-evidence-artifact.js';
21
21
  import { assessImplementationArtifactCompleteness } from './implementation-artifact-completeness.js';
22
+ import { runContractAtNode, type RunContract } from './graph-run-contract.js';
22
23
  export {
23
24
  PR_EVIDENCE_AXES,
24
25
  composePrEvidenceArtifact,
@@ -59,11 +60,15 @@ export function formatAutoMergeSuccessMessage(input: {
59
60
  }
60
61
 
61
62
  import { GoalRunStore, insertGoalRunRecord, type GoalPriorRuns } from './goal-run-store.js';
63
+ import { writeGoalRunRecordFragment } from './goal-execution-records.js';
64
+ import { getUserConfig } from '../user-config.js';
62
65
  import { appendRunLedgerEntry, loadRunLedger, parseRunShardIdentity, queryRunChain, type RunChainShardSibling, type RunLedgerEntry, type RunLedgerWriter, type RunOriginData, type RunShardIdentity } from './run-ledger.js';
63
66
  import { decideLineageSupersede, lineageSupersedeCloseComment, type LineageSupersedeOpenDraft } from './lineage-supersede.js';
64
67
  import { basename, isAbsolute, join, relative, resolve, sep } from 'node:path';
65
68
  import { enqueueControlMemo, readSoftStopRequestStatus, type SoftStopRequestRead } from '../harness/control-inbox.js';
66
69
  import { debug } from '../debug/log.js';
70
+ import { emitDecision } from '../live/detail-switch.js';
71
+ import { reworkDecision } from './decision-events.js';
67
72
  import type { LogSink } from '../mss/logging/sink.js';
68
73
  import type { LogQuery, LogStoreRow } from '../mss/logging/log-store.js';
69
74
  import { refreshCodexQuotaSignals } from '../budget/codex-quota-refresh.js';
@@ -73,6 +78,7 @@ import { parseAskProseTitle } from '../self-dev/launch-preflight.js';
73
78
  import { classifyReviewProviderFailure } from '../self-dev/review-provider-fallback.js';
74
79
  import { classifyError } from '../session-runtime/retry-policy.js';
75
80
  import { decomposeSelfDevGoal, inferHotPaths, type SelfDevDecomposeOptions } from '../self-dev/decompose.js';
81
+ import { boundaryGlobs, boundaryViolations } from './goal-boundary.js';
76
82
  import { targetScopedGoalText } from './goal-text-path-scope.js';
77
83
  import type { SelfDevGoalType } from '../self-dev/orchestrate.js';
78
84
  import { DEFAULT_BRANCH_WORKTREE_BASE, gateGitResidue, observeGitResidue } from '../git-fs/worktree.js';
@@ -86,11 +92,12 @@ import { originObservationFields } from '../agent/origin-observation.js';
86
92
  import { getHarnessSpace, normalizeSpaceId, resolveRunIdentity } from '../harness/harness-space.js';
87
93
  import { getElanousConfigDir } from '../elanous-config-dir.js';
88
94
  import { elanousStateRoot } from '../autopilot/state-paths.js';
95
+ import { harnessReleaseNote, releaseNotesDir, renderReleaseNoteSection, writeReleaseNote, type ReleaseNoteFragment } from '../release-loop/release-note.js';
89
96
  import { plannedSelfImplBranch } from '../harness/worktree-branch-prefix.js';
90
97
  export { slugifyFeature } from '../harness/worktree-branch-prefix.js';
91
98
  import { resolveAutoReviewLabels } from './context-capsule.js';
92
99
  import { GOAL_TYPES, extractVerbatimOriginalAsk, leadingGoalMetadata, parseAskFile, parseGoalType, type GoalType } from './goal-author.js';
93
- import { resolveAdaptiveMaxReworkDecision, resolveEscalateTier, resolveEscalateTarget, buildReworkFeature, failIndicator, appendReworkHistory, truncateReworkHistoryByItem, applyReworkBudgetDecision, parseContractConflictRelaxation, parseReworkBudgetDecision, resolveReworkBudgetCarry, stripReworkBudgetHeaders, countConsecutiveMustFixIds, mergeReworkNotes, resolveReworkKind, type ReworkPlanRevision, type ReworkNotePart } from './rework-policy.js';
100
+ import { resolveAdaptiveMaxReworkDecision, resolveEscalateTier, resolveEscalateTarget, buildReworkFeature, failIndicator, isRepeatedUnverifiedOnlyGateFailure, unverifiedRepeatKey, appendReworkHistory, truncateReworkHistoryByItem, applyReworkBudgetDecision, parseContractConflictRelaxation, parseReworkBudgetDecision, resolveReworkBudgetCarry, stripReworkBudgetHeaders, countConsecutiveMustFixIds, mergeReworkNotes, resolveReworkKind, type ReworkPlanRevision, type ReworkNotePart } from './rework-policy.js';
94
101
  import type { SupervisionReworkSource } from './supervision-vocabulary.js';
95
102
  import { classifyReworkBudgetShadow } from './classify-shadow.js';
96
103
  import { createReworkBudgetJudgment, REWORK_BUDGET_JUDGMENT, reworkBudgetEvidenceForObservation, reworkBudgetWorkflow } from './rework-budget-judgment.js';
@@ -169,12 +176,15 @@ import type { RunOutcome, ReworkBudgetVerdict } from './run-outcome.js';
169
176
  import type { EscalateTier } from './rework-policy.js';
170
177
  import type { ClassifyShadowCallLLM } from './classify-shadow.js';
171
178
  import { hasModuleLoadFailure, type GateTestFailure } from './gate-baseline.js';
172
- import { defaultBranchRef } from './seams.js';
179
+ import { commitWorktree, defaultBranchRef } from './seams.js';
180
+ import { blockedDraftDisposition } from './blocked-draft-policy.js';
173
181
  import { formatLlmMergeOutcome } from '../autopilot/build/llm-conflict-merge.js';
174
182
  import { FOUND_CITED_PATH_REFUTATION_QUOTE, MISSING_CITED_PATH_REFUTATION_QUOTE, MUST_FIX_REFUTATION_ACKNOWLEDGEMENT_WITH_REASON, REFUTATION_QUOTE_GRAMMAR, observeMustFixCitedPaths, parseMustFixRefutationAcknowledgement, parseMustFixRefutations, renderMustFixCitedPathFacts, snapshotMustFixFindings, stableMustFixId, type ReflectEvidenceFacts, type ReflectGateFacts, type MustFixCitedPathFact, type MustFixFinding, type MustFixRecurrenceHistory, type MustFixRefutation, type MustFixRefutationKind } from './reflect-mustfix.js';
175
183
  import type { IngestionEntry } from '../agent-substrate/execution/ingestion-policy.js';
176
184
  import { buildReviewIntent } from '../agent-substrate/review-intent.js';
185
+ import { collectPriorDraftFindings, goalTitleFromTargetGoalFile } from './prior-draft-findings.js';
177
186
  import { resolveDesignCheck, type DesignCheckOutcome } from '../design/design-check.js';
187
+ import { runDesignGate, type DesignGateResult } from '../design/design-gate.js';
178
188
  import type { ReviewerContextBudget } from '../agent-substrate/pr-reviewer.js';
179
189
  import { persistReviewArtifact, type ReviewArtifactWriter } from '../agent-substrate/review-artifact.js';
180
190
  import { createArtifactStore } from '../artifact/index.js';
@@ -429,21 +439,30 @@ export function decideGateFailureDisposition(facts: {
429
439
  return 'rework';
430
440
  }
431
441
 
442
+ function postSyncTimeoutOnly(facts: { introduced?: number; unknown?: number; timedOut?: number; flakyRerun?: number; childResponsibility?: string } | undefined): boolean {
443
+ // Post-sync attribution may omit childResponsibility; zero introduced/unknown with only
444
+ // timeout evidence is sufficient here, without weakening the main-loop predicate.
445
+ return (facts?.childResponsibility === undefined || facts.childResponsibility === 'none')
446
+ && isTimeoutOnlyUnmeasuredGate(facts && { ...facts, childResponsibility: 'none' });
447
+ }
448
+
432
449
  function postSyncGatePolicy(
433
450
  passed: boolean,
434
- childResponsibility: string | undefined,
451
+ facts: { introduced?: number; unknown?: number; timedOut?: number; flakyRerun?: number; childResponsibility?: string } | undefined,
435
452
  syncStatus: PostSyncStatus,
436
453
  ): PostSyncGatePolicy {
437
- const exemptionWithheld = !passed
438
- && childResponsibility === 'none'
454
+ const timeoutOnly = !passed && postSyncTimeoutOnly(facts);
455
+ const introduced = (facts?.introduced ?? 0) > 0;
456
+ const childResponsibility = facts?.childResponsibility;
457
+ const exemptionWithheld = !timeoutOnly && !passed
458
+ && !introduced && childResponsibility === 'none'
439
459
  && syncStatus === 'llm-resolved';
440
460
  const exempted = !passed
441
- && childResponsibility === 'none'
442
- && syncStatus === 'merged';
461
+ && (timeoutOnly || (!introduced && childResponsibility === 'none' && syncStatus === 'merged'));
443
462
  return {
444
463
  exempted,
445
464
  exemptionWithheld,
446
- mustStop: !passed && (childResponsibility !== 'none' || exemptionWithheld),
465
+ mustStop: !passed && !timeoutOnly && (introduced || childResponsibility !== 'none' || exemptionWithheld),
447
466
  };
448
467
  }
449
468
 
@@ -455,7 +474,7 @@ export function postSyncGateObservation(
455
474
  testStepExecuted?: boolean;
456
475
  measuredFileCount?: number;
457
476
  comparisonBase?: string | null;
458
- reflectGateFacts?: { introduced: number; preexisting: number; unknown: number; timedOut?: number; childResponsibility?: string };
477
+ reflectGateFacts?: { introduced: number; preexisting: number; unknown: number; timedOut?: number; flakyRerun?: number; childResponsibility?: string };
459
478
  },
460
479
  branch: string,
461
480
  detectModuleLoadFailure: (output: string) => boolean,
@@ -464,7 +483,7 @@ export function postSyncGateObservation(
464
483
  const facts = regate.reflectGateFacts;
465
484
  const { exempted, exemptionWithheld } = postSyncGatePolicy(
466
485
  regate.passed,
467
- facts?.childResponsibility,
486
+ facts,
468
487
  syncStatus,
469
488
  );
470
489
  return {
@@ -590,6 +609,7 @@ export interface ReviewDiffContext {
590
609
  goalDocumentPath?: string;
591
610
  round?: number;
592
611
  appliedLastRound?: readonly string[];
612
+ priorRunFindings?: import('./prior-draft-findings.js').PriorDraftFinding[];
593
613
  /** Existing run-chain projection of sibling shards; absent means no sibling runs were observed. */
594
614
  shardSiblings?: {
595
615
  items: readonly RunChainShardSibling[];
@@ -622,6 +642,8 @@ export interface ReviewDiffContext {
622
642
  };
623
643
  /** Read-only comparison of the worktree DESIGN.md declaration and installed craft rulebooks. */
624
644
  designCheck?: DesignCheckOutcome;
645
+ /** Deterministic design-token result supplied to review, never the implementation gate. */
646
+ designGate?: DesignGateResult | { unmeasured: string };
625
647
  }
626
648
 
627
649
  /** 런 사실(커밋 제목·변경 파일)을 fail-soft 로 걷어 온다. seam(git) 이 실패하면 그 종류를 생략하고,
@@ -789,6 +811,13 @@ function observeDeclaredScopeDiff(
789
811
  // ⭐ 관측은 «언제나» 남기고, ***사람 줄은 「하나도 안 만들었을 때만»*** 낸다.
790
812
  const line = declaredScopeUnmadeLine(diff);
791
813
  if (line !== null) input.progress?.('declared-targets-unmade', line);
814
+ // ⭐ 그 옆 — `경계:` 글로브에 닿은 변경. 못 읽었거나 변경 목록이 없으면 조용하다.
815
+ if (goalDocument !== null && input.changedFiles !== undefined) {
816
+ const violations = boundaryViolations(boundaryGlobs(goalDocument), input.changedFiles);
817
+ if (violations.length > 0) {
818
+ input.progress?.('boundary-violated', `⚠️ 경계로 선언한 경로를 고쳤다 — ${violations.join(' · ')}`);
819
+ }
820
+ }
792
821
  }
793
822
 
794
823
  /**
@@ -946,10 +975,14 @@ export interface SelfImplementSeams {
946
975
  * `buildReviewIntent` 가 `goal` 하나로 직접 추출한다(`extractIntentBlocks` · 결정론 · LLM 0).
947
976
  * ⇒ 같은 값을 두 경로로 나르면 갈라진다. 골을 SSOT 로 둔다. */
948
977
  reviewDiff?: (cwd: string, ctx?: ReviewDiffContext) => Promise<SelfImplementReview>;
978
+ /** Read-only prior-draft reviewer findings; tests inject the lookup to avoid network access. */
979
+ collectPriorDraftFindings?: typeof collectPriorDraftFindings;
949
980
  /** Existing run-chain query projection. The orchestrator only selects the current entry's producer-computed siblings. */
950
981
  queryRunChain?: () => { entries: readonly { runId: string; prNumber?: number | null; merged?: boolean; shardSiblings: readonly RunChainShardSibling[] }[] };
951
982
  /** Computes the worktree's design declaration verdict for review context; informational only. */
952
983
  resolveDesignCheck?: (worktreePath: string) => DesignCheckOutcome;
984
+ /** Read-only design-token check for HTML/CSS changes; exceptions remain review-visible. */
985
+ runDesignGate?: typeof runDesignGate;
953
986
  /** 실행 원장 우선, 기존 base 브랜치 PR 코멘트 폴백으로 자동 반영 항목을 읽는다. 실패·부재는 빈 목록으로 수렴한다. */
954
987
  findAppliedReviewItems?: (branch: string, goalId?: string) => Promise<{ basePrLocated: boolean; items: readonly string[]; headlineComments?: number; source?: 'ledger' | 'pr-comment' | 'unavailable' }>;
955
988
  /** ★ 반사-기각 seam(RFC-selfdev-judgment-context-substrate Facet C) — must-fix 재주입 前 각 항목을
@@ -962,6 +995,8 @@ export interface SelfImplementSeams {
962
995
  /** PR을 열기 전에 보존할 산출물이 있는지 판별한다. `base` 대비 branch 고유 변경과 미커밋 변경을 함께 본다.
963
996
  * 생략 시 기존 주입 seam 호환을 위해 산출물이 있다고 본다. */
964
997
  preservationHasChanges?: (ctx: { cwd: string; base?: string }) => boolean | Promise<boolean>;
998
+ /** Test seam for blocked environment branch persistence; return whether the branch was pushed. */
999
+ preserveBlockedBranch?: (ctx: { cwd: string; branch: string; title: string }) => boolean | Promise<boolean>;
965
1000
  /** Hard-cap salvage evidence: a clean worktree and commits ahead of origin/main. */
966
1001
  readReworkSalvageEvidence?: (cwd: string) => Promise<ReworkSalvageEvidence>;
967
1002
  /** Starts exactly one detached `elanous dev --file <goal> --base <branch>` follow-up. */
@@ -978,7 +1013,7 @@ export interface SelfImplementSeams {
978
1013
  readPrDiff?: (opts: { number: number; cwd: string; baseCommit: string; headCommit: string }) => Promise<string>;
979
1014
  /** ★ ⑦ 병합 seam(2026-07-21·auto-merge) — 열린 PR 을 실제 병합(gh pr merge --squash). `matchHeadCommit`이 있으면
980
1015
  * 검사한 고정 head 뒤 변경을 gh가 거부한다. autoMerge + 리뷰 clean 일 때만 호출(outward-facing·main 자율병합). */
981
- mergePr?: (opts: { number: number; cwd: string; matchHeadCommit?: string }) => Promise<{ merged: boolean; baseRefName?: string; detail?: string }>;
1016
+ mergePr?: (opts: { number: number; cwd: string; matchHeadCommit?: string }) => Promise<{ merged: boolean; baseRefName?: string; mergeCommit?: string; detail?: string }>;
982
1017
  /** Post-merge cleanup is opt-in and injectable so tests never touch the filesystem. */
983
1018
  postMergeCleanup?: {
984
1019
  enabled: boolean;
@@ -1052,6 +1087,8 @@ export const SELF_IMPLEMENT_PROGRESS_STAGES = [
1052
1087
  // ⛔ 기존 단계 이름을 «빌려 쓰지 않는다» — `progress()` 는 단계 이름으로 원장 행을 만들므로
1053
1088
  // 빌려 쓰면 그 단계 집계가 오염된다([T] 2026-09-12 · `#17767` 이후 계약).
1054
1089
  'declared-targets-unmade',
1090
+ // ⭐ `경계:` 글로브에 실제로 닿은 변경. 막지 않고 이름만 낸다.
1091
+ 'boundary-violated',
1055
1092
  ] as const;
1056
1093
 
1057
1094
  export type SelfImplementProgressStage = typeof SELF_IMPLEMENT_PROGRESS_STAGES[number];
@@ -1821,7 +1858,6 @@ export type GoalRunRecordWriter = (goalFile: string, record: GoalExecutionRecord
1821
1858
 
1822
1859
  export function appendGoalExecutionRecord(goalFile: string, record: GoalExecutionRecord): void {
1823
1860
  const existing = readFileSync(goalFile, 'utf8');
1824
- if (existing.includes(`- runId: ${record.runId}\n`)) return;
1825
1861
  const entry = [
1826
1862
  '## 실행 기록',
1827
1863
  `- runId: ${record.runId}`,
@@ -1890,6 +1926,14 @@ export function appendGoalExecutionRecord(goalFile: string, record: GoalExecutio
1890
1926
  : []),
1891
1927
  '',
1892
1928
  ].join('\n');
1929
+ const goalId = existing.match(/^- GoalId: ([0-9a-f]{16})$/m)?.[1];
1930
+ if (goalId) {
1931
+ const path = writeGoalRunRecordFragment(goalId, record.runId, entry);
1932
+ logRunAwareFailSoft(record.runId, 'goal-record-fragment-written', { goalId, path });
1933
+ }
1934
+ // Legacy documents without GoalId have no fragment key; retain the append so the run is not lost.
1935
+ if (goalId && getUserConfig().tools.selfImplement.goalRecordInDoc === false) return;
1936
+ if (existing.includes(`- runId: ${record.runId}\n`)) return;
1893
1937
  appendFileSync(goalFile, `${existing.endsWith('\n') ? '' : '\n'}${entry}`);
1894
1938
  }
1895
1939
 
@@ -1899,13 +1943,6 @@ export interface SelfImplementOptions {
1899
1943
  * ⇒ 런 슈퍼바이저는 「시도의 요약 판정」만 보고 「어떻게 걸었나」를 «못 봤다».
1900
1944
  * ⛔ 관측용이다 — 흐름을 바꾸지 않는다. ⛔ 던져도 런이 안 죽는다(호출부가 감싼다). */
1901
1945
  onNodeEntry?: (node: PipelineNodeId, round: number) => void;
1902
- /** ⛔⭐ 실험 — 그래프 선언을 «실행 권위»로 올린다(RFC §5 1단계). config 를 «이긴다».
1903
- *
1904
- * 📌 이 칸이 있는 이유가 둘이다:
1905
- * ⓐ 「건너뛰는 쪽」을 시험에서 «누를 수» 있어야 한다 — 없으면 그 갈래는 실물로만 확인된다.
1906
- * ⓑ `resolveGraphAuthority` 의 `source: 'flag'` 가 «아무도 안 쓰는» 퇴화 축이었다
1907
- * (같은 날 `goalTypeSource` 가 같은 병을 앓았다 — 값이 언제나 하나면 그 축은 아무것도 안 가른다). */
1908
- graphAuthoritative?: boolean;
1909
1946
  /** 시험이 런치 오버레이를 빼 «지금 YAML 예산»을 읽게 할 때 쓴다. 생략하면 디스크 오버레이다. */
1910
1947
  graphOverlays?: readonly GraphOverlaySpec[];
1911
1948
  /** ★ K run-identity — 이 self-implement 호출의 per-run join anchor. 미지정 시 상속(env)→canonical mint.
@@ -1985,6 +2022,8 @@ export interface SelfImplementOptions {
1985
2022
  * outward-facing(main 병합)이라 명시 opt-in 만. mergePr seam 이 있어야 실제 병합(없으면 non-draft PR 까지).
1986
2023
  * completion이 없던 기존 호출자의 호환 입력으로 유지한다. */
1987
2024
  autoMerge?: boolean;
2025
+ /** Pod-only: stop after passing the same merge guards, leaving the ready PR for host regate. */
2026
+ mergeByHost?: boolean;
1988
2027
  /** ★ G8 자기판단(2026-07-23·[[ROADMAP-elanous-is-all-pty-unified-autonomy-2026-07-21]] §2b) — PR 을 열 때
1989
2028
  * `auto-review` opt-in 라벨을 붙일지. **2단 게이트**: 이 플래그(사람 옵트인) AND assessAutonomyEligibility
1990
2029
  * (작업 위험도 자기판단·fail-safe) 통과여야 부착. 부적합(외부배포·실주문·설계분기·파괴·보안·리뷰 must-fix)이면
@@ -2096,6 +2135,8 @@ export interface SelfImplementResult {
2096
2135
  supervisorWantedContinue?: true;
2097
2136
  /** Additive hard-cap disposition; outcome remains the stable public terminal contract. */
2098
2137
  salvage?: 'launched' | 'parked';
2138
+ /** Rework stopped on exclusively baseline/flaky/precondition failures; do not retry this goal against the same base. */
2139
+ terminationReason?: 'blocked-by-baseline';
2099
2140
  sessionId?: string;
2100
2141
  worktreePath?: string;
2101
2142
  branch?: string;
@@ -2134,6 +2175,7 @@ export interface SelfImplementResult {
2134
2175
  mergeReason?: string;
2135
2176
  prUrl?: string;
2136
2177
  prNumber?: number;
2178
+ checkedHeadCommit?: string;
2137
2179
  detail?: string;
2138
2180
  }
2139
2181
 
@@ -2443,7 +2485,30 @@ function formatGoalFileForPrBody(goalFile: string, cwd = process.cwd()): string
2443
2485
  return relative(canonicalRoot, canonicalGoal).split(sep).join('/');
2444
2486
  }
2445
2487
 
2446
- function prBody(feature: string, implSummary: string, gateLog?: string, review?: SelfImplementReview, reviewIntent?: string, autoReviewDeclineReasons?: readonly string[], evidence?: string, goalFile?: string, planRevision?: ReworkPlanRevision): string {
2488
+ export class MergedReleaseNoteWriteError extends Error {
2489
+ readonly prNumber: number;
2490
+ readonly prUrl: string;
2491
+ readonly directory: string;
2492
+ readonly fragment: ReleaseNoteFragment;
2493
+
2494
+ constructor(prUrl: string, directory: string, fragment: ReleaseNoteFragment, cause: unknown) {
2495
+ super(`PR #${fragment.pr} was merged, but its release note could not be written to ${directory}: ${safeErrorDescription(cause)}`, { cause });
2496
+ this.name = 'MergedReleaseNoteWriteError';
2497
+ this.prNumber = fragment.pr;
2498
+ this.prUrl = prUrl;
2499
+ this.directory = directory;
2500
+ this.fragment = fragment;
2501
+ }
2502
+ }
2503
+
2504
+ function goalDocumentForReleaseNote(goalFile?: string): string {
2505
+ if (!goalFile) return '';
2506
+ try { return readFileSync(goalFile, 'utf8'); }
2507
+ catch { return ''; }
2508
+ }
2509
+
2510
+ function prBody(feature: string, implSummary: string, gateLog?: string, review?: SelfImplementReview, reviewIntent?: string, autoReviewDeclineReasons?: readonly string[], evidence?: string, goalFile?: string, planRevision?: ReworkPlanRevision, releaseNote?: ReturnType<typeof harnessReleaseNote>): string {
2511
+ const note = releaseNote ?? harnessReleaseNote(goalDocumentForReleaseNote(goalFile), prTitle(feature));
2447
2512
  const relaxation = planRevision?.relaxation
2448
2513
  ? ['', '## 감독 수용 기준 완화', `- 대상: ${planRevision.relaxation.target}`, `- 이전: ${planRevision.relaxation.expected}`, `- 완화: ${planRevision.relaxation.replacement}`, `- 이유: ${planRevision.reason}`, `- 적용: ${planRevision.application?.status ?? 'failed'}${planRevision.application?.detail ? ` (${planRevision.application.detail})` : ''}`, ...(planRevision.disposition ? [`- 충돌 처분: ${planRevision.disposition}`] : [])]
2449
2514
  : [];
@@ -2454,6 +2519,8 @@ function prBody(feature: string, implSummary: string, gateLog?: string, review?:
2454
2519
  '',
2455
2520
  '## 구현 요약',
2456
2521
  implSummary.trim() || '(요약 없음)',
2522
+ '',
2523
+ renderReleaseNoteSection(note).trimEnd(),
2457
2524
  // ★ I-9 — 성공 경로도 수확본을 싣는다. blocked 쪽만 실으면 **통과한 PR 에서 증거가 사라진다**.
2458
2525
  ...(evidence ? ['', '## 자식이 남긴 증거 (EVIDENCE/RESULT · 화면 전체에서 수확)', '```', evidence, '```'] : []),
2459
2526
  ...(reviewIntent ? ['', '## 리뷰 intent', reviewIntent] : []),
@@ -2972,11 +3039,11 @@ export function federationObservation(shardIdentity: RunShardIdentity): Record<s
2972
3039
  * 🚨 그것을 `pr-only` 라 부르면 ***「PR 을 연다」로 읽히는데 worktree-only 도 여기 들어온다*** — 이름이 거짓이 된다.
2973
3040
  * ⇒ 📌 세 번째 값이 필요하면 `completion` 자체를 seam 으로 내려보내야 한다(계약 변경).
2974
3041
  */
2975
- export function completionIntentOf(opts: Pick<SelfImplementOptions, 'completion' | 'autoMerge'>): SelfImplementOptions['completion'] | 'not-auto-merge' {
2976
- return opts.completion ?? (opts.autoMerge === true ? 'auto-merge' : 'not-auto-merge');
3042
+ export function completionIntentOf(opts: Pick<SelfImplementOptions, 'completion' | 'autoMerge' | 'mergeByHost'>): SelfImplementOptions['completion'] | 'not-auto-merge' {
3043
+ return opts.completion ?? (opts.autoMerge === true || opts.mergeByHost === true ? 'auto-merge' : 'not-auto-merge');
2977
3044
  }
2978
3045
 
2979
- function autoMergeEnabled(opts: Pick<SelfImplementOptions, 'completion' | 'autoMerge'>): boolean {
3046
+ function autoMergeEnabled(opts: Pick<SelfImplementOptions, 'completion' | 'autoMerge' | 'mergeByHost'>): boolean {
2980
3047
  return completionIntentOf(opts) === 'auto-merge';
2981
3048
  }
2982
3049
 
@@ -3240,9 +3307,14 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3240
3307
  if (opts.childLlm && (typeof opts.childLlm.provider !== 'string' || !opts.childLlm.provider.trim() || typeof opts.childLlm.model !== 'string' || !opts.childLlm.model.trim())) {
3241
3308
  throw new Error('childLlm.provider and childLlm.model must both be non-empty');
3242
3309
  }
3243
- const branch = opts.branchName ?? plannedSelfImplBranch(opts.feature, opts.goalId);
3244
3310
  const identity = resolveRunIdentity({ explicit: opts.runId });
3245
3311
  const { runId } = identity;
3312
+ const branch = opts.branchName ?? plannedSelfImplBranch(opts.feature, opts.goalId, runId);
3313
+ try {
3314
+ debug.log('self-implement.branch', 'planned', {
3315
+ runId, goalId: opts.goalId, branch, runSuffix: opts.branchName === undefined ? branch.match(/-r[a-z0-9]{6}$/)?.[0] ?? null : null,
3316
+ });
3317
+ } catch { /* observation must not block the run */ }
3246
3318
  const attemptOrdinal = incrementRunAttemptOrdinal(runId);
3247
3319
  const shardIdentity = parseRunShardIdentity(opts.feature);
3248
3320
  const observeOuter = makeRunObserver(runId, opts.goalId, debug.log.bind(debug), opts.seams.writeRunLedger, shardIdentity);
@@ -3314,13 +3386,30 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3314
3386
  };
3315
3387
  let loopRegistered = false;
3316
3388
  let mergeApprovalReceived = false;
3389
+ let autoMergeAuthorizedBeforeSync = false;
3317
3390
  let lastParsedSupervisorVerdict: ReworkBudgetVerdict | undefined;
3318
3391
  let lastParsedSupervisorReason: string | undefined;
3319
3392
  let providerErrorCount = 0;
3320
3393
  let credentialFailureCount = 0;
3394
+ let failureSequence = 0;
3395
+ let lastProviderErrorSeq = 0;
3396
+ let lastCredentialFailureSeq = 0;
3397
+ let lastFailedGateSeq = 0;
3398
+ let lastMustFixReviewSeq = 0;
3399
+ const recordFailureVerdict = async (kind: 'gate' | 'review'): Promise<void> => {
3400
+ // Capture child errors at the verdict boundary, not when terminal reporting eventually reads them.
3401
+ await mergeChildProviderErrors();
3402
+ if (kind === 'gate') lastFailedGateSeq = ++failureSequence;
3403
+ else lastMustFixReviewSeq = ++failureSequence;
3404
+ };
3405
+ const latestVerdictSeq = (): number => Math.max(lastFailedGateSeq, lastMustFixReviewSeq);
3406
+ const hasCurrentProviderError = (): boolean => providerErrorCount > 0 && lastProviderErrorSeq > latestVerdictSeq();
3407
+ const hasCurrentCredentialFailure = (): boolean => credentialFailureCount > 0 && lastCredentialFailureSeq > latestVerdictSeq();
3321
3408
  let lastProviderError: { provider?: string; message?: string } | undefined;
3322
3409
  let lastCredentialFailure: { provider?: string; message?: string } | undefined;
3323
3410
  let childProviderErrorQueryStatus: 'found' | 'none' | 'unavailable' | 'not-configured' = 'not-configured';
3411
+ let queriedProviderErrorCount = 0;
3412
+ let queriedCredentialFailureCount = 0;
3324
3413
  const providerErrorsForResult = (): Pick<SelfImplementResult, 'providerErrors'> => {
3325
3414
  if (providerErrorCount === 0) return {};
3326
3415
  const message = lastProviderError?.message ?? '';
@@ -3340,8 +3429,14 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3340
3429
  const result = await query({ runId, sinceMs: startedAtMs, untilMs: Date.now() });
3341
3430
  childProviderErrorQueryStatus = result.status;
3342
3431
  if (result.status !== 'found') return;
3343
- providerErrorCount += result.providerErrorCount;
3344
- credentialFailureCount += result.credentialFailureCount;
3432
+ const newProviderErrors = Math.max(0, result.providerErrorCount - queriedProviderErrorCount);
3433
+ const newCredentialFailures = Math.max(0, result.credentialFailureCount - queriedCredentialFailureCount);
3434
+ providerErrorCount += newProviderErrors;
3435
+ credentialFailureCount += newCredentialFailures;
3436
+ if (newProviderErrors > 0) lastProviderErrorSeq = ++failureSequence;
3437
+ if (newCredentialFailures > 0) lastCredentialFailureSeq = newProviderErrors > 0 ? lastProviderErrorSeq : ++failureSequence;
3438
+ queriedProviderErrorCount = Math.max(queriedProviderErrorCount, result.providerErrorCount);
3439
+ queriedCredentialFailureCount = Math.max(queriedCredentialFailureCount, result.credentialFailureCount);
3345
3440
  lastProviderError = result.lastProviderError ?? lastProviderError;
3346
3441
  lastCredentialFailure = result.lastCredentialFailure ?? lastCredentialFailure;
3347
3442
  } catch {
@@ -3356,6 +3451,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3356
3451
  if (!data || typeof data !== 'object') return;
3357
3452
  const { provider, message } = data as Record<string, unknown>;
3358
3453
  providerErrorCount++;
3454
+ lastProviderErrorSeq = ++failureSequence;
3359
3455
  lastProviderError = {
3360
3456
  ...(typeof provider === 'string' ? { provider } : {}),
3361
3457
  ...(typeof message === 'string' ? { message } : {}),
@@ -3371,6 +3467,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3371
3467
  // 여기서 문면 정규식으로 다시 재면 소비자마다 다른 답이 나온다.
3372
3468
  if ((data as Record<string, unknown>).authRejected === true) {
3373
3469
  credentialFailureCount++;
3470
+ lastCredentialFailureSeq = lastProviderErrorSeq;
3374
3471
  lastCredentialFailure = { ...lastProviderError };
3375
3472
  }
3376
3473
  },
@@ -3379,6 +3476,15 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3379
3476
  const progressDelivery = { delivered: 0, unwired: 0, callbackFailed: 0 };
3380
3477
  let capturedPrNumber: number | undefined;
3381
3478
  let openPrInvoked = false;
3479
+ const defaultProviderName = opts.seams.currentProviderName?.() ?? currentProviderName();
3480
+ const runProviderName = opts.childLlm?.provider ?? defaultProviderName;
3481
+ const logQuotaProvider = (assessment: QuotaExhaustionAssessment | undefined): void => {
3482
+ try {
3483
+ debug.log('self-implement.abandoned', 'quota-provider', {
3484
+ runProvider: runProviderName, defaultProvider: defaultProviderName, used: assessment?.exhausted !== undefined,
3485
+ });
3486
+ } catch { /* observation must not change the terminal result */ }
3487
+ };
3382
3488
  const instrumentedOpts: SelfImplementOptions = {
3383
3489
  ...opts,
3384
3490
  seams: {
@@ -3418,6 +3524,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3418
3524
  /** ⭐ 방문 예산을 읽으려면 «지금 도는 선언»이 필요하다 — 신원과 «같은 패턴»으로 한 번 심는다.
3419
3525
  * ⛔ 걸음(`traversedNodes`)은 이 스코프에 있고 선언은 안쪽에서 정해지므로, 둘을 잇는 자리가 여기다. */
3420
3526
  let runGraphTemplate: GraphTemplate | undefined;
3527
+ let runContract: RunContract | undefined;
3421
3528
  let runGraphIdentity: { graphId: string; graphVersion: string } | undefined;
3422
3529
  const setRunGraphIdentity = (identity: { graphId: string; graphVersion: string }): void => {
3423
3530
  runGraphIdentity = identity;
@@ -3469,6 +3576,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3469
3576
  traversedNodes.push(node);
3470
3577
  if (node === 'implement') roundCount++;
3471
3578
  const fallbackGraphIdentity = observedGraphIdentity();
3579
+ const contractAtNode = runContract === undefined ? undefined : runContractAtNode(runContract);
3472
3580
  observePipeline('pipeline-node-entry', {
3473
3581
  ...pipelineNodeEntryPayload(
3474
3582
  runGraphTemplate ?? { graphId: fallbackGraphIdentity.graphId, version: fallbackGraphIdentity.graphVersion, nodes: [] },
@@ -3476,7 +3584,15 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3476
3584
  ),
3477
3585
  node,
3478
3586
  round,
3587
+ ...contractAtNode,
3479
3588
  });
3589
+ if (contractAtNode?.contractHonored === false) {
3590
+ observeOuter('graph-contract-violation', {
3591
+ node, round,
3592
+ contractSubstrate: contractAtNode.contractSubstrate,
3593
+ actualSubstrate: contractAtNode.actualSubstrate,
3594
+ }, { level: 'warn' });
3595
+ }
3480
3596
  };
3481
3597
  const observeRoundClassification = (classification: LifecycleScreenComparison): void => {
3482
3598
  roundClassifications.push(classification);
@@ -3731,29 +3847,37 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3731
3847
  }),
3732
3848
  instrumentedOpts.seams.reworkBudgetReviewFindingRecurrence ?? (() => null),
3733
3849
  () => { mergeApprovalReceived = true; },
3850
+ () => { autoMergeAuthorizedBeforeSync = true; },
3734
3851
  (verdict) => { lastParsedSupervisorVerdict = verdict; },
3735
3852
  (reason) => { lastParsedSupervisorReason = reason; },
3736
3853
  (base) => { resolvedBase = base ?? undefined; },
3737
3854
  (basis) => { observationMeasurementBasis = basis; },
3738
3855
  (timeout) => { clarificationTimeout = timeout; },
3739
- () => providerErrorCount > 0,
3740
- () => credentialFailureCount > 0,
3741
- () => providerErrorsForResult().providerErrors?.category,
3856
+ hasCurrentProviderError,
3857
+ hasCurrentCredentialFailure,
3858
+ () => hasCurrentProviderError() ? providerErrorsForResult().providerErrors?.category : undefined,
3742
3859
  (rejectedCount) => { reviewReflectRejectedCount = (reviewReflectRejectedCount ?? 0) + rejectedCount; },
3743
3860
  observeOuter,
3744
3861
  (active) => { runActiveProvider = active; },
3745
3862
  (sessionId) => { terminalSessionId = sessionId; },
3863
+ (contract) => { runContract = contract; },
3864
+ recordFailureVerdict,
3865
+ () => providerErrorCount > 0,
3866
+ () => credentialFailureCount > 0,
3867
+ hasCurrentProviderError,
3868
+ hasCurrentCredentialFailure,
3746
3869
  );
3747
3870
  terminalNode = result.node;
3748
3871
  await mergeChildProviderErrors();
3749
3872
  const addressedResult = attachAbandonedClassification(
3750
3873
  attachReviewReflectionOutcome({ ...result, ...providerErrorsForResult(), runId, ...(lastParsedSupervisorReason ? { supervisorReason: lastParsedSupervisorReason } : {}), ...(mergeApprovalReceived ? { mergeApprovalReceived: true } : {}) }),
3751
3874
  opts.goalFile,
3752
- providerErrorCount > 0,
3753
- credentialFailureCount > 0,
3875
+ hasCurrentProviderError(),
3876
+ hasCurrentCredentialFailure(),
3754
3877
  opts.seams.inspectCodexRotation,
3755
- opts.seams.currentProviderName?.(),
3878
+ runProviderName,
3756
3879
  );
3880
+ if (isAbandonedClassificationOutcome(addressedResult.outcome)) logQuotaProvider(addressedResult.quotaExhaustionAssessment);
3757
3881
  observeOuter('child-provider-error-query', { status: childProviderErrorQueryStatus });
3758
3882
  if (lastProviderError) {
3759
3883
  observeOuter('provider-error-observed', { count: providerErrorCount, ...lastProviderError });
@@ -3823,14 +3947,15 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3823
3947
  branch,
3824
3948
  ...(worktreePath ? { worktreePath } : {}),
3825
3949
  ...(lastParsedSupervisorReason ? { supervisorReason: lastParsedSupervisorReason } : {}),
3826
- ...(mergeApprovalReceived ? { mergeApprovalReceived: true } : {}),
3950
+ ...(mergeApprovalReceived || (e.step === 'merge' && autoMergeAuthorizedBeforeSync) ? { mergeApprovalReceived: true } : {}),
3827
3951
  detail: worktreePath
3828
3952
  ? `자율 단계 '${e.step}' wall-clock ${e.ms}ms 초과 — hang 방지 종결(worktree 회수 경로: ${worktreePath})`
3829
3953
  : `자율 단계 '${e.step}' wall-clock ${e.ms}ms 초과 — hang 방지 종결(worktree 생성 전)`,
3830
3954
  };
3831
3955
  terminalNode = result.node;
3832
3956
  await mergeChildProviderErrors();
3833
- const addressedResult = attachAbandonedClassification(attachReviewReflectionOutcome({ ...result, ...providerErrorsForResult() }), opts.goalFile, providerErrorCount > 0, credentialFailureCount > 0, opts.seams.inspectCodexRotation, opts.seams.currentProviderName?.());
3957
+ const addressedResult = attachAbandonedClassification(attachReviewReflectionOutcome({ ...result, ...providerErrorsForResult() }), opts.goalFile, hasCurrentProviderError(), hasCurrentCredentialFailure(), opts.seams.inspectCodexRotation, runProviderName);
3958
+ logQuotaProvider(addressedResult.quotaExhaustionAssessment);
3834
3959
  observeOuter('child-provider-error-query', { status: childProviderErrorQueryStatus });
3835
3960
  if (lastProviderError) {
3836
3961
  observeOuter('provider-error-observed', { count: providerErrorCount, ...lastProviderError });
@@ -4012,12 +4137,24 @@ export function readQuotaExhausted(
4012
4137
  // ⛔⭐⭐⭐ 그리고 이 신호는 **codex 전용**이다(2R must-fix) — provider 를 «안 보면»
4013
4138
  // Claude·Grok 으로 돈 런까지 codex 쿼터로 «오분류»한다. 그건 이 PR 이 고치려던
4014
4139
  // 「잡통」의 «반대 방향» 오류다.
4015
- // ⚠️ 한계: 이것은 «부모의 현재 설정»이지 그 런이 실제로 쓴 provider 가 아니다
4016
- // (자식이 tier 를 올렸을 수 있다). 그 정확한 귀속은 자식 계측이 선결이라 별개 축이다.
4140
+ // 호출자는 구현 자식 provider 를 우선 넘긴다. 자식 선택이 없으면 프로세스 기본 provider 로 귀속한다.
4141
+ // 부모(리뷰·감독)의 별도 폴백이나 자식 내부 전환은 이 평가의 범위 밖이다.
4017
4142
  const snapshot = rotationInspector();
4018
4143
  // ⭐ 좁히지 않는다 — 스냅샷이 «이미 아는» 것을 증거로 그대로 옮긴다(`quotaAvailabilityEvidence`).
4019
4144
  // ⛔⭐ 「언제 읽었나」를 «값으로» 박는다 — 이 읽기는 런이 «끝난 뒤»다(타입 머리말 참조).
4020
- return assessQuotaExhaustion(providerName, { ...quotaAvailabilityEvidence(snapshot), readPoint: 'postmortem' });
4145
+ const evidence = { ...quotaAvailabilityEvidence(snapshot), readPoint: 'postmortem' as const };
4146
+ // ⛔⭐ 정본 스토어가 아는 계정이 «0개»면 회전이 구성되지 않은 것이다 — 「쓸 계정 없음」을 소진으로 읽지 않는다.
4147
+ // 🩸 P6(2026-09-26 Pod 실물): Pod 는 계정 사본 하나만 받고 회전 목록이 없어 no-candidate → 「할당량 소진」으로
4148
+ // 분류됐다. 진짜 원인(게이트의 tsc 127 · P5)이 그 오분류에 가려졌다. 호스트의 진짜 소진(계정은 있는데 전부 찼다)은 그대로다.
4149
+ if (snapshot.knownAccountCount === 0) return { exhausted: undefined, accountAvailability: evidence };
4150
+ // ⛔⭐ 아는 계정이 «하나»뿐이면 no-candidate 는 «돌릴 곳이 원래 없다»는 뜻이지 «찼다»가 아니다.
4151
+ // 🩸 P2 #20869(2026-09-27 Pod 실물): Pod 는 배분받은 계정 사본 «하나»(third · 잔량 넉넉)만 갖고 그 계정의 사용률 신호가
4152
+ // 없었다 → 회전은 no-candidate → 「할당량 소진」으로 분류돼 진짜 원인(리뷰 UNCONVERGEABLE)을 가렸다.
4153
+ // ⇒ 그 한 계정의 사용률도 도달 신호도 없으면 «모름». 사용률을 알면 종전 판정(임계 미만=false · 이상=true)에 맡긴다.
4154
+ if (snapshot.knownAccountCount === 1 && evidence.reason === 'no-candidate' && snapshot.currentUsedPercent === undefined && snapshot.currentReached !== true) {
4155
+ return { exhausted: undefined, accountAvailability: evidence };
4156
+ }
4157
+ return assessQuotaExhaustion(providerName, evidence);
4021
4158
  } catch {
4022
4159
  return { exhausted: undefined, accountAvailability: undefined }; // fail-soft — 관측은 결론을 막지 않는다
4023
4160
  }
@@ -4085,7 +4222,7 @@ export function attachAbandonedClassification(
4085
4222
  ...(quotaExhaustionAssessment.accountAvailability ? { quotaAccountAvailability: quotaExhaustionAssessment.accountAvailability } : {}),
4086
4223
  ...(credentialFailure ? { credentialFailure: true } : {}),
4087
4224
  ...(providerError ? { providerError: true } : {}),
4088
- ...(result.providerErrors?.category ? { providerErrorCategory: result.providerErrors.category } : {}),
4225
+ ...(providerError && result.providerErrors?.category ? { providerErrorCategory: result.providerErrors.category } : {}),
4089
4226
  worktreePorcelain: worktree.worktreePorcelain,
4090
4227
  ...(worktree.gitResidue ? { gitResidue: worktree.gitResidue } : {}),
4091
4228
  ...(result.completionDisposition ? { completionDisposition: result.completionDisposition } : {}),
@@ -4268,6 +4405,7 @@ async function runSelfImplementInner(
4268
4405
  * 이제 null 이면 measureReviewFindingRecurrence 가 «실제로» 잰다. */
4269
4406
  reworkBudgetReviewFindingRecurrence: () => ReviewFindingRecurrence | null = () => null,
4270
4407
  onMergeApprovalReceived: () => void = () => {},
4408
+ onAutoMergeAuthorizedBeforeSync: () => void = () => {},
4271
4409
  onSupervisorVerdictParsed: (verdict: ReworkBudgetVerdict) => void = () => {},
4272
4410
  onSupervisorReasonParsed: (reason: string | undefined) => void = () => {},
4273
4411
  onResolvedBase: (base: string | null) => void = () => {},
@@ -4282,16 +4420,20 @@ async function runSelfImplementInner(
4282
4420
  * (그러면 「런이 끝날 무렵의 provider」가 되어 `F45` 를 그대로 밟는다). 시작 시점 값을 넘긴다. */
4283
4421
  onActiveProvider: (active: { provider?: string; model?: string; auth?: string }) => void = () => {},
4284
4422
  onSessionCreated: (sessionId: string) => void = () => {},
4423
+ onRunContractResolved: (contract: RunContract) => void = () => {},
4424
+ onFailureVerdict: (kind: 'gate' | 'review') => Promise<void> = async () => {},
4425
+ hasObservedProviderError: () => boolean = hasProviderError,
4426
+ hasObservedCredentialFailure: () => boolean = hasCredentialFailure,
4427
+ hasCurrentProviderError: () => boolean = hasProviderError,
4428
+ hasCurrentCredentialFailure: () => boolean = hasCredentialFailure,
4285
4429
  ): Promise<Omit<SelfImplementResult, 'runId'>> {
4286
4430
  const s = opts.seams;
4287
4431
  const pipelineStartedAtMs = Date.now();
4288
- // Graph authority defaults ON and preserves flag → config → default provenance.
4432
+ // Graph authority is always ON; retain the resolved event with default provenance.
4289
4433
  // For research documents, its declared docs-only routing intentionally skips the gate.
4290
- const userConfig = (await import('../user-config.js')).getUserConfig();
4291
- const graphAuthority = resolveGraphAuthorityForUserConfig(userConfig, opts.graphAuthoritative);
4434
+ const graphAuthority = resolveGraphAuthorityForUserConfig();
4292
4435
  // ⛔ 골 파일이 «없을 수» 있다 — 그때는 골 종류를 모르므로 implement-loop 으로 간다(없는 길로 안 보낸다).
4293
4436
  // ⭐ 대표 지시 ② «변형» — 「최초 결정 시 해당 템플릿 변형을 한다」.
4294
- // ⛔ 승격이 꺼져 있으면 `decideTemplate` 은 `activeTemplate` 과 «같은 값»을 낸다(고르지도 않는다).
4295
4437
  const graphGoalType = opts.goalFile === undefined ? undefined : (goalTypeFields(opts.goalFile).goalType as GoalType | undefined);
4296
4438
  // ⛔ 오버레이는 «한 번» 읽는다 — 라운드마다 디스크를 읽으면 도는 중에 파일이 바뀌어 걸음이 갈린다.
4297
4439
  // ⛔ 이름이 `graph`인 이유: launch(②)·runtime(③) «둘 다» 이 목록에서 고른다. 단계는 인자로 갈린다.
@@ -4308,24 +4450,28 @@ async function runSelfImplementInner(
4308
4450
  // ⛔⭐ `let` 인 이유는 ③ «다이나믹»이다 — 라운드마다 runtime 오버레이가 «앞을 보는 것»만 바꾼다.
4309
4451
  // ⛔ 지난 노드를 재정의하지 않는다(RFC §6: 그러면 원장을 사후에 해석할 수 없다).
4310
4452
  let graphTemplate = graphDecision.template;
4311
- /** 단계 이름 → 그 템플릿의 노드 이름. ⛔ 꺼져 있으면 «항등»이다. */
4453
+ /** 단계 이름 → 그 템플릿의 노드 이름. */
4312
4454
  const node = (stage: PipelineNodeId): PipelineNodeId => nodeNameForStage(stage, graphTemplate) as PipelineNodeId;
4313
4455
  // ⛔⭐ 맥락이 정해진 «직후» 관측기에 심는다 — 이 줄이 없으면 걸음은 YAML 을 따르고 «신원은 안 따른다».
4314
4456
  onGraphResolved(graphIdentityOf(graphTemplate));
4315
- // ⭐ 제어 «출처»를 런마다 «한 번» 남긴다 — ⛔ 승격 여부와 무관하게 «언제나».
4316
- // 🩸 2026-09-08: 이 값은 `gate-skipped-by-graph` «한 자리»에서만 났고, 그 사건은
4317
- // research-loop 이 문서만 바꿨을 때만 난다 ⇒ ***대부분의 런에서 「무엇이 켰나」가 원장에 없었다***.
4318
- // ⛔ 그래서 A/B 의 관문(「두 팔이 갈렸나」)이 «원리상» 답을 못 얻었다.
4319
- // ⛔ 「켜짐」만 남기지 않는다 — `source` 가 「안 켰다」와 「켰는데 안 먹었다」를 가른다.
4457
+ // 권위는 항상 켜지지만 이벤트의 필드 모양은 유지하고 출처를 default로 기록한다.
4320
4458
  observe('graph-authority-resolved', graphAuthorityFields(graphAuthority, graphTemplate));
4459
+ // ⭐ 런 계약 — 런 시작 «한 번» 해석한다(대표 2026-09-26 «초반 계약을 노드가 준수»). 해석 출처(source)와
4460
+ // 실제 칸(actualSubstrate)을 같이 남겨 「계약이 Pod 인데 로컬에서 돌았나」를 원장이 답하게 한다.
4461
+ // 노드 진입 대조는 관측만 하며 실행을 막지 않는다.
4462
+ {
4463
+ const { resolveRunContract } = await import('./graph-run-contract.js');
4464
+ const runContract = resolveRunContract({ ...(graphTemplate.runContract ? { graph: graphTemplate.runContract } : {}), env: process.env });
4465
+ onRunContractResolved(runContract);
4466
+ observe('graph-run-contract-resolved', { ...graphIdentityOf(graphTemplate), ...runContract, ...runContractAtNode(runContract) });
4467
+ }
4321
4468
  // ⛔ 승격이 꺼져 있으면 «심지 않는다» — 그러면 예산 관측도 안 난다(운영 원장이 오늘과 같다).
4322
4469
  if (graphAuthority.enabled) onGraphTemplateResolved(graphTemplate);
4323
4470
  // ⛔ 선택을 «전부» 싣는다 — 얹힌 것만 실으면 「왜 안 얹혔나」를 사후에 못 묻는다.
4324
- // ⛔ 「없음」과 「안 봤음」을 가른다: 승격이 꺼졌으면 selections 가 «빈 배열»이고 그것이 값이다.
4325
4471
  /** ⭐ ③ «다이나믹» — 라운드마다 runtime 오버레이를 다시 고른다.
4326
4472
  * ⛔ **매번 «기준 선언»에서 다시 얹는다** — 이전 라운드 결과 위에 겹쳐 얹으면
4327
4473
  * 「이 걸음을 무엇이 만들었나」가 «누적»이 되어 사후에 못 푼다.
4328
- * ⛔ 승격이 꺼져 있으면 아무 일도 안 한다(오늘과 같은 걸음). */
4474
+ * 오버레이 적용은 기존 실행 경로를 그대로 따른다. */
4329
4475
  const applyRuntimeOverlays = (round: number): void => {
4330
4476
  if (!graphAuthority.enabled) return;
4331
4477
  // ⛔ 「지금 아는 것」만 준다 — 없는 값을 0 으로 지어내지 않는다(key-absent 가 그것을 말한다).
@@ -4376,8 +4522,8 @@ async function runSelfImplementInner(
4376
4522
  roundClassifications.push(classification);
4377
4523
  onRoundClassification(classification);
4378
4524
  };
4379
- const branch = opts.branchName ?? plannedSelfImplBranch(opts.feature, opts.goalId);
4380
4525
  const { runId, source: runIdSource } = identity ?? resolveRunIdentity({ explicit: opts.runId });
4526
+ const branch = opts.branchName ?? plannedSelfImplBranch(opts.feature, opts.goalId, runId);
4381
4527
  try {
4382
4528
  debug.log('run-identity', 'own', {
4383
4529
  runId, branch, source: runIdSource, nestDepth: nestInfo().depth, ...originObservationFields(),
@@ -4406,11 +4552,13 @@ async function runSelfImplementInner(
4406
4552
  // ⭐ 관측 이벤트와 «같은 값»을 원장으로도 보낸다 — 로그에만 있으면 원장 질의가 못 센다(`F12`).
4407
4553
  try { onActiveProvider(activeProvider); } catch { /* 보조 기록이 런을 죽이지 않는다 */ }
4408
4554
  const boundedFeature = boundReadableText(opts.feature, RUN_START_FEATURE_MAX_CHARS);
4555
+ const launchCwd = resolve(process.cwd());
4409
4556
  observe('start', {
4410
4557
  feature: boundedFeature.text, featureTruncated: boundedFeature.truncated, featureOriginalChars: boundedFeature.originalChars,
4411
4558
  branch, base: opts.base ?? null, draft: opts.draft ?? true,
4412
4559
  willFork: !!(opts.parentSessionId && s.forkSession), parentSessionId: opts.parentSessionId ?? null,
4413
- nestDepth: nestInfo().depth, goalSource, goalFile: opts.goalFile ?? null, ...originObservationFields(),
4560
+ nestDepth: nestInfo().depth, goalSource, goalFile: opts.goalFile === undefined ? null : resolve(launchCwd, opts.goalFile),
4561
+ targetRoot: gitRootOf(launchCwd) ?? launchCwd, ...originObservationFields(),
4414
4562
  provider: activeProvider.provider ?? null, model: activeProvider.model ?? null, auth: activeProvider.auth ?? null,
4415
4563
  ...(opts.correlationId !== undefined ? { correlationId: opts.correlationId } : {}),
4416
4564
  });
@@ -4777,12 +4925,15 @@ async function runSelfImplementInner(
4777
4925
  return occurrencePattern.test(reason) && roundsPattern.test(reason);
4778
4926
  };
4779
4927
  const failCounts: number[] = [];
4928
+ // 직전 gate 실패 라운드의 미검증 집합(정렬 키). 통과하면 비운다 — «연속» 반복만 센다.
4929
+ let lastGateUnverifiedKey: string | undefined;
4780
4930
  const reworkHistory: string[] = [];
4781
4931
  const supervisorDecisionHistory: Array<{ round: number; verdict: ReworkBudgetVerdict; reason: string }> = [];
4782
4932
  let judgedEffectiveMax: number | undefined;
4783
4933
  let lastReworkVerdict: ReworkBudgetVerdict | undefined;
4784
4934
  let lastSupervisorVerdict: ReworkBudgetVerdict | undefined;
4785
4935
  let lastSupervisorReason: string | undefined;
4936
+ let consecutiveUnresolvedBudget = 0;
4786
4937
  let pendingPlanRevision: ReworkPlanRevision | undefined;
4787
4938
  let lastPlanRevision: ReworkPlanRevision | undefined;
4788
4939
  const isReviewRework = (source: SupervisionReworkSource): boolean => {
@@ -4818,8 +4969,23 @@ async function runSelfImplementInner(
4818
4969
  observe('review-context-carried', { base: opts.base, basePrLocated: false, carriedItems: 0, headlineComments: 0, source: 'unavailable', error: true, reason: 'lookup-failed' }, { level: 'warn' });
4819
4970
  }
4820
4971
  }
4972
+ const goalTitle = opts.goalFile ? goalTitleFromTargetGoalFile(opts.goalFile, wt.path) : undefined;
4973
+ let priorRunFindings: Awaited<ReturnType<typeof collectPriorDraftFindings>> = [];
4974
+ if (goalTitle) {
4975
+ try {
4976
+ priorRunFindings = await (s.collectPriorDraftFindings ?? collectPriorDraftFindings)({ goalTitle, currentRunId: runId, repoPath: wt.path });
4977
+ } catch (error) {
4978
+ observe('prior-findings.unreadable', { error: error instanceof Error ? error.message : String(error) });
4979
+ }
4980
+ }
4981
+ if (priorRunFindings.length) {
4982
+ observe('prior-findings.loaded', {
4983
+ prs: priorRunFindings.length,
4984
+ items: priorRunFindings.reduce((sum, finding) => sum + finding.items.length, 0),
4985
+ });
4986
+ }
4821
4987
  let appliedLastRound: string[] | undefined;
4822
- let reviewIntent = buildReviewIntent({ goal: opts.feature, goalFile: opts.goalFile });
4988
+ let reviewIntent = buildReviewIntent({ goal: opts.feature, goalFile: opts.goalFile, ...(priorRunFindings.length ? { priorRunFindings } : {}) });
4823
4989
  // ⛔⭐ 리뷰 루프가 만든 마지막 컨텍스트를 잡아 둔다 — PR 본문 조립 직전에 **최종 커밋**의
4824
4990
  // 런 사실로 갱신하기 위해서다(3R must-fix). 루프 안 수집은 `openPr` 단계가 만드는 커밋을
4825
4991
  // 못 본다: 자식은 파일만 남기고 실제 커밋은 `commitWork` 가 루프 뒤에서 만든다.
@@ -4996,9 +5162,10 @@ async function runSelfImplementInner(
4996
5162
  }
4997
5163
  };
4998
5164
  let preservationBase = wt.resolvedBase;
5165
+ const runProviderName = opts.childLlm?.provider ?? (s.currentProviderName?.() ?? currentProviderName());
4999
5166
  let cachedQuotaExhaustionAssessment: QuotaExhaustionAssessment | undefined;
5000
5167
  const quotaExhaustionAssessmentForRun = (): QuotaExhaustionAssessment => {
5001
- cachedQuotaExhaustionAssessment ??= readQuotaExhausted(s.inspectCodexRotation, s.currentProviderName?.());
5168
+ cachedQuotaExhaustionAssessment ??= readQuotaExhausted(s.inspectCodexRotation, runProviderName);
5002
5169
  return cachedQuotaExhaustionAssessment;
5003
5170
  };
5004
5171
  const classifyUnfinishedRun = (stage: SelfImplementStage, verdict?: ReworkBudgetVerdict, decomposition?: TerminalDecomposition): AbandonedClassificationResult => {
@@ -5008,9 +5175,9 @@ async function runSelfImplementInner(
5008
5175
  ...(opts.goalFile ? { goalType: goalTypeFields(opts.goalFile).goalType } : {}),
5009
5176
  ...(quotaExhaustionAssessment.exhausted ? { quotaExhausted: true } : {}),
5010
5177
  ...(quotaExhaustionAssessment.accountAvailability ? { quotaAccountAvailability: quotaExhaustionAssessment.accountAvailability } : {}),
5011
- ...(hasCredentialFailure() ? { credentialFailure: true } : {}),
5012
- ...(hasProviderError() ? { providerError: true } : {}),
5013
- ...(providerErrorCategory() ? { providerErrorCategory: providerErrorCategory() } : {}),
5178
+ ...(hasCurrentCredentialFailure() ? { credentialFailure: true } : {}),
5179
+ ...(hasCurrentProviderError() ? { providerError: true } : {}),
5180
+ ...(hasCurrentProviderError() && providerErrorCategory() ? { providerErrorCategory: providerErrorCategory() } : {}),
5014
5181
  worktreePorcelain: worktree.worktreePorcelain,
5015
5182
  ...(worktree.gitResidue ? { gitResidue: worktree.gitResidue } : {}),
5016
5183
  ...(impl.completionDisposition ? { completionDisposition: impl.completionDisposition } : {}),
@@ -5145,30 +5312,76 @@ async function runSelfImplementInner(
5145
5312
  opts.goalFile,
5146
5313
  s.persistPrBodyArtifact,
5147
5314
  );
5148
- // worktree-only 는 원격이 없어 draft PR 을 열 수 없다. 시도 실패로 사유를 전하지 않고
5149
- // 같은 본문을 아티팩트로 남긴 뒤 워크트리·브랜치를 보존한다. no-changes 가 먼저다.
5150
- if (opts.completion === 'worktree-only') {
5315
+ // no-changes wins; worktree-only remains local even for environment stops.
5316
+ const environmentStop = blockedDraftDisposition(classificationRecord.classification) === 'preserve-branch';
5317
+ const worktreeOnly = opts.completion === 'worktree-only';
5318
+ if (worktreeOnly || environmentStop) {
5151
5319
  let artifactPath: string | undefined;
5152
5320
  let artifactError: string | undefined;
5153
5321
  try {
5154
5322
  artifactPath = persistFullPrBody(s.persistPrBodyArtifact, {
5155
- origin: 'self-implement-blocked-draft-pr-worktree-only',
5323
+ origin: worktreeOnly ? 'self-implement-blocked-draft-pr-worktree-only' : 'self-implement-blocked-draft-pr-environment-stop',
5156
5324
  body: assembled.body,
5157
5325
  originalChars: assembled.originalChars,
5158
5326
  });
5159
5327
  } catch (persistenceError) {
5160
5328
  artifactError = persistenceError instanceof Error ? persistenceError.message : String(persistenceError);
5161
5329
  }
5330
+ let pushed = false;
5331
+ let committed = false;
5332
+ let pushError: Error | undefined;
5333
+ let preservationErrorStep: 'worktree' | 'commit' | 'push' | undefined;
5334
+ if (environmentStop && !worktreeOnly) {
5335
+ try {
5336
+ if (!s.preserveBlockedBranch && !existsSync(wt.path)) {
5337
+ preservationErrorStep = 'worktree';
5338
+ throw new Error(`worktree not found: ${wt.path}`);
5339
+ }
5340
+ if (s.preserveBlockedBranch) {
5341
+ pushed = await s.preserveBlockedBranch({ cwd: wt.path, branch: wt.branch, title: prTitle(opts.feature) });
5342
+ if (!pushed) throw new Error('브랜치 push가 성공하지 않았음');
5343
+ } else {
5344
+ preservationErrorStep = 'commit';
5345
+ const commit = commitWorktree(wt.path, prTitle(opts.feature));
5346
+ if (!commit.ok && !/nothing to commit/.test(commit.out)) throw new Error(commit.out);
5347
+ committed = commit.ok;
5348
+ if (runGitCommand(wt.path, ['remote', 'get-url', 'origin']).status === 0) {
5349
+ preservationErrorStep = 'push';
5350
+ const push = runGitCommand(wt.path, ['push', '-u', 'origin', `HEAD:refs/heads/${wt.branch}`]);
5351
+ if (push.status !== 0) throw new Error(push.stderr || push.stdout);
5352
+ pushed = true;
5353
+ }
5354
+ }
5355
+ } catch (error) {
5356
+ pushError = error instanceof Error ? error : new Error(String(error));
5357
+ }
5358
+ }
5162
5359
  observe('rework-blocked-draft-pr', {
5163
5360
  ...observation,
5164
- skipped: 'worktree-only',
5361
+ skipped: worktreeOnly ? 'worktree-only' : 'environment-stop',
5362
+ ...(!worktreeOnly && environmentStop ? { pushed, committed } : {}),
5165
5363
  worktreePath: wt.path,
5364
+ ...(pushError ? { pushError: pushError.message, preservationErrorStep: preservationErrorStep ?? 'push' } : {}),
5166
5365
  ...(artifactPath ? { prBodyArtifactPath: artifactPath } : {}),
5167
5366
  ...(artifactError ? { prBodyArtifactError: artifactError } : {}),
5168
- });
5169
- progress(stage, artifactPath
5170
- ? `worktree-only 완료: draft PR을 열지 않음(worktree·branch 보존 · 중단 사유 보존: ${artifactPath} · worktree: ${wt.path} · branch: ${wt.branch})`
5171
- : `worktree-only 완료: draft PR을 열지 않음(worktree·branch 보존 · 중단 사유 보존 실패: ${artifactError ?? 'unknown error'} · worktree: ${wt.path} · branch: ${wt.branch})`);
5367
+ }, pushError ? { level: 'warn' } : undefined);
5368
+ if (pushError) {
5369
+ const failure = preservationErrorStep === 'worktree' ? '워크트리 부재로 보존 실패' : preservationErrorStep === 'commit' ? '로컬 브랜치 커밋 실패' : '원격 브랜치 보존 실패';
5370
+ progress('aborted', `환경 탓 중단 — ${failure}: ${wt.branch} (${pushError.message}; worktree: ${wt.path})`);
5371
+ if (preservationErrorStep === 'worktree') return undefined;
5372
+ throw new Error(`환경 탓 중단 — ${failure}: ${wt.branch} (worktree: ${wt.path})`, { cause: pushError });
5373
+ }
5374
+ if (worktreeOnly) {
5375
+ progress(stage, artifactPath
5376
+ ? `worktree-only 완료: draft PR을 열지 않음(worktree·branch 보존 · 중단 사유 보존: ${artifactPath} · worktree: ${wt.path} · branch: ${wt.branch})`
5377
+ : `worktree-only 완료: draft PR을 열지 않음(worktree·branch 보존 · 중단 사유 보존 실패: ${artifactError ?? 'unknown error'} · worktree: ${wt.path} · branch: ${wt.branch})`);
5378
+ } else {
5379
+ // No draft PR on this path, so the stop reason must be findable from the progress line itself.
5380
+ const reasonNote = artifactPath ? `중단 사유 보존: ${artifactPath}` : `중단 사유 보존 실패: ${artifactError ?? 'unknown error'}`;
5381
+ progress(stage, pushed
5382
+ ? `환경 탓 중단 — draft PR 없이 브랜치만 보존: ${wt.branch} · ${reasonNote}`
5383
+ : `환경 탓 중단 — draft PR 없이 로컬 브랜치만 보존(원격 origin 없음): ${wt.branch} · worktree: ${wt.path} · ${reasonNote}`);
5384
+ }
5172
5385
  return undefined;
5173
5386
  }
5174
5387
  progress('pr-opening', '중단 산출물을 draft PR로 보존…');
@@ -5315,6 +5528,23 @@ async function runSelfImplementInner(
5315
5528
  await flushPrComments(pr);
5316
5529
  return { decision, pr };
5317
5530
  };
5531
+ const baselineOnlyGate = (): boolean => {
5532
+ const failures = gate?.baselineFailures;
5533
+ return gate?.passed === false && !!failures?.length && gate.reflectGateFacts?.introduced === 0
5534
+ && gate.reflectGateFacts.unknown === 0
5535
+ && failures.every(({ attribution }) => attribution === 'preexisting' || attribution === 'flaky-timeout'
5536
+ || attribution === 'flaky-rerun' || attribution === 'precondition-unmet');
5537
+ };
5538
+ const noRetryBaseline = (): { terminationReason?: 'blocked-by-baseline' } => {
5539
+ if (!baselineOnlyGate()) return {};
5540
+ const failures = gate!.baselineFailures!;
5541
+ debug.log('self-implement.supervisor', 'no-retry-baseline', {
5542
+ runId,
5543
+ preexisting: failures.filter(({ attribution }) => attribution === 'preexisting').length,
5544
+ flaky: failures.filter(({ attribution }) => attribution === 'flaky-timeout' || attribution === 'flaky-rerun').length,
5545
+ });
5546
+ return { terminationReason: 'blocked-by-baseline' };
5547
+ };
5318
5548
  const salvageHardCap = async (hardCapBlockedExtend: boolean, pr?: { number: number }): Promise<'launched' | 'parked'> => {
5319
5549
  let evidence: ReworkSalvageEvidence | undefined;
5320
5550
  if (hardCapBlockedExtend) {
@@ -5333,21 +5563,27 @@ async function runSelfImplementInner(
5333
5563
  ...(opts.goalFile ? { goalType: goalTypeFields(opts.goalFile).goalType } : {}),
5334
5564
  ...(quotaExhaustionAssessment.exhausted ? { quotaExhausted: true } : {}),
5335
5565
  ...(quotaExhaustionAssessment.accountAvailability ? { quotaAccountAvailability: quotaExhaustionAssessment.accountAvailability } : {}),
5336
- ...(hasCredentialFailure() ? { credentialFailure: true } : {}),
5337
- ...(hasProviderError() ? { providerError: true } : {}),
5338
- ...(providerErrorCategory() ? { providerErrorCategory: providerErrorCategory() } : {}),
5566
+ ...(hasCurrentCredentialFailure() ? { credentialFailure: true } : {}),
5567
+ ...(hasCurrentProviderError() ? { providerError: true } : {}),
5568
+ ...(hasCurrentProviderError() && providerErrorCategory() ? { providerErrorCategory: providerErrorCategory() } : {}),
5339
5569
  worktreePorcelain: worktree.worktreePorcelain,
5340
5570
  ...(worktree.gitResidue ? { gitResidue: worktree.gitResidue } : {}),
5341
5571
  stage: isReviewRework(reworkKind) ? 'review-blocked' : 'gate-failed',
5342
5572
  reviewResultObserved: review !== undefined,
5343
5573
  mustFixReported: (review?.mustFix.length ?? 0) > 0,
5344
5574
  });
5575
+ observe('rework-salvage-classification', { ...abandonedClassification, branch: wt.branch });
5576
+ // Salvage may resume an observed environment interruption even when a later
5577
+ // gate/review verdict is the terminal classification. Keep its cause distinct.
5578
+ const salvageClassification = abandonedClassification.classification === 'implementation-deficit' && hasObservedProviderError()
5579
+ ? hasObservedCredentialFailure() ? 'credential-failure' : 'provider-error'
5580
+ : abandonedClassification.classification;
5345
5581
  const decision = decideReworkSalvage({
5346
5582
  hardCapBlockedExtend,
5347
5583
  goalFile: opts.goalFile,
5348
5584
  salvageAttempt: opts.salvageAttempt,
5349
5585
  evidence,
5350
- abandonedClassification: abandonedClassification.classification,
5586
+ abandonedClassification: salvageClassification,
5351
5587
  });
5352
5588
  if (decision.action !== 'launch') {
5353
5589
  const reason = decision.reason;
@@ -5360,7 +5596,7 @@ async function runSelfImplementInner(
5360
5596
  const launchObservation = {
5361
5597
  branch: wt.branch,
5362
5598
  goalFile: opts.goalFile,
5363
- ...(environmentReason ? { reason: environmentReason, abandonedClassification: abandonedClassification.classification } : {}),
5599
+ ...(environmentReason ? { reason: environmentReason, abandonedClassification: salvageClassification } : {}),
5364
5600
  ...(salvageEvidence ? { clean: salvageEvidence.clean, aheadCommits: salvageEvidence.aheadCommits } : {}),
5365
5601
  };
5366
5602
  observe('rework-salvage', { action: 'launching', ...launchObservation });
@@ -5437,36 +5673,48 @@ async function runSelfImplementInner(
5437
5673
  const judgmentCallLLM = s.judgmentCallLLM;
5438
5674
  if (diagnosedDecision?.verdict !== 'CONTRACT-CONFLICT' && !judgmentCallLLM) throw new Error('rework-budget@v1 requires a judgment provider');
5439
5675
  const judgmentProvider = judgmentCallLLM ? createReworkBudgetJudgment(judgmentCallLLM) : undefined;
5440
- const result = diagnosedDecision?.verdict === 'CONTRACT-CONFLICT'
5441
- ? undefined
5442
- : await withStepTimeout(
5443
- runWorkflowToCompletion(
5444
- {
5445
- workflow: reworkBudgetWorkflow,
5446
- arguments: diagnosis,
5447
- artifactsDir: '',
5448
- persistRun: false,
5449
- judgmentContext: { kind: reworkKind, history: priorHistory },
5450
- },
5451
- {
5452
- callLLM: judgmentCallLLM!,
5453
- runBash: async () => ({ stdout: '', stderr: '', exitCode: 0 }),
5454
- runJudgment: judgmentProvider!,
5455
- },
5456
- ),
5457
- T.review,
5458
- 'review',
5459
- );
5460
- if (result) {
5461
- const classified = result.outputs['rework-budget'];
5462
- if (!result.ok || !classified?.ok || typeof classified.output !== 'string') {
5463
- throw new Error(classified?.error ?? 'rework-budget@v1 judgment failed');
5676
+ try {
5677
+ const result = diagnosedDecision?.verdict === 'CONTRACT-CONFLICT'
5678
+ ? undefined
5679
+ : await withStepTimeout(
5680
+ runWorkflowToCompletion(
5681
+ {
5682
+ workflow: reworkBudgetWorkflow,
5683
+ arguments: diagnosis,
5684
+ artifactsDir: '',
5685
+ persistRun: false,
5686
+ judgmentContext: { kind: reworkKind, history: priorHistory },
5687
+ },
5688
+ {
5689
+ callLLM: judgmentCallLLM!,
5690
+ runBash: async () => ({ stdout: '', stderr: '', exitCode: 0 }),
5691
+ runJudgment: judgmentProvider!,
5692
+ },
5693
+ ),
5694
+ T.review,
5695
+ 'review',
5696
+ );
5697
+ if (result) {
5698
+ const classified = result.outputs['rework-budget'];
5699
+ if (!result.ok || !classified?.ok || typeof classified.output !== 'string') {
5700
+ throw new Error(classified?.error ?? 'rework-budget@v1 judgment failed');
5701
+ }
5702
+ const picked = classified.output === 'EXTEND' || classified.output === 'SUFFICIENT' || classified.output === 'UNCONVERGEABLE'
5703
+ ? classified.output
5704
+ : undefined;
5705
+ if (!picked) throw new Error(`rework-budget@v1 returned unsupported class '${String(classified.output)}'`);
5706
+ parsedDecision = { verdict: picked, reason: diagnosedDecision?.reason ?? 'workflow-fabric classification' };
5464
5707
  }
5465
- const picked = classified.output === 'EXTEND' || classified.output === 'SUFFICIENT' || classified.output === 'UNCONVERGEABLE'
5466
- ? classified.output
5708
+ consecutiveUnresolvedBudget = 0;
5709
+ } catch (error) {
5710
+ const message = safeErrorDescription(error);
5711
+ if (!message.startsWith('rework-budget@v1 classification did not resolve a supported class')
5712
+ && !message.startsWith('rework-budget@v1 returned unsupported class')) throw error;
5713
+ consecutiveUnresolvedBudget++;
5714
+ observe('rework-budget-unresolved-fallback', { round, error: message.slice(0, 200), consecutive: consecutiveUnresolvedBudget }, { level: 'warn' });
5715
+ parsedDecision = consecutiveUnresolvedBudget >= 2
5716
+ ? { verdict: 'UNCONVERGEABLE', reason: 'rework-budget classification unresolved ×2' }
5467
5717
  : undefined;
5468
- if (!picked) throw new Error(`rework-budget@v1 returned unsupported class '${String(classified.output)}'`);
5469
- parsedDecision = { verdict: picked, reason: diagnosedDecision?.reason ?? 'workflow-fabric classification' };
5470
5718
  }
5471
5719
  let fabricObservation: Record<string, unknown> | undefined;
5472
5720
  if (s.classifyCallLLM) {
@@ -5497,7 +5745,7 @@ async function runSelfImplementInner(
5497
5745
  selfImplementConfig.reworkBudget.maxRounds,
5498
5746
  reworkKind,
5499
5747
  priorHistory.length,
5500
- shadowStop,
5748
+ consecutiveUnresolvedBudget >= 2 ? false : shadowStop,
5501
5749
  supervisorDecisionHistory.at(-1)?.verdict,
5502
5750
  );
5503
5751
  effectiveMax = budgetDecision.effectiveMax;
@@ -5688,9 +5936,11 @@ async function runSelfImplementInner(
5688
5936
  const quotaExhaustionAssessment = quotaExhaustionAssessmentForRun();
5689
5937
  return { ok: false, stage: 'review-blocked', node: 'rework', ...terminal, ...supervisorOutcome, sessionId, worktreePath: wt.path, branch: wt.branch, gate, review, quotaExhaustionAssessment, ...(lastSupervisorReason ? { supervisorReason: lastSupervisorReason } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: `rework judged unconvergeable after ${round} rework round(s): ${parsedDecision.reason}` };
5690
5938
  }
5691
- const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', verdict: parsedDecision.verdict, reason: parsedDecision.reason, gate, decomposition: terminalDecomposition, salvageStatusExpected: false });
5939
+ const baselineStop = noRetryBaseline();
5940
+ const reason = baselineStop.terminationReason ?? parsedDecision.reason;
5941
+ const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', verdict: parsedDecision.verdict, reason, gate, decomposition: terminalDecomposition, salvageStatusExpected: false });
5692
5942
  const quotaExhaustionAssessment = quotaExhaustionAssessmentForRun();
5693
- return { ok: false, stage: 'gate-failed', node: 'rework', ...terminal, ...supervisorOutcome, sessionId, worktreePath: wt.path, branch: wt.branch, gate, quotaExhaustionAssessment, ...(lastSupervisorReason ? { supervisorReason: lastSupervisorReason } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: `rework judged unconvergeable after ${round} rework round(s): ${parsedDecision.reason}` };
5943
+ return { ok: false, stage: 'gate-failed', node: 'rework', ...terminal, ...supervisorOutcome, ...baselineStop, sessionId, worktreePath: wt.path, branch: wt.branch, gate, quotaExhaustionAssessment, ...(lastSupervisorReason ? { supervisorReason: lastSupervisorReason } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: baselineStop.terminationReason ?? `rework judged unconvergeable after ${round} rework round(s): ${parsedDecision.reason}` };
5694
5944
  }
5695
5945
  } else {
5696
5946
  const repeatedBlockingIds = repeatedBlockingFindingIds(currentBlockingFindings, previousBlockingFindings);
@@ -5699,7 +5949,10 @@ async function runSelfImplementInner(
5699
5949
  }
5700
5950
  } catch (error) {
5701
5951
  if (judgmentStarted) throw error;
5952
+ consecutiveUnresolvedBudget = 0;
5702
5953
  }
5954
+ } else if (round > 0) {
5955
+ consecutiveUnresolvedBudget = 0;
5703
5956
  }
5704
5957
  if (round > effectiveMax) {
5705
5958
  finalizeSupervisorDeliveries('rework-round-limit');
@@ -5711,8 +5964,9 @@ async function runSelfImplementInner(
5711
5964
  const pr = await preserveBlockedArtifacts({ stage: 'review-blocked', verdict: lastReworkVerdict, reason, gate, salvageStatusExpected: false });
5712
5965
  return { ok: false, stage: 'review-blocked', node: 'rework', ...terminal, sessionId, worktreePath: wt.path, branch: wt.branch, gate, review, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(lastSupervisorVerdict === 'CONTRACT-CONFLICT' ? { supervisorVerdict: lastSupervisorVerdict } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: reason };
5713
5966
  }
5714
- const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', verdict: lastReworkVerdict, reason, gate, salvageStatusExpected: false });
5715
- return { ok: false, stage: 'gate-failed', node: 'rework', ...terminal, sessionId, worktreePath: wt.path, branch: wt.branch, gate, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(lastSupervisorVerdict === 'CONTRACT-CONFLICT' ? { supervisorVerdict: lastSupervisorVerdict } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: reason };
5967
+ const baselineStop = noRetryBaseline();
5968
+ const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', verdict: lastReworkVerdict, reason: baselineStop.terminationReason ?? reason, gate, salvageStatusExpected: false });
5969
+ return { ok: false, stage: 'gate-failed', node: 'rework', ...terminal, ...baselineStop, sessionId, worktreePath: wt.path, branch: wt.branch, gate, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(lastSupervisorVerdict === 'CONTRACT-CONFLICT' ? { supervisorVerdict: lastSupervisorVerdict } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: baselineStop.terminationReason ?? reason };
5716
5970
  }
5717
5971
  const terminal = resolveRunOutcome({ termination: 'budget-exhausted', ...(lastReworkVerdict ? { lastVerdict: lastReworkVerdict } : {}) });
5718
5972
  // ⛔⭐ **보존(=커밋·push) 뒤에 발사한다.** 종전엔 발사가 먼저라, 인수 자식이 `--base <그 브랜치>`
@@ -5751,10 +6005,11 @@ async function runSelfImplementInner(
5751
6005
  const disposition = { ...terminal, ...(salvage ? { salvage } : {}) };
5752
6006
  return { ok: false, stage: 'review-blocked', node: 'rework', ...disposition, sessionId, worktreePath: wt.path, branch: wt.branch, gate, review, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(lastSupervisorVerdict === 'CONTRACT-CONFLICT' ? { supervisorVerdict: lastSupervisorVerdict } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: reason };
5753
6007
  }
5754
- const reason = `gate failed after ${round - 1} rework round(s)`;
5755
- const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate, salvageStatusExpected: true });
5756
- const salvage = await salvageHardCap(canSalvage, pr);
5757
- const disposition = { ...terminal, ...(salvage ? { salvage } : {}) };
6008
+ const baselineStop = noRetryBaseline();
6009
+ const reason = baselineStop.terminationReason ?? `gate failed after ${round - 1} rework round(s)`;
6010
+ const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate, salvageStatusExpected: !baselineStop.terminationReason });
6011
+ const salvage = baselineStop.terminationReason ? 'parked' : await salvageHardCap(canSalvage, pr);
6012
+ const disposition = { ...terminal, ...(salvage ? { salvage } : {}), ...baselineStop };
5758
6013
  return { ok: false, stage: 'gate-failed', node: 'rework', ...disposition, sessionId, worktreePath: wt.path, branch: wt.branch, gate, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(lastSupervisorVerdict === 'CONTRACT-CONFLICT' ? { supervisorVerdict: lastSupervisorVerdict } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: reason };
5759
6014
  }
5760
6015
 
@@ -5787,6 +6042,9 @@ async function runSelfImplementInner(
5787
6042
  progress('implementing', round === 0
5788
6043
  ? '구현 중 (헤드리스 goal-loop·수분 소요)…'
5789
6044
  : formatReworkProgressLine(round, effectiveMax, escalateTier, attemptOrdinal));
6045
+ if (round > 0) {
6046
+ try { emitDecision(reworkDecision({ runId, round, effectiveMax, escalateTier, kind: reworkKind })); } catch { /* observation must not interrupt rework */ }
6047
+ }
5790
6048
  let reworkArtifactPath: string | undefined;
5791
6049
  if (round > 0) {
5792
6050
  try {
@@ -6111,7 +6369,9 @@ async function runSelfImplementInner(
6111
6369
  progress('gated', !runsGate
6112
6370
  ? `gate 미실행 — 이 그래프(${graphTemplate.graphId})는 gate 노드를 갖지 않는다`
6113
6371
  : gate.passed ? 'gate 통과' : `gate 실패(라운드 ${round})`);
6372
+ if (gate.passed) lastGateUnverifiedKey = undefined;
6114
6373
  if (!gate.passed) {
6374
+ await onFailureVerdict('gate');
6115
6375
  const facts = gate.reflectGateFacts;
6116
6376
  const failureDisposition = decideGateFailureDisposition(facts);
6117
6377
  // 타임아웃«뿐» — 도입 0 · 미분류 0 · 자식 책임 없음. 재작업으로 보내지 않고 리뷰로 진행한다.
@@ -6183,6 +6443,23 @@ async function runSelfImplementInner(
6183
6443
  const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate, salvageStatusExpected: false });
6184
6444
  return { ok: false, stage: 'gate-failed', node: 'rework', ...resolveRunOutcome({ termination: 'abandoned' }), sessionId, worktreePath: wt.path, branch: wt.branch, gate, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: reason };
6185
6445
  }
6446
+ // ⭐ 반복 열쇠 = 미검증 집합. 실패 시험 0건인데 직전 gate 실패와 «같은» 집합이면 재작업이 그 신호를 못 바꾼다
6447
+ // (run-7dd4cce6: 리뷰 지적 비교는 incomparable · 점수 1/3 · 예산 판정 EXTEND 로 헛돌았다).
6448
+ if (isRepeatedUnverifiedOnlyGateFailure({ previousKey: lastGateUnverifiedKey, unverified: gate.unverified, gateLog: gate.log, ...(facts ? { introduced: facts.introduced } : {}) })) {
6449
+ finalizeSupervisorDeliveries('gate-failed-unverified-repeat');
6450
+ const unverifiedFiles = [...new Set(gate.unverified ?? [])].sort();
6451
+ const reason = `gate failed twice in a row with no failing test and the same ${unverifiedFiles.length} unverified file(s); rework cannot change that signal — escalating without rework`;
6452
+ observe('gate-failed-unverified-repeat-escalated', {
6453
+ round,
6454
+ unverified: unverifiedFiles.slice(0, 20),
6455
+ unverifiedCount: unverifiedFiles.length,
6456
+ reason,
6457
+ }, { level: 'warn' });
6458
+ progress('gate-failed', `중단 — 실패 시험 0건 · 같은 미검증 파일 ${unverifiedFiles.length}개가 되풀이(재작업으로 안 바뀐다 · 사람 판단 대기)`);
6459
+ const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate, salvageStatusExpected: false });
6460
+ return { ok: false, stage: 'gate-failed', node: 'rework', ...resolveRunOutcome({ termination: 'abandoned' }), sessionId, worktreePath: wt.path, branch: wt.branch, gate, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: reason };
6461
+ }
6462
+ lastGateUnverifiedKey = unverifiedRepeatKey(gate.unverified);
6186
6463
  round++;
6187
6464
  continue;
6188
6465
  }
@@ -6225,6 +6502,26 @@ async function runSelfImplementInner(
6225
6502
  path: designCheck.path,
6226
6503
  });
6227
6504
  }
6505
+ const runFacts = collectRunFacts(wt.path);
6506
+ let designGate: ReviewDiffContext['designGate'];
6507
+ // Git porcelain collapses untracked directories to `site/`; inspect their files too.
6508
+ let untrackedFiles: string[] = [];
6509
+ if (runFacts.changedFiles?.some((file) => file.endsWith('/'))) {
6510
+ try {
6511
+ const untracked = runGitCommand(wt.path, ['ls-files', '--others', '--exclude-standard'], { encoding: 'utf8' });
6512
+ if (untracked.status === 0) untrackedFiles = untracked.stdout.split(/\r?\n/).filter(Boolean);
6513
+ } catch { /* change discovery must not stop review */ }
6514
+ }
6515
+ if ([...(runFacts.changedFiles ?? []), ...(gateRouteFiles ?? []), ...untrackedFiles].some((file) => /\.(?:html|css)$/i.test(file))) {
6516
+ try {
6517
+ designGate = (s.runDesignGate ?? runDesignGate)({ projectDir: wt.path, base: wt.resolvedBase });
6518
+ } catch (error) {
6519
+ designGate = { unmeasured: safeErrorDescription(error) };
6520
+ }
6521
+ observe('design-gate', 'unmeasured' in designGate
6522
+ ? { verdict: null, reason: null, p0Total: null, advisoryTotal: null, files: null, unmeasured: designGate.unmeasured }
6523
+ : { verdict: designGate.verdict, reason: designGate.reason ?? null, p0Total: designGate.p0Total, advisoryTotal: designGate.advisoryTotal, files: designGate.files.length });
6524
+ }
6228
6525
  let goalDocumentPath: string | undefined;
6229
6526
  try {
6230
6527
  goalDocumentPath = opts.goalId ? s.goalDocumentPathByGoalId?.(opts.goalId) : undefined;
@@ -6233,9 +6530,10 @@ async function runSelfImplementInner(
6233
6530
  }
6234
6531
  const reviewContext = {
6235
6532
  runId,
6236
- ...collectRunFacts(wt.path),
6533
+ ...runFacts,
6237
6534
  goal: opts.feature,
6238
6535
  goalFile: opts.goalFile,
6536
+ ...(priorRunFindings.length ? { priorRunFindings } : {}),
6239
6537
  ...(goalDocumentPath ? { goalDocumentPath } : {}),
6240
6538
  round,
6241
6539
  ...((round === 0 ? carriedAppliedItems : appliedLastRound)?.length
@@ -6248,6 +6546,7 @@ async function runSelfImplementInner(
6248
6546
  // ⛔⭐ 하니스가 이미 센 것을 판정자에게 준다(원장 `JDG-S4`·`JDG-S5` — 로그에만 있으면 못 본다).
6249
6547
  ...(evidenceCoverage ? { evidenceCoverage } : {}),
6250
6548
  ...(designCheck ? { designCheck } : {}),
6549
+ ...(designGate ? { designGate } : {}),
6251
6550
  ...(gateEvidence ? { gateEvidenceNote: gateEvidence } : {}),
6252
6551
  ...(gate.baselineFailures?.some((failure) => failure.attribution === 'preexisting')
6253
6552
  ? { preexistingTestFailures: gate.baselineFailures
@@ -6274,6 +6573,7 @@ async function runSelfImplementInner(
6274
6573
  throw error;
6275
6574
  }
6276
6575
  onReviewFindings(round, review.mustFix);
6576
+ if (review.mustFix.length > 0) await onFailureVerdict('review');
6277
6577
  const reviewFindings = snapshotMustFixFindings([...review.mustFix, ...review.shouldFix]);
6278
6578
  const reviewMustFixFindings = reviewFindings.slice(0, review.mustFix.length);
6279
6579
  observeReviewFindingRecurrence(round, review.mustFix);
@@ -6507,7 +6807,7 @@ async function runSelfImplementInner(
6507
6807
  const { latestSignalIncomplete } = signalIncompleteState(roundClassifications);
6508
6808
  const autoMerge = autoMergeEnabled(opts);
6509
6809
  const gateTimeoutUnmeasured = isTimeoutOnlyUnmeasuredGate(gate.reflectGateFacts);
6510
- const canAuto = !gateTimeoutUnmeasured && autoMerge && reviewReal && review!.verdict !== 'fail' && reviewDiffComplete && !requiredEvidenceMissing && !latestSignalIncomplete && !decisionSignalRed;
6810
+ let canAuto = !gateTimeoutUnmeasured && autoMerge && reviewReal && review!.verdict !== 'fail' && reviewDiffComplete && !requiredEvidenceMissing && !latestSignalIncomplete && !decisionSignalRed;
6511
6811
  // ⭐⭐ 통과의 «이유»를 둘로 가른다 — ⛔ 막지는 «않는다»(대표 판단 2026-08-11: ⓐ 문면만).
6512
6812
  // 📏 근거(`JDG-T36` · merge-decision 300건 전수): `verifyByBreaking` 이 실린 8건의 auto 중 ***5건***이
6513
6813
  // ***ran=true 인데 distinguishes=0***(아무것도 안 가르는 자기검증)이었고, 그 다섯이 «전부»
@@ -6518,7 +6818,7 @@ async function runSelfImplementInner(
6518
6818
  // 그건 `skippedReason` 이 이미 가른다. 그래서 여기 조건에 넣지 않는다.
6519
6819
  const verifyInconclusive = gate.verifyByBreaking?.ran === true && (gate.verifyByBreaking.distinguishes ?? 0) === 0;
6520
6820
  const verifyNothingAtBase = verifyInconclusive && (gate.verifyByBreaking?.missingAtBase ?? 0) > 0;
6521
- const mergeReason = canAuto ? (verifyNothingAtBase ? 'review-clean-verify-nothing-at-base' : verifyInconclusive ? 'review-clean-verify-inconclusive' : 'review-clean-armed')
6821
+ let mergeReason = canAuto ? (verifyNothingAtBase ? 'review-clean-verify-nothing-at-base' : verifyInconclusive ? 'review-clean-verify-inconclusive' : 'review-clean-armed')
6522
6822
  : gateTimeoutUnmeasured ? GATE_TIMEOUT_UNMEASURED_MERGE_REASON
6523
6823
  : !autoMerge ? 'no-auto-flag'
6524
6824
  : requiredEvidenceMissing ? 'required-evidence-uncovered'
@@ -6528,9 +6828,9 @@ async function runSelfImplementInner(
6528
6828
  : review!.verdict === 'fail' ? 'review-must-fix'
6529
6829
  : review!.diffTruncated === true ? 'review-diff-truncated'
6530
6830
  : 'review-diff-budget-unknown';
6531
- const mergeSkipReason = canAuto ? undefined : mergeReason;
6532
- if (canAuto) onMergeApprovalReceived();
6533
- observe('merge-decision', {
6831
+ let mergeSkipReason = canAuto ? undefined : mergeReason;
6832
+ if (canAuto) onAutoMergeAuthorizedBeforeSync();
6833
+ const mergeDecisionObservation = {
6534
6834
  autoMerge, reviewed: reviewReal, verdict: review?.verdict ?? 'none',
6535
6835
  decision: canAuto ? 'auto' : 'hitl', reason: mergeReason,
6536
6836
  ...mergeDecisionEvidenceCoverage(evidenceCoverage),
@@ -6552,8 +6852,15 @@ async function runSelfImplementInner(
6552
6852
  ...(gate.verifyByBreaking ? { verifyByBreaking: gate.verifyByBreaking } : {}),
6553
6853
  ...(decisionSignalPress ? { decisionSignalPress, decisionSignalBaselineOnly } : {}),
6554
6854
  ...(decisionSignalPressReason ? { decisionSignalPressReason } : {}),
6555
- });
6855
+ };
6856
+ const recordMergeDecision = () => {
6857
+ observe('merge-decision', {
6858
+ ...mergeDecisionObservation,
6859
+ decision: canAuto ? 'auto' : 'hitl', reason: mergeReason,
6860
+ });
6861
+ };
6556
6862
  if (opts.completion === 'worktree-only' && !decisionSignalRed) {
6863
+ recordMergeDecision();
6557
6864
  progress('worktree-completed', '✅ 작업 트리 완료 — PR 생성 없이 worktree 보존');
6558
6865
  observe('worktree-completed', { branch: wt.branch, hadApprover: !!s.approvePr });
6559
6866
  return {
@@ -6561,10 +6868,11 @@ async function runSelfImplementInner(
6561
6868
  detail: 'worktree-only completion: PR creation skipped',
6562
6869
  };
6563
6870
  }
6564
- const approved = canAuto ? true : (s.approvePr
6871
+ let approved = canAuto ? true : (s.approvePr
6565
6872
  ? await s.approvePr({ branch: wt.branch, ...(gate.log ? { gateLog: gate.log } : {}), implSummary: impl.summary, ...(review ? { review } : {}) })
6566
6873
  : false);
6567
6874
  if (!approved) {
6875
+ recordMergeDecision();
6568
6876
  observe('pr-declined', { branch: wt.branch, hadApprover: !!s.approvePr });
6569
6877
  return {
6570
6878
  ok: false, stage: 'pr-declined', node: 'open-pr', ...resolveRunOutcome({ termination: 'abandoned' }), ...decisionSignalResult, sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), ...(mergeSkipReason ? { mergeReason: mergeSkipReason } : {}),
@@ -6585,6 +6893,9 @@ async function runSelfImplementInner(
6585
6893
  ...(resolvedTarget.error === undefined ? {} : { resolveError: resolvedTarget.error }),
6586
6894
  });
6587
6895
  progress('merge-conflict', '⚠️ 기본 브랜치 해석 실패 — 자동병합 차단(수동 정합 필요·HITL 결정)');
6896
+ canAuto = false;
6897
+ mergeReason = 'default-branch-unresolved';
6898
+ recordMergeDecision();
6588
6899
  return { ok: false, stage: 'merge-conflict', node: 'main-sync', ...resolveRunOutcome({ termination: 'abandoned' }), ...decisionSignalResult, sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), detail: 'pre-PR main sync default-branch-unresolved' };
6589
6900
  }
6590
6901
  progress('gating', `최신 ${mergeTarget} 정합 (병렬 드리프트·LLM 충돌해결)…`);
@@ -6593,6 +6904,9 @@ async function runSelfImplementInner(
6593
6904
  observe('pre-pr-sync', mainSyncObservation(sync, mergeTarget, opts.base, wt.branch));
6594
6905
  if (sync.status === 'conflict-unresolved' || sync.status === 'error') {
6595
6906
  progress('merge-conflict', `⚠️ ${mergeTarget} 정합 ${sync.status}${sync.errorStep === undefined ? '' : ` (${sync.errorStep})`} — 자동병합 차단(수동 정합 필요·HITL 결정)`);
6907
+ canAuto = false;
6908
+ mergeReason = `main-sync-${sync.status}`;
6909
+ recordMergeDecision();
6596
6910
  return { ok: false, stage: 'merge-conflict', node: 'main-sync', ...resolveRunOutcome({ termination: 'abandoned' }), ...decisionSignalResult, sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), detail: `pre-PR main sync ${sync.status}` };
6597
6911
  }
6598
6912
  if (sync.status === 'llm-resolved' || sync.status === 'merged') {
@@ -6602,14 +6916,33 @@ async function runSelfImplementInner(
6602
6916
  : `${mergeTarget} 정합됨 — 통합 결과 full 재-gate…`);
6603
6917
  onNodeEntry('regate', round);
6604
6918
  const regate = await withStepTimeout(s.gate(wt.path, { runId, mode: 'postsync' }), T.gate, 'gate');
6919
+ if (!regate.passed) await onFailureVerdict('gate');
6605
6920
  // `mode` name/meaning stay: `full` = existing gate including tests. Both
6606
6921
  // conflict-resolved and clean-merge reuse this same `s.gate` invocation.
6922
+ const timeoutOnlyPostSync = !regate.passed && postSyncTimeoutOnly(regate.reflectGateFacts);
6607
6923
  const postSyncPolicy = postSyncGatePolicy(
6608
6924
  regate.passed,
6609
- regate.reflectGateFacts?.childResponsibility,
6925
+ regate.reflectGateFacts,
6610
6926
  sync.status,
6611
6927
  );
6612
6928
  observe('gate.postsync', postSyncGateObservation(regate, wt.branch, hasModuleLoadFailure, sync.status));
6929
+ if (timeoutOnlyPostSync) {
6930
+ const facts = regate.reflectGateFacts!;
6931
+ observe('post-sync-gate-timeout-only-continued', {
6932
+ introduced: facts.introduced, unknown: facts.unknown, timedOut: facts.timedOut ?? 0,
6933
+ }, { level: 'warn' });
6934
+ canAuto = false;
6935
+ mergeReason = GATE_TIMEOUT_UNMEASURED_MERGE_REASON;
6936
+ mergeSkipReason = mergeReason;
6937
+ approved = s.approvePr
6938
+ ? await s.approvePr({
6939
+ branch: wt.branch,
6940
+ gateLog: [regate.log, `post-sync gate timeout-only (introduced=${facts.introduced}, unknown=${facts.unknown}, timedOut=${facts.timedOut ?? 'unmeasured'}, flakyRerun=${facts.flakyRerun ?? 'unmeasured'}); merge reason: ${GATE_TIMEOUT_UNMEASURED_MERGE_REASON}`].filter(Boolean).join('\n'),
6941
+ implSummary: impl.summary,
6942
+ ...(review ? { review } : {}),
6943
+ })
6944
+ : false;
6945
+ }
6613
6946
  if (postSyncPolicy.mustStop) {
6614
6947
  progress('gate-failed', sync.status === 'llm-resolved'
6615
6948
  ? '중단 — main 충돌해결 후 gate 실패(면책 보류·통합 깨짐)'
@@ -6619,16 +6952,27 @@ async function runSelfImplementInner(
6619
6952
  : sync.status === 'llm-resolved'
6620
6953
  ? 'gate failed after main-sync (conflict-resolved integration break)'
6621
6954
  : 'gate failed after main-sync (clean-merge integration break)';
6955
+ canAuto = false;
6956
+ mergeReason = 'post-sync-gate-failed';
6957
+ recordMergeDecision();
6622
6958
  const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate: regate, salvageStatusExpected: false });
6623
6959
  return { ok: false, stage: 'gate-failed', node: 'regate', ...resolveRunOutcome({ termination: 'abandoned' }), ...decisionSignalResult, sessionId, worktreePath: wt.path, branch: wt.branch, gate: regate, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(review ? { review } : {}), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: reason };
6624
6960
  }
6625
6961
  if (!regate.passed) {
6626
- progress('gating', 'main 정합 후 gate 실패는 자식 책임 없음으로 면책 — 통합 깨짐으로 중단하지 않고 계속 진행');
6962
+ progress('gating', timeoutOnlyPostSync
6963
+ ? 'main 정합 후 gate 타임아웃만 — 사람 확인으로 진행'
6964
+ : 'main 정합 후 gate 실패는 자식 책임 없음으로 면책 — 통합 깨짐으로 중단하지 않고 계속 진행');
6627
6965
  }
6628
6966
  gate = regate;
6629
6967
  }
6630
6968
  }
6631
6969
 
6970
+ recordMergeDecision();
6971
+ if (!approved) {
6972
+ observe('pr-declined', { branch: wt.branch, hadApprover: !!s.approvePr });
6973
+ return { ok: false, stage: 'pr-declined', node: 'open-pr', ...resolveRunOutcome({ termination: 'abandoned' }), ...decisionSignalResult, sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), mergeReason, detail: s.approvePr ? 'PR not approved' : 'no approvePr seam — fail-closed(자동승인 금지)' };
6974
+ }
6975
+ if (canAuto) onMergeApprovalReceived();
6632
6976
  const extractedOriginalAsk = extractVerbatimOriginalAsk(opts.feature);
6633
6977
  const { labels, declineReasons, eligibility } = resolveAutoReviewLabels(!!opts.autoReview, {
6634
6978
  objective: opts.feature,
@@ -6670,8 +7014,8 @@ async function runSelfImplementInner(
6670
7014
  // 재면 각각 셋·다섯 칸이 «비어» 있었고, 그중 「원장」과 「위험」은 «둘 다» 0이었다.
6671
7015
  // `prBody` 는 모든 인자가 optional 이라 비면 그 절이 «조용히 사라진다» — 그래서 결손이
6672
7016
  // 정상 산출과 구별되지 않았다. 이 관문이 그 부재를 «이름으로» 말한다.
6673
- // ⛔ 기본은 «막지 않는다»(config `tools.selfImplement.prEvidenceArtifactEnforce`) — 골의 내용과
6674
- // 무관하게 착지를 죽이지 않기 위한 의도적 결정이다. 다만 ***거절은 항상 관측으로 남는다***.
7017
+ // ⛔ «막지 않는다» — 골의 내용과 무관하게 착지를 죽이지 않는다. ***거절은 항상 관측으로 남는다***.
7018
+ // (차단 스위치 `prEvidenceArtifactEnforce` 는 2026-09-26 설정 졸업으로 지웠다 — 한 번도 기본으로 안 켜졌다.)
6675
7019
  const prEvidence = collectPrEvidence({
6676
7020
  feature: opts.feature,
6677
7021
  goalFile: opts.goalFile,
@@ -6686,28 +7030,19 @@ async function runSelfImplementInner(
6686
7030
  provider: activeProvider.provider,
6687
7031
  planRevision: lastPlanRevision,
6688
7032
  });
6689
- const prEvidenceDecision = decidePrEvidenceGate(prEvidence, {
6690
- enforce: userConfig.tools.selfImplement.prEvidenceArtifactEnforce === true,
6691
- });
7033
+ const prEvidenceDecision = decidePrEvidenceGate(prEvidence);
6692
7034
  observe('pr-evidence-artifact', {
6693
7035
  accepted: prEvidenceDecision.missing.length === 0,
6694
- blocked: prEvidenceDecision.blocked,
6695
- enforced: prEvidenceDecision.enforced,
6696
7036
  axes: PR_EVIDENCE_AXES.length,
6697
7037
  missingCount: prEvidenceDecision.missing.length,
6698
7038
  missing: prEvidenceDecision.missing,
6699
7039
  ...(prEvidenceDecision.reason ? { reason: prEvidenceDecision.reason } : {}),
6700
7040
  ...(prEvidenceDecision.body ? { bodyChars: prEvidenceDecision.body.length } : {}),
6701
7041
  });
6702
- if (prEvidenceDecision.blocked) {
6703
- // ⛔ 준비 «전»에 멎는다 — 부실한 본문으로 PR 을 열지 않는다. worktree·브랜치는 보존한다.
6704
- const location = `PR 근거 아티팩트 관문 차단 — ${prEvidenceDecision.reason} (worktree·branch 보존 · ${wt.branch} · ${wt.path})`;
6705
- progress('aborted', location);
6706
- throw new Error(location);
6707
- }
7042
+ const releaseNote = harnessReleaseNote(goalDocumentForReleaseNote(opts.goalFile), prTitle(opts.feature));
6708
7043
  const preparedPrBody = preparePrBody(
6709
7044
  [
6710
- prBody(opts.feature, impl.summary, gate.log, review, reviewIntent, declineReasons, harvestedForPr(), opts.goalFile, lastPlanRevision),
7045
+ prBody(opts.feature, impl.summary, gate.log, review, reviewIntent, declineReasons, harvestedForPr(), opts.goalFile, lastPlanRevision, releaseNote),
6711
7046
  ...(prEvidenceDecision.body ? ['', '---', '', prEvidenceDecision.body] : []),
6712
7047
  ].join('\n'),
6713
7048
  s.persistPrBodyArtifact,
@@ -6747,7 +7082,7 @@ async function runSelfImplementInner(
6747
7082
  });
6748
7083
  await flushPrComments(pr);
6749
7084
 
6750
- if (canAuto && s.mergePr) {
7085
+ if (canAuto && (s.mergePr || opts.mergeByHost)) {
6751
7086
  let docsMarkdownDeletions: number | undefined;
6752
7087
  let nonDocsMarkdownDeletions: number | undefined;
6753
7088
  let checkedHeadCommit: string | undefined;
@@ -6777,6 +7112,7 @@ async function runSelfImplementInner(
6777
7112
  guardFailure = `${checkedHeadCommit === undefined ? 'readPrCommitShas' : 'readPrDiff'} failed: ${error instanceof Error ? error.message : String(error)}`;
6778
7113
  }
6779
7114
  }
7115
+ if (opts.mergeByHost && checkedHeadCommit && !/^[0-9a-f]{40}$/i.test(checkedHeadCommit)) guardFailure = 'checked head SHA is not a full commit hash';
6780
7116
  const blocked = guardFailure !== undefined || docsMarkdownDeletions! >= DOCS_MARKDOWN_AUTO_MERGE_DELETION_THRESHOLD;
6781
7117
  observe('auto-merge-docs-deletion-guard', {
6782
7118
  number: pr.number, threshold: DOCS_MARKDOWN_AUTO_MERGE_DELETION_THRESHOLD, blocked,
@@ -6795,11 +7131,29 @@ async function runSelfImplementInner(
6795
7131
  const guardSkipReason = mergeSkipReason ?? (guardFailure ? 'merge-guard-unevaluated' : 'docs-deletion-threshold');
6796
7132
  return { ok: true, stage: 'pr-opened', node: 'open-pr', ...resolveRunOutcome({ termination: 'completed' }), ...decisionSignalResult, ...preservedCompletionResult, ...(completionStatus ? { completionStatus } : {}), sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), mergeReason: guardSkipReason, prUrl: pr.url, prNumber: pr.number, detail };
6797
7133
  }
7134
+ if (opts.mergeByHost) {
7135
+ observe('merge-ready', { number: pr.number, checkedHeadCommit });
7136
+ progress('pr-opened', `호스트 재게이트 대기 (#${pr.number})`);
7137
+ return { ok: true, stage: 'merge-ready', node: 'open-pr', ...resolveRunOutcome({ termination: 'completed' }), ...decisionSignalResult, ...preservedCompletionResult, ...(completionStatus ? { completionStatus } : {}), sessionId, worktreePath: wt.path, branch: wt.branch, gate, ...(review ? { review } : {}), checkedHeadCommit: checkedHeadCommit!, prUrl: pr.url, prNumber: pr.number };
7138
+ }
6798
7139
  onNodeEntry('merge', round);
6799
7140
  progress('merging', '자동 병합 (리뷰 clean·squash)…');
6800
- const m = await withStepTimeout(s.mergePr({ number: pr.number, cwd: wt.path, matchHeadCommit: checkedHeadCommit! }), T.pr, 'pr');
7141
+ const m = await withStepTimeout(s.mergePr!({ number: pr.number, cwd: wt.path, matchHeadCommit: checkedHeadCommit! }), T.pr, 'pr');
6801
7142
  observe('merged', { number: pr.number, merged: m.merged, detail: m.detail ?? null });
6802
7143
  if (m.merged) {
7144
+ const directory = releaseNotesDir(elanousStateRoot());
7145
+ const fragment: ReleaseNoteFragment = {
7146
+ pr: pr.number,
7147
+ ...releaseNote,
7148
+ source: 'harness',
7149
+ ...(m.mergeCommit ? { mergeSha: m.mergeCommit } : {}),
7150
+ };
7151
+ try {
7152
+ writeReleaseNote(directory, fragment);
7153
+ } catch (error) {
7154
+ observe('release-note-write-failed', { number: pr.number, prUrl: pr.url, directory, fragment, error: safeErrorDescription(error) }, { level: 'error' });
7155
+ throw new MergedReleaseNoteWriteError(pr.url, directory, fragment, error);
7156
+ }
6803
7157
  const mergedBase = m.baseRefName?.trim() || observedPrBase;
6804
7158
  const defaultBranch = resolveDefaultBranchTarget(s.defaultBranchRef ?? defaultBranchRef, wt.path).target ?? undefined;
6805
7159
  progress('merged', formatAutoMergeSuccessMessage({ prNumber: pr.number, mergedBase, defaultBranch }));