elanous 0.2.0 → 0.2.4

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 (1174) hide show
  1. package/.env.example +6 -0
  2. package/README.md +16 -14
  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/1105-c473ed46272fba79.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1191-7b13a24117a689fa.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/2375-3fcae5186c64fe6b.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +25 -0
  17. package/apps/pwa/out/_next/static/chunks/{2a79f15a-2013e4d421d6df88.js → 2ea96958-e8c7e112de50b067.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/319-d37df1b6e0cbeff4.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +5 -0
  20. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{6804.8ed6ab492bc5fc0a.js → 4323.c5dfb6f503304775.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/4836-3c93795ab834381e.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{320-d7013ec072863e5e.js → 5080-1613752891fcadb4.js} +4 -4
  26. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/6062-73e68343a9814f6a.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/6090-1bd6077591603947.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7457-f5cb1cc8db9f7453.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8046cadf-211ca3c0e00f2b72.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8067-f74bf14d67ad98f1.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8142-011e1f474efb8b33.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8519-0059d82bdb4812bf.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/9740-52467f244755917f.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/9804-64c02c3c127d5014.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/approvals/page-21c3261af6ab377c.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1991445b8ea86274.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/board/page-4ebfaee2369fe248.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/botlab/page-9fa879ebf5959096.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/bots/page-ca7c3cc305c3285a.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/chat/page-9951930add3d2051.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/control/page-4472ddf1e2458e69.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/design-check/page-4de08d4b766f134b.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/editor/page-7a975e2b9db1dfb7.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/intake/page-49270714ef35bb96.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/layout-33fbdf353e2a5982.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/live/page-259f122e2dd64317.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/market/page-65b82726753658e1.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4b8df3748dc06285.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/morning/page-112f7e477bda77fd.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/not-found-542a5c0006da637c.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/observatory/page-63ffb347831262ea.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/page-98e4e359d97263b4.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/reflection/page-97e24ac675ce576e.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ac6391f26391d89d.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f45c9d45ffc43bd.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-36995b9cb5d98218.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/settings/page-0c795b577988d63f.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b4311e2f71c6735a.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/setup/page-eb2381074df20dba.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/share/page-b01336e64eba01ae.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/showroom/page-7af7f21c1f2858ef.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/tasks/page-a98ecd364586c89b.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/term/page-57f0502dfbfa089b.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/trace/page-3467d2e1abd8a14a.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/vault/page-7842ca23d53ba682.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-ae9ac882912b0198.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/workflows/page-3a0d72e3f783bcef.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/workspace/page-f3b39fe8358c2a97.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-5a22af3181ac2afb.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/main-app-1457627bb302a22c.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +1 -0
  92. package/apps/pwa/out/_next/static/css/e66b7f5efc8df3f3.css +1 -0
  93. package/apps/pwa/out/_next/static/zoQX5iTvXOsIvCjxCe1Ji/_buildManifest.js +1 -0
  94. package/apps/pwa/out/approvals/index.html +1 -0
  95. package/apps/pwa/out/approvals/index.txt +30 -0
  96. package/apps/pwa/out/autopilot/index.html +1 -1
  97. package/apps/pwa/out/autopilot/index.txt +27 -26
  98. package/apps/pwa/out/board/index.html +1 -0
  99. package/apps/pwa/out/board/index.txt +30 -0
  100. package/apps/pwa/out/botlab/index.html +1 -1
  101. package/apps/pwa/out/botlab/index.txt +24 -23
  102. package/apps/pwa/out/bots/index.html +1 -1
  103. package/apps/pwa/out/bots/index.txt +24 -23
  104. package/apps/pwa/out/chat/index.html +1 -2
  105. package/apps/pwa/out/chat/index.txt +24 -23
  106. package/apps/pwa/out/control/index.html +1 -1
  107. package/apps/pwa/out/control/index.txt +27 -26
  108. package/apps/pwa/out/design-check/index.html +1 -1
  109. package/apps/pwa/out/design-check/index.txt +27 -26
  110. package/apps/pwa/out/editor/index.html +1 -0
  111. package/apps/pwa/out/editor/index.txt +31 -0
  112. package/apps/pwa/out/healthz +1 -1
  113. package/apps/pwa/out/index.html +1 -1
  114. package/apps/pwa/out/index.txt +24 -23
  115. package/apps/pwa/out/intake/index.html +1 -1
  116. package/apps/pwa/out/intake/index.txt +27 -26
  117. package/apps/pwa/out/live/index.html +1 -0
  118. package/apps/pwa/out/live/index.txt +30 -0
  119. package/apps/pwa/out/market/index.html +1 -0
  120. package/apps/pwa/out/market/index.txt +27 -0
  121. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  122. package/apps/pwa/out/missions/placeholder/index.txt +24 -23
  123. package/apps/pwa/out/morning/index.html +1 -1
  124. package/apps/pwa/out/morning/index.txt +27 -26
  125. package/apps/pwa/out/observatory/index.html +1 -1
  126. package/apps/pwa/out/observatory/index.txt +27 -26
  127. package/apps/pwa/out/reflection/index.html +1 -1
  128. package/apps/pwa/out/reflection/index.txt +25 -24
  129. package/apps/pwa/out/scheduler/index.html +1 -1
  130. package/apps/pwa/out/scheduler/index.txt +27 -26
  131. package/apps/pwa/out/sessions/index.html +1 -1
  132. package/apps/pwa/out/sessions/index.txt +24 -23
  133. package/apps/pwa/out/settings/devices/index.html +1 -1
  134. package/apps/pwa/out/settings/devices/index.txt +27 -26
  135. package/apps/pwa/out/settings/index.html +1 -1
  136. package/apps/pwa/out/settings/index.txt +27 -26
  137. package/apps/pwa/out/setup/done/index.html +1 -1
  138. package/apps/pwa/out/setup/done/index.txt +27 -26
  139. package/apps/pwa/out/setup/index.html +1 -1
  140. package/apps/pwa/out/setup/index.txt +27 -26
  141. package/apps/pwa/out/share/index.html +1 -1
  142. package/apps/pwa/out/share/index.txt +27 -26
  143. package/apps/pwa/out/showroom/index.html +1 -1
  144. package/apps/pwa/out/showroom/index.txt +24 -23
  145. package/apps/pwa/out/tasks/index.html +1 -1
  146. package/apps/pwa/out/tasks/index.txt +27 -26
  147. package/apps/pwa/out/term/index.html +1 -1
  148. package/apps/pwa/out/term/index.txt +27 -26
  149. package/apps/pwa/out/trace/index.html +1 -0
  150. package/apps/pwa/out/trace/index.txt +30 -0
  151. package/apps/pwa/out/vault/index.html +1 -1
  152. package/apps/pwa/out/vault/index.txt +27 -26
  153. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  154. package/apps/pwa/out/workflows/chat-ui/index.txt +27 -26
  155. package/apps/pwa/out/workflows/index.html +1 -1
  156. package/apps/pwa/out/workflows/index.txt +27 -27
  157. package/apps/pwa/out/workspace/index.html +1 -1
  158. package/apps/pwa/out/workspace/index.txt +27 -26
  159. package/apps/pwa/out/worktrees/index.html +1 -1
  160. package/apps/pwa/out/worktrees/index.txt +27 -26
  161. package/catalog/resources.yaml +8 -11
  162. package/docs/design/systems/LICENSE +201 -0
  163. package/docs/design/systems/NOTICE.md +29 -0
  164. package/docs/design/systems/SOURCE.json +291 -0
  165. package/docs/design/systems/application/DESIGN.md +71 -0
  166. package/docs/design/systems/application/manifest.json +54 -0
  167. package/docs/design/systems/application/tokens.css +63 -0
  168. package/docs/design/systems/artistic/DESIGN.md +71 -0
  169. package/docs/design/systems/artistic/manifest.json +54 -0
  170. package/docs/design/systems/artistic/tokens.css +63 -0
  171. package/docs/design/systems/bento/DESIGN.md +71 -0
  172. package/docs/design/systems/bento/manifest.json +54 -0
  173. package/docs/design/systems/bento/tokens.css +63 -0
  174. package/docs/design/systems/bold/DESIGN.md +71 -0
  175. package/docs/design/systems/bold/manifest.json +54 -0
  176. package/docs/design/systems/bold/tokens.css +63 -0
  177. package/docs/design/systems/brutalism/DESIGN.md +71 -0
  178. package/docs/design/systems/brutalism/manifest.json +54 -0
  179. package/docs/design/systems/brutalism/tokens.css +63 -0
  180. package/docs/design/systems/cafe/DESIGN.md +71 -0
  181. package/docs/design/systems/cafe/manifest.json +54 -0
  182. package/docs/design/systems/cafe/tokens.css +63 -0
  183. package/docs/design/systems/claymorphism/DESIGN.md +71 -0
  184. package/docs/design/systems/claymorphism/manifest.json +54 -0
  185. package/docs/design/systems/claymorphism/tokens.css +63 -0
  186. package/docs/design/systems/clean/DESIGN.md +71 -0
  187. package/docs/design/systems/clean/manifest.json +54 -0
  188. package/docs/design/systems/clean/tokens.css +63 -0
  189. package/docs/design/systems/colorful/DESIGN.md +71 -0
  190. package/docs/design/systems/colorful/manifest.json +54 -0
  191. package/docs/design/systems/colorful/tokens.css +63 -0
  192. package/docs/design/systems/contemporary/DESIGN.md +71 -0
  193. package/docs/design/systems/contemporary/manifest.json +54 -0
  194. package/docs/design/systems/contemporary/tokens.css +63 -0
  195. package/docs/design/systems/corporate/DESIGN.md +71 -0
  196. package/docs/design/systems/corporate/manifest.json +54 -0
  197. package/docs/design/systems/corporate/tokens.css +63 -0
  198. package/docs/design/systems/cosmic/DESIGN.md +71 -0
  199. package/docs/design/systems/cosmic/manifest.json +54 -0
  200. package/docs/design/systems/cosmic/tokens.css +63 -0
  201. package/docs/design/systems/creative/DESIGN.md +71 -0
  202. package/docs/design/systems/creative/manifest.json +54 -0
  203. package/docs/design/systems/creative/tokens.css +63 -0
  204. package/docs/design/systems/dashboard/DESIGN.md +71 -0
  205. package/docs/design/systems/dashboard/manifest.json +54 -0
  206. package/docs/design/systems/dashboard/tokens.css +63 -0
  207. package/docs/design/systems/default/DESIGN.md +62 -0
  208. package/docs/design/systems/default/manifest.json +69 -0
  209. package/docs/design/systems/default/tokens.css +200 -0
  210. package/docs/design/systems/dithered/DESIGN.md +71 -0
  211. package/docs/design/systems/dithered/manifest.json +54 -0
  212. package/docs/design/systems/dithered/tokens.css +63 -0
  213. package/docs/design/systems/doodle/DESIGN.md +71 -0
  214. package/docs/design/systems/doodle/manifest.json +54 -0
  215. package/docs/design/systems/doodle/tokens.css +63 -0
  216. package/docs/design/systems/dramatic/DESIGN.md +71 -0
  217. package/docs/design/systems/dramatic/manifest.json +54 -0
  218. package/docs/design/systems/dramatic/tokens.css +63 -0
  219. package/docs/design/systems/editorial/DESIGN.md +71 -0
  220. package/docs/design/systems/editorial/manifest.json +54 -0
  221. package/docs/design/systems/editorial/tokens.css +63 -0
  222. package/docs/design/systems/elegant/DESIGN.md +71 -0
  223. package/docs/design/systems/elegant/manifest.json +54 -0
  224. package/docs/design/systems/elegant/tokens.css +63 -0
  225. package/docs/design/systems/energetic/DESIGN.md +72 -0
  226. package/docs/design/systems/energetic/manifest.json +54 -0
  227. package/docs/design/systems/energetic/tokens.css +63 -0
  228. package/docs/design/systems/enterprise/DESIGN.md +71 -0
  229. package/docs/design/systems/enterprise/manifest.json +54 -0
  230. package/docs/design/systems/enterprise/tokens.css +63 -0
  231. package/docs/design/systems/expressive/DESIGN.md +71 -0
  232. package/docs/design/systems/expressive/manifest.json +54 -0
  233. package/docs/design/systems/expressive/tokens.css +63 -0
  234. package/docs/design/systems/fantasy/DESIGN.md +71 -0
  235. package/docs/design/systems/fantasy/manifest.json +54 -0
  236. package/docs/design/systems/fantasy/tokens.css +63 -0
  237. package/docs/design/systems/flat/DESIGN.md +71 -0
  238. package/docs/design/systems/flat/manifest.json +54 -0
  239. package/docs/design/systems/flat/tokens.css +63 -0
  240. package/docs/design/systems/friendly/DESIGN.md +71 -0
  241. package/docs/design/systems/friendly/manifest.json +54 -0
  242. package/docs/design/systems/friendly/tokens.css +63 -0
  243. package/docs/design/systems/glassmorphism/DESIGN.md +71 -0
  244. package/docs/design/systems/glassmorphism/manifest.json +54 -0
  245. package/docs/design/systems/glassmorphism/tokens.css +63 -0
  246. package/docs/design/systems/gradient/DESIGN.md +71 -0
  247. package/docs/design/systems/gradient/manifest.json +54 -0
  248. package/docs/design/systems/gradient/tokens.css +63 -0
  249. package/docs/design/systems/luxury/DESIGN.md +71 -0
  250. package/docs/design/systems/luxury/manifest.json +54 -0
  251. package/docs/design/systems/luxury/tokens.css +63 -0
  252. package/docs/design/systems/minimal/DESIGN.md +71 -0
  253. package/docs/design/systems/minimal/manifest.json +54 -0
  254. package/docs/design/systems/minimal/tokens.css +63 -0
  255. package/docs/design/systems/modern/DESIGN.md +71 -0
  256. package/docs/design/systems/modern/manifest.json +54 -0
  257. package/docs/design/systems/modern/tokens.css +63 -0
  258. package/docs/design/systems/mono/DESIGN.md +71 -0
  259. package/docs/design/systems/mono/manifest.json +54 -0
  260. package/docs/design/systems/mono/tokens.css +63 -0
  261. package/docs/design/systems/neobrutalism/DESIGN.md +71 -0
  262. package/docs/design/systems/neobrutalism/manifest.json +54 -0
  263. package/docs/design/systems/neobrutalism/tokens.css +63 -0
  264. package/docs/design/systems/neon/DESIGN.md +71 -0
  265. package/docs/design/systems/neon/manifest.json +54 -0
  266. package/docs/design/systems/neon/tokens.css +63 -0
  267. package/docs/design/systems/neumorphism/DESIGN.md +71 -0
  268. package/docs/design/systems/neumorphism/manifest.json +54 -0
  269. package/docs/design/systems/neumorphism/tokens.css +63 -0
  270. package/docs/design/systems/paper/DESIGN.md +71 -0
  271. package/docs/design/systems/paper/manifest.json +54 -0
  272. package/docs/design/systems/paper/tokens.css +63 -0
  273. package/docs/design/systems/perspective/DESIGN.md +71 -0
  274. package/docs/design/systems/perspective/manifest.json +54 -0
  275. package/docs/design/systems/perspective/tokens.css +63 -0
  276. package/docs/design/systems/premium/DESIGN.md +71 -0
  277. package/docs/design/systems/premium/manifest.json +54 -0
  278. package/docs/design/systems/premium/tokens.css +63 -0
  279. package/docs/design/systems/professional/DESIGN.md +71 -0
  280. package/docs/design/systems/professional/manifest.json +54 -0
  281. package/docs/design/systems/professional/tokens.css +63 -0
  282. package/docs/design/systems/publication/DESIGN.md +71 -0
  283. package/docs/design/systems/publication/manifest.json +54 -0
  284. package/docs/design/systems/publication/tokens.css +63 -0
  285. package/docs/design/systems/refined/DESIGN.md +71 -0
  286. package/docs/design/systems/refined/manifest.json +54 -0
  287. package/docs/design/systems/refined/tokens.css +63 -0
  288. package/docs/design/systems/retro/DESIGN.md +71 -0
  289. package/docs/design/systems/retro/manifest.json +54 -0
  290. package/docs/design/systems/retro/tokens.css +63 -0
  291. package/docs/design/systems/shadcn/DESIGN.md +71 -0
  292. package/docs/design/systems/shadcn/manifest.json +54 -0
  293. package/docs/design/systems/shadcn/tokens.css +255 -0
  294. package/docs/design/systems/simple/DESIGN.md +71 -0
  295. package/docs/design/systems/simple/manifest.json +54 -0
  296. package/docs/design/systems/simple/tokens.css +63 -0
  297. package/docs/design/systems/skeumorphism/DESIGN.md +71 -0
  298. package/docs/design/systems/skeumorphism/manifest.json +54 -0
  299. package/docs/design/systems/skeumorphism/tokens.css +63 -0
  300. package/docs/design/systems/sleek/DESIGN.md +71 -0
  301. package/docs/design/systems/sleek/manifest.json +54 -0
  302. package/docs/design/systems/sleek/tokens.css +63 -0
  303. package/docs/design/systems/spacious/DESIGN.md +71 -0
  304. package/docs/design/systems/spacious/manifest.json +54 -0
  305. package/docs/design/systems/spacious/tokens.css +63 -0
  306. package/docs/design/systems/storytelling/DESIGN.md +71 -0
  307. package/docs/design/systems/storytelling/manifest.json +54 -0
  308. package/docs/design/systems/storytelling/tokens.css +63 -0
  309. package/docs/design/systems/tom-modern/DESIGN.md +361 -0
  310. package/docs/design/systems/tom-modern/manifest.json +16 -0
  311. package/docs/design/systems/tom-modern/tokens.css +99 -0
  312. package/docs/design/systems/vibrant/DESIGN.md +71 -0
  313. package/docs/design/systems/vibrant/manifest.json +54 -0
  314. package/docs/design/systems/vibrant/tokens.css +63 -0
  315. package/docs/design/systems/vintage/DESIGN.md +71 -0
  316. package/docs/design/systems/vintage/manifest.json +54 -0
  317. package/docs/design/systems/vintage/tokens.css +63 -0
  318. package/docs/design/systems/warm-editorial/DESIGN.md +65 -0
  319. package/docs/design/systems/warm-editorial/manifest.json +54 -0
  320. package/docs/design/systems/warm-editorial/tokens.css +63 -0
  321. package/docs/goal-context/01-goal-authoring-checks.md +18 -0
  322. package/docs/goal-context/steward-directives-2026-09-28.md +44 -0
  323. package/graphs/catalog/catalog.yaml +615 -0
  324. package/graphs/default-loop.yaml +1 -1
  325. package/graphs/document-loop.yaml +1 -1
  326. package/graphs/examples/stale-draft-digest/digest.ts +26 -0
  327. package/graphs/examples/stale-draft-digest/recipes.yaml +8 -0
  328. package/graphs/examples/stale-draft-digest/stale-draft-digest.yaml +22 -0
  329. package/graphs/heal/heal-loop.yaml +155 -0
  330. package/graphs/heal/recipes.yaml +19 -0
  331. package/graphs/implement-loop.yaml +2 -2
  332. package/graphs/intake/intake-daily.yaml +55 -0
  333. package/graphs/intake/recipes.yaml +16 -0
  334. package/graphs/landing/landing-heal.yaml +22 -0
  335. package/graphs/landing/recipes.yaml +8 -0
  336. package/graphs/launch/launch-head.yaml +66 -0
  337. package/graphs/launch/recipes.yaml +8 -0
  338. package/graphs/operate-loop.yaml +1 -1
  339. package/graphs/ops/docs-publish.yaml +31 -0
  340. package/graphs/ops/recipes.yaml +8 -0
  341. package/graphs/release/recipes.yaml +38 -0
  342. package/graphs/release/release-loop.yaml +40 -0
  343. package/graphs/research-loop.yaml +1 -1
  344. package/graphs/steward/recipes.yaml +12 -0
  345. package/graphs/steward/steward.yaml +45 -0
  346. package/graphs/video/broll-line.yaml +54 -0
  347. package/package.json +7 -5
  348. package/plugins/job-coach/.agents/plugins/marketplace.json +12 -0
  349. package/plugins/job-coach/.codex-plugin/plugin.json +6 -0
  350. package/plugins/job-coach/.mcp.json +9 -0
  351. package/plugins/job-coach/README.md +20 -0
  352. package/plugins/job-coach/connectors/ncs/server.ts +89 -0
  353. package/plugins/job-coach/examples/interview-sample.md +11 -0
  354. package/plugins/job-coach/graphs/course-links.ts +46 -0
  355. package/plugins/job-coach/graphs/recipes.yaml +18 -0
  356. package/plugins/job-coach/graphs/report.yaml +20 -0
  357. package/plugins/job-coach/graphs/run-step.ts +108 -0
  358. package/plugins/job-coach/plugin.json +13 -0
  359. package/plugins/job-coach/plugin.ts +6 -0
  360. package/plugins/job-coach/skills/career-report/SKILL.md +6 -0
  361. package/plugins/job-coach/skills/interview-to-profile/SKILL.md +6 -0
  362. package/plugins/job-coach/skills/run-report/SKILL.md +15 -0
  363. package/scripts/backup/elanous-backup.sh +139 -13
  364. package/scripts/backup/elanous-restore.sh +122 -0
  365. package/scripts/ci-daemon-port-gate.ts +164 -0
  366. package/scripts/ci-typecheck-changed.ts +15 -1
  367. package/scripts/cli-json-exit-scan.ts +126 -0
  368. package/scripts/codex-quota-alert-format.ts +52 -0
  369. package/scripts/codex-quota-alert.ts +63 -13
  370. package/scripts/continuation-dogfood.ts +2 -1
  371. package/scripts/coord-channel-watch.sh +5 -5
  372. package/scripts/coord-tracks.json +5 -4
  373. package/scripts/cron-run.ts +37 -16
  374. package/scripts/daemon-port-baseline.txt +9 -0
  375. package/scripts/design/extract-corpus-bench.ts +469 -0
  376. package/scripts/design/extract-corpus-score.ts +510 -0
  377. package/scripts/design/vendor-open-design-systems.ts +100 -0
  378. package/scripts/docs-lint.ts +1 -1
  379. package/scripts/fleet/node-setup.sh +38 -4
  380. package/scripts/heal/run-role.ts +328 -0
  381. package/scripts/install-role-watch.sh +95 -0
  382. package/scripts/install.ps1 +11 -1
  383. package/scripts/install.sh +81 -9
  384. package/scripts/isolation-hardcode-baseline.txt +1 -1
  385. package/scripts/landing-heal/must-fix-match.ts +37 -0
  386. package/scripts/landing-heal/run-mission.ts +101 -0
  387. package/scripts/lib/pwa-scenarios/acp-replay.ts +79 -0
  388. package/scripts/lib/pwa-scenarios/cdp-driver.ts +67 -0
  389. package/scripts/lib/pwa-scenarios/runner.ts +200 -0
  390. package/scripts/lib/pwa-scenarios/scenarios.ts +202 -0
  391. package/scripts/market/db-check.ts +212 -0
  392. package/scripts/market-posture-cycle.ts +63 -4
  393. package/scripts/nightly-docops.ts +1 -1
  394. package/scripts/ops/channel-bot-token-migrate.ts +146 -0
  395. package/scripts/ops-health-check.ts +15 -3
  396. package/scripts/pty-scenarios/run.ts +272 -0
  397. package/scripts/public-leak-baseline.txt +0 -7
  398. package/scripts/publish-internal-dist.ts +119 -0
  399. package/scripts/pwa-scenarios.ts +106 -0
  400. package/scripts/rebrand-elanous.ts +1 -1
  401. package/scripts/release-loop/cutoff.ts +139 -0
  402. package/scripts/release-loop/docs-land-node.ts +65 -0
  403. package/scripts/release-loop/docs-node.ts +172 -0
  404. package/scripts/release-loop/gate-diff.ts +29 -0
  405. package/scripts/release-loop/gate-node.ts +353 -0
  406. package/scripts/release-loop/node-verdict.ts +85 -0
  407. package/scripts/release-loop/prepare-node.ts +31 -0
  408. package/scripts/release-loop/publish-node.ts +57 -0
  409. package/scripts/release-loop/pwa-node-verdict.ts +45 -0
  410. package/scripts/release-loop/pwa-scenarios-node.ts +140 -0
  411. package/scripts/release-loop/release-docs.ts +102 -0
  412. package/scripts/release-loop/tui-node-checks.ts +29 -0
  413. package/scripts/release-loop/tui-sim-node.ts +113 -0
  414. package/scripts/release-loop/upgrade-node.ts +25 -0
  415. package/scripts/release-loop/verify-node.ts +21 -0
  416. package/scripts/release-loop/version-node.ts +147 -0
  417. package/scripts/release-upgrade-check.sh +53 -0
  418. package/scripts/se-mission-prepare.ts +9 -15
  419. package/scripts/test-deterministic.ts +2 -1
  420. package/scripts/uninstall.sh +10 -3
  421. package/scripts/video-broll-line.ts +89 -0
  422. package/scripts/waitlist-daily-digest.ts +108 -0
  423. package/scripts/window-landings.sh +1 -1
  424. package/skills/motion-broll/LICENSE +25 -0
  425. package/skills/motion-broll/SKILL.md +150 -0
  426. package/skills/motion-broll/SOURCE.md +6 -0
  427. package/skills/motion-broll/engine/base.css +19 -0
  428. package/skills/motion-broll/engine/beats.js +11 -0
  429. package/skills/motion-broll/engine/build.py +21 -0
  430. package/skills/motion-broll/engine/fonts/Geist-Variable.woff2 +0 -0
  431. package/skills/motion-broll/engine/fonts/GeistMono-Medium.woff2 +0 -0
  432. package/skills/motion-broll/engine/fonts/OFL-Geist.txt +92 -0
  433. package/skills/motion-broll/engine/motion.js +146 -0
  434. package/skills/motion-broll/engine/render.js +22 -0
  435. package/skills/motion-broll/examples/opus-aoe2/01-opus-drop.html +41 -0
  436. package/skills/motion-broll/examples/opus-aoe2/02-pip-builds.html +110 -0
  437. package/skills/motion-broll/examples/opus-aoe2/03-effort-slider.html +38 -0
  438. package/skills/motion-broll/examples/opus-aoe2/04-master-prompt.html +56 -0
  439. package/skills/motion-broll/examples/opus-aoe2/05-low-vs-max.html +49 -0
  440. package/skills/motion-broll/examples/opus-aoe2/06-chapter.html +18 -0
  441. package/skills/motion-broll/examples/opus-aoe2/plan.json +14 -0
  442. package/skills/motion-broll/reference/engine-api.md +106 -0
  443. package/skills/motion-broll/scripts/composite.py +14 -0
  444. package/skills/motion-broll/scripts/inspect_video.py +34 -0
  445. package/skills/motion-broll/scripts/make_pages.py +34 -0
  446. package/skills/motion-broll/scripts/setup.sh +16 -0
  447. package/skills/motion-broll/scripts/words.py +13 -0
  448. package/skills/motion-broll/templates/compare.html +135 -0
  449. package/skills/motion-broll/templates/viewer.html +97 -0
  450. package/skills/omni-digest/SKILL.md +260 -0
  451. package/skills/omni-digest/digest.md +197 -0
  452. package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +32 -0
  453. package/skills/omni-digest/package-lock.json +558 -0
  454. package/skills/omni-digest/package.json +13 -0
  455. package/skills/omni-digest/scripts/main.ts +404 -0
  456. package/skills/omni-digest/src/delegate.ts +34 -0
  457. package/skills/omni-digest/src/detect.ts +46 -0
  458. package/skills/omni-digest/src/diagram.ts +72 -0
  459. package/skills/omni-digest/src/domain-staging.ts +50 -0
  460. package/skills/omni-digest/src/env.ts +38 -0
  461. package/skills/omni-digest/src/fetch.ts +237 -0
  462. package/skills/omni-digest/src/media.ts +180 -0
  463. package/skills/omni-digest/src/obsidian.ts +69 -0
  464. package/skills/omni-digest/src/ocr.ts +149 -0
  465. package/skills/omni-digest/src/router.ts +60 -0
  466. package/skills/omni-digest/src/summarize.ts +87 -0
  467. package/skills/omni-digest/src/types.ts +124 -0
  468. package/skills/omni-digest/src/util.ts +34 -0
  469. package/skills/omni-digest/src/visual.ts +129 -0
  470. package/skills/omni-digest/src/x-api.ts +151 -0
  471. package/skills/omni-digest/tsconfig.json +13 -0
  472. package/src/a2a/agent-card.ts +29 -0
  473. package/src/a2a/server.ts +173 -0
  474. package/src/acp/auto-persist.ts +3 -6
  475. package/src/acp/backend-registry.ts +6 -10
  476. package/src/acp/channel-browser-shell.ts +1 -535
  477. package/src/acp/client.ts +106 -36
  478. package/src/acp/fs-roots.ts +20 -4
  479. package/src/acp/obsidian-tags.ts +6 -3
  480. package/src/acp/server.ts +189 -32
  481. package/src/agent/pty-binding.ts +1 -1
  482. package/src/agent/spawn-embodied-agent-in-vw.ts +5 -336
  483. package/src/agent/subagent-callable.ts +39 -1
  484. package/src/agent-mission/browser-login.ts +241 -0
  485. package/src/agent-mission/capabilities-cli.ts +33 -0
  486. package/src/agent-mission/capability-matrix.ts +31 -0
  487. package/src/agent-mission/capability-readers.ts +79 -0
  488. package/src/agent-mission/capability-types.ts +15 -0
  489. package/src/agent-mission/claude-headless.ts +131 -0
  490. package/src/agent-mission/claude-subscription.ts +57 -0
  491. package/src/agent-mission/doc-guided-install.ts +185 -0
  492. package/src/agent-mission/driver.ts +821 -69
  493. package/src/agent-mission/env-profile.ts +68 -0
  494. package/src/agent-mission/handoff.ts +128 -0
  495. package/src/agent-mission/in-agent-plugin.ts +311 -0
  496. package/src/agent-mission/mission-cli.ts +19 -1
  497. package/src/agent-mission/parse.ts +9 -4
  498. package/src/agent-mission/pr-review-watch.ts +62 -13
  499. package/src/agent-mission/resource-ladder.ts +187 -0
  500. package/src/agent-mission/tool-install.ts +249 -0
  501. package/src/agent-mission/tool-ladder.ts +37 -0
  502. package/src/agent-room/room-builder.ts +6 -600
  503. package/src/agent-substrate/review-intent.ts +43 -1
  504. package/src/auth/scope.ts +8 -4
  505. package/src/auth/temp-tokens.ts +131 -0
  506. package/src/auto-research/obsidian-bridge.ts +2 -0
  507. package/src/autopilot/build/integrity-gate.ts +27 -4
  508. package/src/autopilot/build/isolated-instance.ts +2 -1
  509. package/src/autopilot/build/llm-conflict-merge.ts +27 -0
  510. package/src/autopilot/llm-control-brain.ts +54 -12
  511. package/src/autopilot/mission-engine.ts +15 -1
  512. package/src/autopilot/mission-notify.ts +4 -2
  513. package/src/autopilot/mission-origin.ts +5 -5
  514. package/src/autopilot/mission-phase-track.ts +52 -0
  515. package/src/autopilot/mission-tool.ts +1 -1
  516. package/src/autopilot/pty-control-loop.ts +94 -2
  517. package/src/autopilot/track-agent.ts +138 -0
  518. package/src/autopilot/track-courier.ts +153 -0
  519. package/src/boot/acp-server.ts +16 -2
  520. package/src/boot/check-same-origin.ts +19 -5
  521. package/src/boot/daemon-multi-llm-runtime.ts +14 -8
  522. package/src/boot/daemon-prompt-turn.ts +2 -0
  523. package/src/boot/daemon-runtime.ts +36 -14
  524. package/src/boot/daemon-tools/index.ts +16 -0
  525. package/src/boot/daemon-tools/self-implement.ts +4 -0
  526. package/src/boot/daemon-tools/types.ts +3 -0
  527. package/src/browser-cdp/chrome-flags.ts +7 -0
  528. package/src/browser-cdp/client.ts +2 -0
  529. package/src/browser-pane/mount.ts +1 -246
  530. package/src/budget/codex-reset-credit-state.ts +15 -0
  531. package/src/budget/fetchers/codex.ts +2 -1
  532. package/src/budget/run-usage-rollup.ts +11 -4
  533. package/src/budget/unified-usage.ts +2 -1
  534. package/src/capture/tui-self-report.ts +10 -0
  535. package/src/channel-bot-token.ts +126 -0
  536. package/src/chat/index.ts +21 -45
  537. package/src/chat/input-text-key.ts +2 -2
  538. package/src/chat/mode/manual.ts +2 -4
  539. package/src/chat/pickers/state.ts +10 -27
  540. package/src/chat/search/modal.ts +14 -2
  541. package/src/chat/tool-render/types.ts +1 -1
  542. package/src/chat/turn-typeahead.ts +2 -1
  543. package/src/chat/wrap.ts +6 -8
  544. package/src/cli/__fixtures__/agent-help-before/agent.txt +18 -0
  545. package/src/cli/__fixtures__/agent-help-before/registry.txt +13 -0
  546. package/src/cli/__fixtures__/agent-help-before/root.txt +100 -0
  547. package/src/cli/__fixtures__/agent-help-before/tier.txt +15 -0
  548. package/src/cli/a2a-cli.ts +52 -0
  549. package/src/cli/agent-cli.ts +721 -0
  550. package/src/cli/autopilot-cli.ts +739 -0
  551. package/src/cli/bg-launch.ts +20 -4
  552. package/src/cli/claude-plugin-setup.ts +199 -0
  553. package/src/cli/config-test-sync.ts +94 -10
  554. package/src/cli/connector-cli.ts +204 -0
  555. package/src/cli/control-cli.ts +220 -0
  556. package/src/cli/control-join-cli.ts +142 -0
  557. package/src/cli/docs-cli.ts +38 -0
  558. package/src/cli/doctor-cli.ts +225 -26
  559. package/src/cli/doctor-distro.ts +17 -1
  560. package/src/cli/doctor-fix.ts +145 -17
  561. package/src/cli/doctor-llm-assist.ts +71 -0
  562. package/src/cli/doctor-private-files.ts +66 -0
  563. package/src/cli/doctor-readiness.ts +8 -5
  564. package/src/cli/fleet-cli.ts +63 -0
  565. package/src/cli/g6a-registration-probe.ts +16 -0
  566. package/src/cli/git-install-plan.ts +51 -0
  567. package/src/cli/hooks-cli.ts +44 -0
  568. package/src/cli/ingest-token-cli.ts +21 -0
  569. package/src/cli/intake-cli.ts +416 -0
  570. package/src/cli/labels-cli.ts +74 -0
  571. package/src/cli/leader-cli.ts +10 -159
  572. package/src/cli/live-cli.ts +48 -0
  573. package/src/cli/llm-detect-cli.ts +130 -0
  574. package/src/cli/logs-cli.ts +231 -7
  575. package/src/cli/machine-cli.ts +38 -0
  576. package/src/cli/mcp-call.ts +43 -13
  577. package/src/cli/mcp-gateway-cli.ts +90 -0
  578. package/src/cli/mcp-login.ts +116 -8
  579. package/src/cli/mcp-reload.ts +20 -3
  580. package/src/cli/nexus-dist.ts +18 -13
  581. package/src/cli/nexus-ios-bind.ts +20 -7
  582. package/src/cli/ops-cli.ts +225 -0
  583. package/src/cli/plugin-cli.ts +103 -0
  584. package/src/cli/pod-cli.ts +83 -0
  585. package/src/cli/port-lease-local.ts +124 -0
  586. package/src/cli/pr-cli.ts +12 -1
  587. package/src/cli/provider-cli.ts +720 -0
  588. package/src/cli/pty-record-cli.ts +63 -0
  589. package/src/cli/pty-takeover-cli.ts +57 -40
  590. package/src/cli/pty-web-address.ts +52 -0
  591. package/src/cli/publish-cli.ts +44 -0
  592. package/src/cli/pwa-build.ts +18 -12
  593. package/src/cli/pwa-dev.ts +13 -8
  594. package/src/cli/pwa-registry.ts +6 -0
  595. package/src/cli/pwa-share.ts +65 -22
  596. package/src/cli/pwa-show.ts +20 -4
  597. package/src/cli/pwa-start.ts +99 -27
  598. package/src/cli/pwa-test.ts +201 -96
  599. package/src/cli/release-cli.ts +90 -7
  600. package/src/cli/remotes-cli.ts +20 -1
  601. package/src/cli/remotes.ts +2 -1
  602. package/src/cli/repo-cli.ts +315 -36
  603. package/src/cli/research-cli.ts +66 -0
  604. package/src/cli/role-cli.ts +320 -0
  605. package/src/cli/schedule-cli.ts +246 -0
  606. package/src/cli/self-update.ts +98 -10
  607. package/src/cli/setup-cli.ts +64 -2
  608. package/src/cli/shadow-cli.ts +188 -0
  609. package/src/cli/share-auto-mount.ts +12 -8
  610. package/src/cli/start-cli.ts +221 -0
  611. package/src/cli/stdout-flush.ts +8 -0
  612. package/src/cli/storage-cli.ts +334 -0
  613. package/src/cli/tailscale-serve.ts +34 -19
  614. package/src/cli/tasks-cli.ts +176 -0
  615. package/src/cli/test-state-dir-flag.ts +1 -1
  616. package/src/cli/usage-cli.ts +15 -4
  617. package/src/cli/where-cli.ts +22 -55
  618. package/src/code-edit/diff-render.ts +6 -32
  619. package/src/code-edit/source-delta-browser.ts +0 -1
  620. package/src/codex/models.ts +1 -1
  621. package/src/config.ts +8 -13
  622. package/src/connectors/event-ledger.ts +41 -0
  623. package/src/connectors/linear-projector.ts +88 -0
  624. package/src/connectors/linear.ts +143 -0
  625. package/src/connectors/types.ts +19 -0
  626. package/src/control-plane/lease-holder.ts +41 -0
  627. package/src/control-plane/ledger.ts +146 -0
  628. package/src/control-plane/light-member.ts +164 -0
  629. package/src/control-plane/member-tokens.ts +88 -0
  630. package/src/control-plane/member.ts +159 -0
  631. package/src/control-plane/port-lease-heartbeat.ts +101 -0
  632. package/src/control-plane/ports.ts +40 -0
  633. package/src/control-plane/primary.ts +169 -0
  634. package/src/control-plane/server.ts +216 -0
  635. package/src/dashboard/acp-boot.ts +11 -38
  636. package/src/dashboard/assistant-render-state-runtime.ts +2 -2
  637. package/src/dashboard/assistant-sample-runtime.ts +2 -2
  638. package/src/dashboard/auto-compact-runtime.ts +11 -16
  639. package/src/dashboard/browser-help-runtime.ts +2 -3
  640. package/src/dashboard/chat/acp-chat.ts +2 -5
  641. package/src/dashboard/code-edit-post-turn-runtime.ts +1 -2
  642. package/src/dashboard/compact-surface-assembly.ts +0 -14
  643. package/src/dashboard/compact-surface-dispatch.ts +1 -38
  644. package/src/dashboard/compact-surface-inventory.ts +0 -8
  645. package/src/dashboard/compact-surface-runtime.ts +0 -14
  646. package/src/dashboard/context-menu-provider-boot.ts +0 -9
  647. package/src/dashboard/context-window-runtime-boot.ts +0 -37
  648. package/src/dashboard/index.ts +278 -2558
  649. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +0 -6
  650. package/src/dashboard/input/chat-main-slash-command.ts +2 -2
  651. package/src/dashboard/input/dashboard-priority-key-route.ts +1 -43
  652. package/src/dashboard/input/mouse-modal-surface-runtime.ts +1 -5
  653. package/src/dashboard/input/mouse-wiring.ts +2 -3
  654. package/src/dashboard/layout-display-runtime-registration.ts +0 -10
  655. package/src/dashboard/modals/pane-multi.ts +1 -1
  656. package/src/dashboard/replay-preview.ts +1 -1
  657. package/src/dashboard/runtime/approvers.ts +0 -1
  658. package/src/dashboard/runtime/state-snapshot.ts +0 -90
  659. package/src/dashboard/scenario-runtime-boot.ts +16 -16
  660. package/src/dashboard/slash-runtime/dashboard-handlers.ts +134 -1456
  661. package/src/dashboard/slash-runtime/design-pick.ts +96 -0
  662. package/src/dashboard/slash-runtime/help-from-registry.ts +77 -0
  663. package/src/dashboard/surface-registry-wiring.ts +2 -15
  664. package/src/dashboard/turn-message-runtime.ts +0 -4
  665. package/src/dashboard/turn-preamble.ts +1 -1
  666. package/src/dashboard/turn-stream-formatter.ts +2 -2
  667. package/src/dashboard/turn-stream-runtime.ts +2 -2
  668. package/src/dashboard-pane-context-menu.ts +0 -14
  669. package/src/debug/log.ts +7 -0
  670. package/src/decide/boundary-shadow.ts +131 -0
  671. package/src/design/apply-direction.ts +209 -0
  672. package/src/design/css-root-tokens.ts +89 -0
  673. package/src/design/custom-system-create.ts +230 -0
  674. package/src/design/design-directions.ts +61 -41
  675. package/src/design/design-gate.ts +241 -0
  676. package/src/design/design-library.ts +57 -0
  677. package/src/design/design-previews.ts +138 -0
  678. package/src/design/design-systems.ts +61 -0
  679. package/src/design/lint-artifact-run.ts +46 -6
  680. package/src/design/lint-artifact.ts +5 -1
  681. package/src/design/open-design-client.ts +247 -0
  682. package/src/design/system-from-extract.ts +767 -0
  683. package/src/design/system-schema.ts +123 -0
  684. package/src/discord-slash-wire.ts +2 -1
  685. package/src/discord-test-runner.ts +2 -1
  686. package/src/discord-voice-wire.ts +2 -1
  687. package/src/discord.ts +1 -1
  688. package/src/dispatch/opportunistic-launcher.ts +24 -1
  689. package/src/domains/ops-status.ts +35 -2
  690. package/src/domains/outbound-alert.ts +16 -4
  691. package/src/domains/repeated-failure.ts +89 -0
  692. package/src/domains/schedule-manage-tool.ts +28 -8
  693. package/src/domains/schedule-migrate.ts +22 -4
  694. package/src/domains/schedule-registry.ts +88 -33
  695. package/src/domains/schedule-runs.ts +132 -0
  696. package/src/domains/schedule-state.ts +152 -0
  697. package/src/element-registry/address.ts +1 -3
  698. package/src/git-fs/gh-cli.ts +47 -17
  699. package/src/git-fs/retry.ts +1 -0
  700. package/src/git-fs/runner.ts +1 -0
  701. package/src/git-fs/worktree.ts +6 -5
  702. package/src/github/pr-labels.ts +68 -0
  703. package/src/graph-kinds/plugin-nodes.ts +60 -0
  704. package/src/graph-kinds/registry.ts +118 -0
  705. package/src/graph-runner/graph-cli.ts +103 -0
  706. package/src/graph-runner/graph-notify.ts +220 -0
  707. package/src/graph-runner/graph-tick.ts +119 -0
  708. package/src/graph-runner/release-manifest.ts +93 -0
  709. package/src/graph-runner/runner.ts +457 -0
  710. package/src/grok/credential.ts +158 -5
  711. package/src/grounding/ensure-grounding.ts +131 -0
  712. package/src/grounding/mirror-export.ts +89 -0
  713. package/src/grounding/mirror-manifest.ts +252 -0
  714. package/src/grounding/sources-cli.ts +209 -0
  715. package/src/grounding/sources.ts +333 -0
  716. package/src/grounding/token.ts +115 -0
  717. package/src/harness/harness-cli-command.ts +352 -19
  718. package/src/harness/harness-pod-dispatch.ts +110 -0
  719. package/src/harness/harness-stop.ts +131 -0
  720. package/src/harness/harness-substrate-default.ts +40 -0
  721. package/src/harness/harness-worktrees.ts +1 -1
  722. package/src/harness/harness-write-boundary.ts +2 -0
  723. package/src/harness/llm-decompose.ts +2 -1
  724. package/src/harness/self-send-decide.ts +224 -0
  725. package/src/harness/shell-relay.ts +5 -0
  726. package/src/hooks/providers.ts +77 -0
  727. package/src/hooks/queue.ts +73 -0
  728. package/src/hooks/receiver.ts +133 -0
  729. package/src/index.ts +666 -3406
  730. package/src/input-core/dispatcher.ts +1 -1
  731. package/src/input-core/drag-esc-interceptor.ts +1 -1
  732. package/src/instance/current.ts +5 -5
  733. package/src/instance/leader.ts +10 -326
  734. package/src/instance/nexus-run-refusal.ts +27 -92
  735. package/src/instance/project-local-exclude.ts +27 -0
  736. package/src/instance/resolve.ts +40 -175
  737. package/src/intake-plane/capture.ts +14 -1
  738. package/src/intake-plane/check.ts +34 -14
  739. package/src/intake-plane/collect-github.ts +258 -0
  740. package/src/intake-plane/collect-pod.ts +100 -0
  741. package/src/intake-plane/collect-telegram-saved.ts +86 -0
  742. package/src/intake-plane/digest.ts +102 -0
  743. package/src/intake-plane/enrich-plugins.ts +1 -1
  744. package/src/intake-plane/front-classifier.ts +56 -0
  745. package/src/intake-plane/front-route-classifier.ts +80 -0
  746. package/src/intake-plane/front-route-rules.ts +152 -0
  747. package/src/intake-plane/grounding-docs.ts +185 -0
  748. package/src/intake-plane/harness-target.ts +20 -0
  749. package/src/intake-plane/intake-to-tasks.ts +303 -0
  750. package/src/intake-plane/items.ts +247 -0
  751. package/src/intake-plane/link-ledger.ts +27 -0
  752. package/src/intake-plane/route.ts +104 -0
  753. package/src/intake-plane/runtime-callables.ts +3 -1
  754. package/src/intake-plane/sketch-ledger.ts +34 -0
  755. package/src/intake-plane/slash.ts +30 -2
  756. package/src/intake-plane/submit-intake-work.ts +160 -0
  757. package/src/intake-plane/telegram-work.ts +56 -0
  758. package/src/iul/sidebar-shell.ts +0 -165
  759. package/src/launch-head/capability-check.ts +162 -0
  760. package/src/launch-head/launch-head-cli.ts +242 -0
  761. package/src/launch-head/load-balance.ts +81 -0
  762. package/src/live/detail-switch.ts +175 -0
  763. package/src/llm/provider-detect.ts +247 -0
  764. package/src/llm/provider-probe.ts +57 -0
  765. package/src/llm.ts +55 -23
  766. package/src/log-entry.ts +1 -1
  767. package/src/log-pane/attachment-popup.ts +1 -2
  768. package/src/loops/loop-cli.ts +37 -0
  769. package/src/loops/registry.ts +174 -0
  770. package/src/market/official-keys.ts +5 -0
  771. package/src/market/publish.ts +273 -0
  772. package/src/market/signed-index.ts +156 -0
  773. package/src/market/tgz.ts +121 -0
  774. package/src/mcp/client.ts +1 -1
  775. package/src/mcp/mcp-oauth.ts +40 -5
  776. package/src/mcp/server.ts +75 -7
  777. package/src/mcp-gateway/gateway.ts +128 -0
  778. package/src/mcp-gateway/pat-store.ts +124 -0
  779. package/src/mss/logging/log-store.ts +91 -2
  780. package/src/mss/logging/scoped-level.ts +5 -9
  781. package/src/native-tool-catalog.ts +64 -343
  782. package/src/nexus/api/connect-info.ts +23 -25
  783. package/src/nexus/api/context-url.ts +1 -1
  784. package/src/nexus/api/design-check.ts +90 -59
  785. package/src/nexus/api/design-previews-route.ts +182 -0
  786. package/src/nexus/api/design-system-create-route.ts +123 -0
  787. package/src/nexus/api/graph-kinds.ts +69 -0
  788. package/src/nexus/api/graphs-api.ts +221 -0
  789. package/src/nexus/api/harness-api.ts +31 -2
  790. package/src/nexus/api/health.ts +15 -0
  791. package/src/nexus/api/http-server.ts +274 -43
  792. package/src/nexus/api/image-generate.ts +3 -0
  793. package/src/nexus/api/ingest-token.ts +175 -0
  794. package/src/nexus/api/intake-ledger-api.ts +54 -0
  795. package/src/nexus/api/intake-route.ts +111 -0
  796. package/src/nexus/api/json-response.ts +33 -0
  797. package/src/nexus/api/live-detail.ts +47 -0
  798. package/src/nexus/api/live-shipped.ts +78 -0
  799. package/src/nexus/api/log-fabric.ts +33 -2
  800. package/src/nexus/api/markdown-publish.ts +3 -2
  801. package/src/nexus/api/mcp-http.ts +14 -9
  802. package/src/nexus/api/mcp-oauth-hint.ts +30 -0
  803. package/src/nexus/api/mcp-public-allowlist.ts +33 -0
  804. package/src/nexus/api/merge-approvals-gate.ts +79 -0
  805. package/src/nexus/api/merge-approvals.ts +306 -0
  806. package/src/nexus/api/meta-api.ts +4 -0
  807. package/src/nexus/api/next-fluent-wiring.ts +7 -9
  808. package/src/nexus/api/plugins-market.ts +125 -0
  809. package/src/nexus/api/pod-credential-api.ts +133 -0
  810. package/src/nexus/api/public-routes.ts +80 -0
  811. package/src/nexus/api/rest-route-paths.ts +15 -0
  812. package/src/nexus/api/schedules-action.ts +12 -3
  813. package/src/nexus/api/schedules-read.ts +228 -0
  814. package/src/nexus/api/sessions-store.ts +8 -2
  815. package/src/nexus/api/setup-answer-priority.ts +130 -0
  816. package/src/nexus/api/setup-channel-bot.ts +56 -0
  817. package/src/nexus/api/setup-child-llm.ts +228 -0
  818. package/src/nexus/api/setup-obsidian-skills.ts +93 -0
  819. package/src/nexus/api/task-cards-api.ts +34 -0
  820. package/src/nexus/api/tasks-create.ts +136 -0
  821. package/src/nexus/api/telegram-trigger-bot.ts +3 -3
  822. package/src/nexus/api/terminals.ts +204 -18
  823. package/src/nexus/api/trace.ts +354 -0
  824. package/src/nexus/api/vault-api.ts +140 -7
  825. package/src/nexus/api/worktrees.ts +18 -2
  826. package/src/nexus/boot/register-mcp-clients.ts +38 -4
  827. package/src/nexus/daemon-endpoint.ts +85 -0
  828. package/src/nexus/default-port.ts +1 -0
  829. package/src/nexus/index.ts +329 -111
  830. package/src/nexus/onboarding/pwa-share-prompt.ts +31 -8
  831. package/src/nexus/onboarding/tailscale-probe.ts +9 -1
  832. package/src/nexus/setup-status.ts +58 -0
  833. package/src/nexus/supervisor/lock.ts +8 -0
  834. package/src/nexus/webterm/pty.ts +15 -0
  835. package/src/oauth/codex-account-rotation.ts +122 -16
  836. package/src/oauth/codex-account-store.ts +88 -19
  837. package/src/oauth/codex-quota-policy.ts +55 -0
  838. package/src/oauth/store.ts +28 -25
  839. package/src/obsidian/default-vault.ts +17 -0
  840. package/src/obsidian/vault-write-guard.ts +46 -0
  841. package/src/onboarding/help/llm.md +2 -2
  842. package/src/onboarding.ts +2 -2
  843. package/src/panes/alt-skip-predicate.ts +4 -3
  844. package/src/panes/external-terminal-pane.ts +3 -4
  845. package/src/panes/factory.ts +1 -18
  846. package/src/panes/index.ts +1 -5
  847. package/src/panes/pane-cycle.ts +1 -1
  848. package/src/panes/types.ts +1 -1
  849. package/src/platform/env-literal.ts +4 -0
  850. package/src/plugin-hooks/dispatcher.ts +10 -4
  851. package/src/plugins/core/host.ts +94 -4
  852. package/src/plugins/core/manifest.ts +104 -7
  853. package/src/plugins/install/market-fetch.ts +249 -0
  854. package/src/plugins/install/plugin-install.ts +387 -0
  855. package/src/policy/claude-subscription-guard.ts +25 -0
  856. package/src/preview/terminal.ts +24 -1
  857. package/src/preview-pane/mount.ts +1 -142
  858. package/src/prompt/references.ts +4 -51
  859. package/src/pty-shell/pty-control-ipc.ts +57 -3
  860. package/src/pty-shell/pty-mouse.ts +75 -0
  861. package/src/pty-shell/pty-recording.ts +108 -0
  862. package/src/pty-shell/registry.ts +53 -3
  863. package/src/python/resolve-python.ts +1 -1
  864. package/src/release-loop/manifest.ts +65 -0
  865. package/src/release-loop/release-note.ts +174 -0
  866. package/src/roles/lease-cas.ts +52 -0
  867. package/src/roles/machine-name.ts +48 -0
  868. package/src/roles/machine-profile.ts +65 -0
  869. package/src/roles/role-lease-read.ts +81 -0
  870. package/src/roles/role-lease.ts +63 -0
  871. package/src/roles/role-watch.ts +69 -0
  872. package/src/self-dev/ask-launch-flow.ts +39 -22
  873. package/src/self-dev/ask-launch-io.ts +1 -1
  874. package/src/self-dev/dev-cli.ts +250 -139
  875. package/src/self-dev/dev-pipeline.ts +80 -8
  876. package/src/self-dev/draft-sweep.ts +231 -0
  877. package/src/self-dev/draft-triage-rules.ts +42 -0
  878. package/src/self-dev/entrance-baseline.ts +156 -4
  879. package/src/self-dev/fabric-decompose-adapter.ts +10 -0
  880. package/src/self-dev/launch-preflight.ts +1 -1
  881. package/src/self-dev/orchestrate.ts +297 -20
  882. package/src/self-dev/repair-signals.ts +6 -0
  883. package/src/self-dev/run-store.ts +20 -5
  884. package/src/self-dev/run-supervisor.ts +43 -3
  885. package/src/self-implement/abandoned-classification.ts +15 -1
  886. package/src/self-implement/blocked-draft-policy.ts +6 -0
  887. package/src/self-implement/budget-gate.ts +236 -0
  888. package/src/self-implement/child-llm-preference.ts +84 -0
  889. package/src/self-implement/decision-events.ts +57 -0
  890. package/src/self-implement/decision-signal-press.ts +5 -2
  891. package/src/self-implement/dependency-change-gate.ts +90 -0
  892. package/src/self-implement/gate-baseline.ts +32 -1
  893. package/src/self-implement/gate-cli.ts +29 -7
  894. package/src/self-implement/gate-scope.ts +7 -1
  895. package/src/self-implement/goal-author-decompose.ts +22 -4
  896. package/src/self-implement/goal-author.ts +23 -2
  897. package/src/self-implement/goal-boundary.ts +65 -0
  898. package/src/self-implement/goal-clarification-escalation.ts +1 -0
  899. package/src/self-implement/goal-documents-dir.ts +6 -1
  900. package/src/self-implement/goal-execution-records.ts +58 -0
  901. package/src/self-implement/goal-run-store.ts +42 -24
  902. package/src/self-implement/graph-authority.ts +13 -28
  903. package/src/self-implement/graph-catalog.ts +48 -0
  904. package/src/self-implement/graph-run-contract.ts +127 -0
  905. package/src/self-implement/graph-templates.ts +14 -7
  906. package/src/self-implement/graph-yaml.ts +35 -6
  907. package/src/self-implement/harness-policy-gates.ts +42 -0
  908. package/src/self-implement/headless-elanous-driver.ts +30 -6
  909. package/src/self-implement/heal-triage.ts +229 -0
  910. package/src/self-implement/host-regate.ts +240 -0
  911. package/src/self-implement/non-git-consent.ts +23 -0
  912. package/src/self-implement/orchestrator.ts +481 -132
  913. package/src/self-implement/pipeline-shape.ts +1 -1
  914. package/src/self-implement/pr-evidence-artifact.ts +6 -19
  915. package/src/self-implement/prior-draft-findings.ts +128 -0
  916. package/src/self-implement/pwa-import-graph.ts +65 -0
  917. package/src/self-implement/repo-provision.ts +18 -21
  918. package/src/self-implement/report-origin.ts +39 -0
  919. package/src/self-implement/rework-policy.ts +21 -0
  920. package/src/self-implement/run-ledger-compact.ts +438 -0
  921. package/src/self-implement/run-ledger.ts +212 -29
  922. package/src/self-implement/run-report.ts +24 -0
  923. package/src/self-implement/run-status-mapping.ts +2 -0
  924. package/src/self-implement/running-runs.ts +112 -14
  925. package/src/self-implement/scoped-typecheck-config.ts +49 -0
  926. package/src/self-implement/seams.ts +203 -38
  927. package/src/self-implement/self-implement-cli.ts +17 -2
  928. package/src/self-implement/shadow-repo.ts +350 -0
  929. package/src/self-implement/supervision-vocabulary.ts +7 -0
  930. package/src/shell-runner/dispatch.ts +3 -0
  931. package/src/shell-runner/index.ts +0 -7
  932. package/src/skills/runner.ts +0 -69
  933. package/src/skills/tools/agent-room-slash.ts +2 -1
  934. package/src/skills/tools/agent-room.ts +8 -140
  935. package/src/skills/tools/agent.ts +5 -3
  936. package/src/skills/tools/context.ts +5 -140
  937. package/src/skills/tools/control.ts +4 -188
  938. package/src/skills/tools/dashboard-slash.ts +3 -11
  939. package/src/skills/tools/dashboard-state.ts +3 -5
  940. package/src/skills/tools/dev-harness.ts +3 -2
  941. package/src/skills/tools/omni-search.ts +29 -1
  942. package/src/skills/tools/shell.ts +11 -29
  943. package/src/skills/tools/spawn-coding-agent-headless.ts +6 -9
  944. package/src/ssh/ssh-picker-modal.ts +1 -1
  945. package/src/steward/directive.ts +99 -0
  946. package/src/steward/triage.ts +203 -0
  947. package/src/storage/cli-bin.ts +67 -0
  948. package/src/storage/object-store-visibility.ts +169 -0
  949. package/src/storage/object-store.ts +452 -0
  950. package/src/storage/s3.ts +53 -10
  951. package/src/storage/storage-detect.ts +337 -0
  952. package/src/surface/address.ts +3 -5
  953. package/src/surface/index.ts +0 -6
  954. package/src/surface/llm-tools.ts +1 -2
  955. package/src/surface/shell-runner-boot.ts +4 -89
  956. package/src/task-cards/card-cli.ts +64 -0
  957. package/src/task-cards/card-store.ts +241 -0
  958. package/src/task-orchestrator/boot.ts +27 -1
  959. package/src/task-orchestrator/dispatcher.ts +49 -7
  960. package/src/task-orchestrator/external-fingerprint.ts +10 -0
  961. package/src/task-orchestrator/external-policy.ts +86 -0
  962. package/src/task-orchestrator/feedback-loop.ts +4 -2
  963. package/src/task-orchestrator/graph.ts +18 -1
  964. package/src/task-orchestrator/runtimes/create.ts +128 -0
  965. package/src/task-orchestrator/store.ts +78 -18
  966. package/src/task-orchestrator/surface-registry.ts +5 -2
  967. package/src/task-orchestrator/surfaces/external-exec.ts +180 -0
  968. package/src/task-orchestrator/surfaces/idea-approval-pr.ts +118 -0
  969. package/src/task-orchestrator/surfaces/index.ts +4 -3
  970. package/src/task-orchestrator/surfaces/pod-account-broker.ts +60 -5
  971. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +136 -0
  972. package/src/task-orchestrator/surfaces/pod-command-job.ts +348 -0
  973. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +177 -0
  974. package/src/task-orchestrator/surfaces/pod-pool.ts +128 -12
  975. package/src/task-orchestrator/surfaces/pod-skills.ts +11 -3
  976. package/src/task-orchestrator/surfaces/pod-source-bundle.ts +132 -0
  977. package/src/task-orchestrator/surfaces/pod-source-receive.ts +91 -0
  978. package/src/task-orchestrator/surfaces/pod-source-spec.ts +77 -0
  979. package/src/task-orchestrator/surfaces/self-implement-pod.ts +782 -41
  980. package/src/task-orchestrator/surfaces/self-implement.ts +8 -1
  981. package/src/task-orchestrator/tox-loop.ts +204 -0
  982. package/src/task-orchestrator/types.ts +21 -1
  983. package/src/telegram-commands.ts +8 -0
  984. package/src/telegram-report.ts +2 -1
  985. package/src/telegram-run.ts +18 -5
  986. package/src/telegram.ts +92 -22
  987. package/src/tool-runtime/acp-session-runtime.ts +28 -7
  988. package/src/tool-runtime/agent-runtime.ts +1 -0
  989. package/src/tool-runtime/context-runtime.ts +18 -35
  990. package/src/tool-runtime/control-runtime.ts +8 -21
  991. package/src/tool-runtime/dashboard-state-runtime.ts +1 -5
  992. package/src/tool-runtime/elanous-asana-runtimes.ts +205 -0
  993. package/src/tool-runtime/elanous-control-runtimes.ts +16 -2
  994. package/src/tool-runtime/elanous-task-submit-runtime.ts +124 -0
  995. package/src/tool-runtime/index.ts +4 -1
  996. package/src/tool-runtime/scenario-runtimes.ts +22 -21
  997. package/src/tool-runtime/scenario-target-mount.ts +6 -32
  998. package/src/tool-runtime/types.ts +8 -0
  999. package/src/tui/chat/attachment-summary.ts +4 -4
  1000. package/src/tui-client/headless-core-guard.ts +0 -1
  1001. package/src/tui.ts +8 -5
  1002. package/src/typecheck-ratchet.ts +15 -0
  1003. package/src/ui/hover-presenter.ts +3 -7
  1004. package/src/user-config.ts +427 -190
  1005. package/src/version/code-revision.ts +33 -8
  1006. package/src/version/packed-revision.json +1 -1
  1007. package/src/video-pipeline/broll-agent.ts +102 -0
  1008. package/src/video-pipeline/recipes/broll.ts +263 -0
  1009. package/src/video-pipeline/walk-line.ts +2 -1
  1010. package/src/views/scratch-image-size.ts +10 -0
  1011. package/src/voice/channel-adapters/pwa-voice-adapter.ts +2 -18
  1012. package/src/voice/channel-adapters/telegram-voice-adapter.ts +1 -6
  1013. package/src/voice/voice-tts-singleton.ts +46 -8
  1014. package/src/web-push/vapid-keys.ts +1 -1
  1015. package/src/web-search/index.ts +5 -5
  1016. package/src/web-terminal/preview-tap-registry.ts +152 -43
  1017. package/src/workflow-runtime/executor.ts +18 -22
  1018. package/src/workflow-runtime/node-catalog.ts +20 -1
  1019. package/src/workflow-runtime/nodes/bash.ts +1 -0
  1020. package/src/workflow-runtime/nodes/task.ts +74 -0
  1021. package/src/workflow-runtime/nodes/triggers.ts +24 -1
  1022. package/src/workflow-runtime/plugin-kind-node.ts +138 -0
  1023. package/src/workflow-runtime/schema.ts +98 -2
  1024. package/src/workflow-runtime/triggers/webhook-router.ts +43 -3
  1025. package/src/workflow-runtime/triggers/webhook-source.ts +19 -1
  1026. package/src/workflow-runtime/types.ts +74 -4
  1027. package/apps/pwa/out/_next/static/Ksn99fVf2HUWhSyV1-FC8/_buildManifest.js +0 -1
  1028. package/apps/pwa/out/_next/static/chunks/1176-4943bd83b00e53a2.js +0 -25
  1029. package/apps/pwa/out/_next/static/chunks/1380-9c652e1002032c86.js +0 -1
  1030. package/apps/pwa/out/_next/static/chunks/1863-2ea170dfec26b88b.js +0 -1
  1031. package/apps/pwa/out/_next/static/chunks/2091-2d6b7f4f16300f83.js +0 -1
  1032. package/apps/pwa/out/_next/static/chunks/2347-366617ec73babe3b.js +0 -1
  1033. package/apps/pwa/out/_next/static/chunks/2598.814f64e3268634e7.js +0 -1
  1034. package/apps/pwa/out/_next/static/chunks/3089-e60cc8f5d35ee239.js +0 -1
  1035. package/apps/pwa/out/_next/static/chunks/3158-c77ed9ea34f9cc9f.js +0 -1
  1036. package/apps/pwa/out/_next/static/chunks/3607-f0b5c5ee18fcf56a.js +0 -1
  1037. package/apps/pwa/out/_next/static/chunks/3659-05b2d5d971b42dbc.js +0 -1
  1038. package/apps/pwa/out/_next/static/chunks/3736-b6a7bfdcb8f56ec6.js +0 -1
  1039. package/apps/pwa/out/_next/static/chunks/3839-eebf298e89a7bb77.js +0 -1
  1040. package/apps/pwa/out/_next/static/chunks/4012.832a2824b978e7ee.js +0 -5
  1041. package/apps/pwa/out/_next/static/chunks/4706-d85d7f3345f3ff91.js +0 -1
  1042. package/apps/pwa/out/_next/static/chunks/526-17a6a2e0e6dc4498.js +0 -1
  1043. package/apps/pwa/out/_next/static/chunks/5508-676ac75f2757ad40.js +0 -1
  1044. package/apps/pwa/out/_next/static/chunks/5583-8a0317f4b8e68db9.js +0 -1
  1045. package/apps/pwa/out/_next/static/chunks/5927.8378481a12cc8044.js +0 -1
  1046. package/apps/pwa/out/_next/static/chunks/6258-b58f722b10e8d31d.js +0 -1
  1047. package/apps/pwa/out/_next/static/chunks/6820-32fd097e6186fdc9.js +0 -1
  1048. package/apps/pwa/out/_next/static/chunks/6852-983db7ca958634b7.js +0 -1
  1049. package/apps/pwa/out/_next/static/chunks/7235-e583e4a015e159b9.js +0 -1
  1050. package/apps/pwa/out/_next/static/chunks/7482-7b417330b24a996a.js +0 -1
  1051. package/apps/pwa/out/_next/static/chunks/7701-99b7d4dedb955bf8.js +0 -1
  1052. package/apps/pwa/out/_next/static/chunks/77f1928d-bd3777589042d3ea.js +0 -1
  1053. package/apps/pwa/out/_next/static/chunks/8366-36956cafc5e33614.js +0 -1
  1054. package/apps/pwa/out/_next/static/chunks/8370-23d0de995be666f8.js +0 -1
  1055. package/apps/pwa/out/_next/static/chunks/8617-307421f3b0e8b2a2.js +0 -1
  1056. package/apps/pwa/out/_next/static/chunks/8837-e45de46a9fedf1f5.js +0 -1
  1057. package/apps/pwa/out/_next/static/chunks/9058-0e8055a5ea3ebdd6.js +0 -1
  1058. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-84b84eca12acada4.js +0 -1
  1059. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1f23568c29e88f7a.js +0 -1
  1060. package/apps/pwa/out/_next/static/chunks/app/botlab/page-bf6fc9aafd6135a7.js +0 -1
  1061. package/apps/pwa/out/_next/static/chunks/app/bots/page-3f8539ae4b719d2e.js +0 -1
  1062. package/apps/pwa/out/_next/static/chunks/app/chat/page-d2900febb74ecf32.js +0 -1
  1063. package/apps/pwa/out/_next/static/chunks/app/control/page-e82dec647dd79c36.js +0 -1
  1064. package/apps/pwa/out/_next/static/chunks/app/dashboard/page-096ec743a8ee955a.js +0 -1
  1065. package/apps/pwa/out/_next/static/chunks/app/design-check/page-255c2ceded4b3493.js +0 -1
  1066. package/apps/pwa/out/_next/static/chunks/app/healthz/route-84b84eca12acada4.js +0 -1
  1067. package/apps/pwa/out/_next/static/chunks/app/intake/page-2db61b2f9efba61f.js +0 -1
  1068. package/apps/pwa/out/_next/static/chunks/app/layout-e11ee17f221aaa9b.js +0 -1
  1069. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e075974e029ce4c4.js +0 -1
  1070. package/apps/pwa/out/_next/static/chunks/app/morning/page-ec5b68a9af3366a0.js +0 -1
  1071. package/apps/pwa/out/_next/static/chunks/app/not-found-986c177afb4adae6.js +0 -1
  1072. package/apps/pwa/out/_next/static/chunks/app/observatory/page-a72781461af2f2a3.js +0 -1
  1073. package/apps/pwa/out/_next/static/chunks/app/page-92781cbaafc487ad.js +0 -1
  1074. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2c14d2a1f2930f33.js +0 -1
  1075. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-22ee4bf8070b2b4d.js +0 -1
  1076. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9c06e4a8297942a8.js +0 -1
  1077. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d0cd32f6d373798f.js +0 -1
  1078. package/apps/pwa/out/_next/static/chunks/app/settings/page-0c1642018d87ebb8.js +0 -1
  1079. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-93e5e97d614df487.js +0 -1
  1080. package/apps/pwa/out/_next/static/chunks/app/setup/layout-84b84eca12acada4.js +0 -1
  1081. package/apps/pwa/out/_next/static/chunks/app/setup/page-b1ce871940d7393e.js +0 -1
  1082. package/apps/pwa/out/_next/static/chunks/app/share/page-ae154addf345febe.js +0 -1
  1083. package/apps/pwa/out/_next/static/chunks/app/showroom/page-90af3aa813d2053c.js +0 -1
  1084. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f3f962fda428a738.js +0 -1
  1085. package/apps/pwa/out/_next/static/chunks/app/term/page-1c1f7cc1d5def06d.js +0 -1
  1086. package/apps/pwa/out/_next/static/chunks/app/vault/page-09d4cbdaaacf06c1.js +0 -1
  1087. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e877b8e8ca90b27f.js +0 -1
  1088. package/apps/pwa/out/_next/static/chunks/app/workflows/page-71d902f463dea526.js +0 -1
  1089. package/apps/pwa/out/_next/static/chunks/app/workspace/page-40ea576cefa25fe6.js +0 -1
  1090. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a56a3f178c3831f6.js +0 -1
  1091. package/apps/pwa/out/_next/static/chunks/bcc499d1-804a270d878e0842.js +0 -1
  1092. package/apps/pwa/out/_next/static/chunks/framework-b25b7c5501c59b6d.js +0 -1
  1093. package/apps/pwa/out/_next/static/chunks/main-a9ec9da43387afff.js +0 -1
  1094. package/apps/pwa/out/_next/static/chunks/main-app-aa2c05954aaa6754.js +0 -1
  1095. package/apps/pwa/out/_next/static/chunks/pages/_app-bb3768fb4b84aebb.js +0 -1
  1096. package/apps/pwa/out/_next/static/chunks/pages/_error-2820ba75b87b2f5e.js +0 -1
  1097. package/apps/pwa/out/_next/static/chunks/webpack-58c73b145f189b1c.js +0 -1
  1098. package/apps/pwa/out/_next/static/css/effec8adf767aa75.css +0 -1
  1099. package/apps/pwa/out/dashboard/index.html +0 -1
  1100. package/apps/pwa/out/dashboard/index.txt +0 -26
  1101. package/src/acp/resident-shell.ts +0 -244
  1102. package/src/agent/spawn-local-llm-in-vw.ts +0 -240
  1103. package/src/dashboard/agent-spawn-tools-boot.ts +0 -14
  1104. package/src/dashboard/dock-picker-inventory.ts +0 -41
  1105. package/src/dashboard/goal-plan-hud-bridge.ts +0 -112
  1106. package/src/dashboard/hud-mirror.ts +0 -207
  1107. package/src/dashboard/input/mouse-dock-runtime.ts +0 -156
  1108. package/src/dashboard/input/mouse-hover-runtime.ts +0 -46
  1109. package/src/dashboard/input/mouse-pill-context-runtime.ts +0 -74
  1110. package/src/dashboard/input/mouse-workspace-restore-runtime.ts +0 -64
  1111. package/src/dashboard/input/scratch-actions.ts +0 -36
  1112. package/src/dashboard/input/virtual-window-key-router.ts +0 -24
  1113. package/src/dashboard/rich-scratch-viewers.ts +0 -77
  1114. package/src/dashboard/scratch-slash-runtime.ts +0 -36
  1115. package/src/dashboard/scratch-state-runtime.ts +0 -42
  1116. package/src/dashboard/scratch-widget-runtime.ts +0 -37
  1117. package/src/dashboard/sim-shell.ts +0 -313
  1118. package/src/dashboard/virtual-window-control-runtime.ts +0 -57
  1119. package/src/dashboard/virtual-window-help-runtime.ts +0 -113
  1120. package/src/dashboard/virtual-window-input-runtime.ts +0 -99
  1121. package/src/dashboard/virtual-window-mutation-runtime.ts +0 -102
  1122. package/src/dashboard/virtual-window-split-runtime.ts +0 -70
  1123. package/src/dashboard/vw-popup-openers.ts +0 -126
  1124. package/src/dashboard/window-picker-popup.ts +0 -74
  1125. package/src/dashboard/window-slash-runtime.ts +0 -108
  1126. package/src/dashboard/windowing/companion-slash.ts +0 -78
  1127. package/src/dashboard/windowing/fast-switch.ts +0 -138
  1128. package/src/dashboard/windowing/lifecycle.ts +0 -185
  1129. package/src/dashboard/windowing/virtual-windows.ts +0 -259
  1130. package/src/dashboard/windowing/visibility-chord.ts +0 -77
  1131. package/src/iul/resident-vw.ts +0 -55
  1132. package/src/panes/content-adapter.ts +0 -162
  1133. package/src/prompt/vw-reference.ts +0 -153
  1134. package/src/shell-runner/external-terminal-pane.ts +0 -157
  1135. package/src/sim/resident-vw.ts +0 -48
  1136. package/src/skills/tools/spawn-coding-agent-vw.ts +0 -181
  1137. package/src/skills/tools/virtual-windows.ts +0 -632
  1138. package/src/surface/adapters/window-surface-adapter.ts +0 -141
  1139. package/src/tool-runtime/layout-runtimes.ts +0 -81
  1140. package/src/tool-runtime/scenario-window-mount.ts +0 -207
  1141. package/src/views/ui-mode.ts +0 -100
  1142. package/src/virtual-window-context-menu.ts +0 -97
  1143. package/src/virtual-windows/addressing.ts +0 -195
  1144. package/src/virtual-windows/benchmark-preset.ts +0 -119
  1145. package/src/virtual-windows/event-bus.ts +0 -202
  1146. package/src/virtual-windows/layout/apply-planner.ts +0 -189
  1147. package/src/virtual-windows/layout/index.ts +0 -68
  1148. package/src/virtual-windows/layout/layout-commands.ts +0 -186
  1149. package/src/virtual-windows/layout/layout-tools.ts +0 -262
  1150. package/src/virtual-windows/layout/persistence.ts +0 -219
  1151. package/src/virtual-windows/layout/presets.ts +0 -114
  1152. package/src/virtual-windows/layout/restore-planner.ts +0 -223
  1153. package/src/virtual-windows/layout/serializer.ts +0 -197
  1154. package/src/virtual-windows/layout/tree.ts +0 -147
  1155. package/src/virtual-windows/layout/types.ts +0 -63
  1156. package/src/virtual-windows/layout-tree.ts +0 -389
  1157. package/src/virtual-windows/navigation.ts +0 -251
  1158. package/src/virtual-windows/pane-capture.ts +0 -142
  1159. package/src/virtual-windows/pane-content.ts +0 -611
  1160. package/src/virtual-windows/pane-spawner.ts +0 -278
  1161. package/src/virtual-windows/pty-tail-content.ts +0 -291
  1162. package/src/virtual-windows/resident-window.ts +0 -59
  1163. package/src/virtual-windows/secondary-action.ts +0 -25
  1164. package/src/virtual-windows/terminal-slot-content.ts +0 -165
  1165. package/src/virtual-windows/virtual-window.ts +0 -1301
  1166. package/src/virtual-windows/vw-local-input-target-popup.ts +0 -110
  1167. package/src/virtual-windows/vw-rename-modal.ts +0 -77
  1168. package/src/virtual-windows/vw-selector-popup.ts +0 -177
  1169. package/src/virtual-windows/window-registry.ts +0 -519
  1170. package/src/voice/channel-adapters/discord-voice-adapter.ts +0 -202
  1171. package/src/voice/voice-pwa-dispatch.ts +0 -245
  1172. package/src/window-picker-modal.ts +0 -135
  1173. /package/apps/pwa/out/_next/static/{Ksn99fVf2HUWhSyV1-FC8 → zoQX5iTvXOsIvCjxCe1Ji}/_ssgManifest.js +0 -0
  1174. /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
 
@@ -3314,13 +3381,30 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3314
3381
  };
3315
3382
  let loopRegistered = false;
3316
3383
  let mergeApprovalReceived = false;
3384
+ let autoMergeAuthorizedBeforeSync = false;
3317
3385
  let lastParsedSupervisorVerdict: ReworkBudgetVerdict | undefined;
3318
3386
  let lastParsedSupervisorReason: string | undefined;
3319
3387
  let providerErrorCount = 0;
3320
3388
  let credentialFailureCount = 0;
3389
+ let failureSequence = 0;
3390
+ let lastProviderErrorSeq = 0;
3391
+ let lastCredentialFailureSeq = 0;
3392
+ let lastFailedGateSeq = 0;
3393
+ let lastMustFixReviewSeq = 0;
3394
+ const recordFailureVerdict = async (kind: 'gate' | 'review'): Promise<void> => {
3395
+ // Capture child errors at the verdict boundary, not when terminal reporting eventually reads them.
3396
+ await mergeChildProviderErrors();
3397
+ if (kind === 'gate') lastFailedGateSeq = ++failureSequence;
3398
+ else lastMustFixReviewSeq = ++failureSequence;
3399
+ };
3400
+ const latestVerdictSeq = (): number => Math.max(lastFailedGateSeq, lastMustFixReviewSeq);
3401
+ const hasCurrentProviderError = (): boolean => providerErrorCount > 0 && lastProviderErrorSeq > latestVerdictSeq();
3402
+ const hasCurrentCredentialFailure = (): boolean => credentialFailureCount > 0 && lastCredentialFailureSeq > latestVerdictSeq();
3321
3403
  let lastProviderError: { provider?: string; message?: string } | undefined;
3322
3404
  let lastCredentialFailure: { provider?: string; message?: string } | undefined;
3323
3405
  let childProviderErrorQueryStatus: 'found' | 'none' | 'unavailable' | 'not-configured' = 'not-configured';
3406
+ let queriedProviderErrorCount = 0;
3407
+ let queriedCredentialFailureCount = 0;
3324
3408
  const providerErrorsForResult = (): Pick<SelfImplementResult, 'providerErrors'> => {
3325
3409
  if (providerErrorCount === 0) return {};
3326
3410
  const message = lastProviderError?.message ?? '';
@@ -3340,8 +3424,14 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3340
3424
  const result = await query({ runId, sinceMs: startedAtMs, untilMs: Date.now() });
3341
3425
  childProviderErrorQueryStatus = result.status;
3342
3426
  if (result.status !== 'found') return;
3343
- providerErrorCount += result.providerErrorCount;
3344
- credentialFailureCount += result.credentialFailureCount;
3427
+ const newProviderErrors = Math.max(0, result.providerErrorCount - queriedProviderErrorCount);
3428
+ const newCredentialFailures = Math.max(0, result.credentialFailureCount - queriedCredentialFailureCount);
3429
+ providerErrorCount += newProviderErrors;
3430
+ credentialFailureCount += newCredentialFailures;
3431
+ if (newProviderErrors > 0) lastProviderErrorSeq = ++failureSequence;
3432
+ if (newCredentialFailures > 0) lastCredentialFailureSeq = newProviderErrors > 0 ? lastProviderErrorSeq : ++failureSequence;
3433
+ queriedProviderErrorCount = Math.max(queriedProviderErrorCount, result.providerErrorCount);
3434
+ queriedCredentialFailureCount = Math.max(queriedCredentialFailureCount, result.credentialFailureCount);
3345
3435
  lastProviderError = result.lastProviderError ?? lastProviderError;
3346
3436
  lastCredentialFailure = result.lastCredentialFailure ?? lastCredentialFailure;
3347
3437
  } catch {
@@ -3356,6 +3446,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3356
3446
  if (!data || typeof data !== 'object') return;
3357
3447
  const { provider, message } = data as Record<string, unknown>;
3358
3448
  providerErrorCount++;
3449
+ lastProviderErrorSeq = ++failureSequence;
3359
3450
  lastProviderError = {
3360
3451
  ...(typeof provider === 'string' ? { provider } : {}),
3361
3452
  ...(typeof message === 'string' ? { message } : {}),
@@ -3371,6 +3462,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3371
3462
  // 여기서 문면 정규식으로 다시 재면 소비자마다 다른 답이 나온다.
3372
3463
  if ((data as Record<string, unknown>).authRejected === true) {
3373
3464
  credentialFailureCount++;
3465
+ lastCredentialFailureSeq = lastProviderErrorSeq;
3374
3466
  lastCredentialFailure = { ...lastProviderError };
3375
3467
  }
3376
3468
  },
@@ -3379,6 +3471,15 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3379
3471
  const progressDelivery = { delivered: 0, unwired: 0, callbackFailed: 0 };
3380
3472
  let capturedPrNumber: number | undefined;
3381
3473
  let openPrInvoked = false;
3474
+ const defaultProviderName = opts.seams.currentProviderName?.() ?? currentProviderName();
3475
+ const runProviderName = opts.childLlm?.provider ?? defaultProviderName;
3476
+ const logQuotaProvider = (assessment: QuotaExhaustionAssessment | undefined): void => {
3477
+ try {
3478
+ debug.log('self-implement.abandoned', 'quota-provider', {
3479
+ runProvider: runProviderName, defaultProvider: defaultProviderName, used: assessment?.exhausted !== undefined,
3480
+ });
3481
+ } catch { /* observation must not change the terminal result */ }
3482
+ };
3382
3483
  const instrumentedOpts: SelfImplementOptions = {
3383
3484
  ...opts,
3384
3485
  seams: {
@@ -3418,6 +3519,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3418
3519
  /** ⭐ 방문 예산을 읽으려면 «지금 도는 선언»이 필요하다 — 신원과 «같은 패턴»으로 한 번 심는다.
3419
3520
  * ⛔ 걸음(`traversedNodes`)은 이 스코프에 있고 선언은 안쪽에서 정해지므로, 둘을 잇는 자리가 여기다. */
3420
3521
  let runGraphTemplate: GraphTemplate | undefined;
3522
+ let runContract: RunContract | undefined;
3421
3523
  let runGraphIdentity: { graphId: string; graphVersion: string } | undefined;
3422
3524
  const setRunGraphIdentity = (identity: { graphId: string; graphVersion: string }): void => {
3423
3525
  runGraphIdentity = identity;
@@ -3469,6 +3571,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3469
3571
  traversedNodes.push(node);
3470
3572
  if (node === 'implement') roundCount++;
3471
3573
  const fallbackGraphIdentity = observedGraphIdentity();
3574
+ const contractAtNode = runContract === undefined ? undefined : runContractAtNode(runContract);
3472
3575
  observePipeline('pipeline-node-entry', {
3473
3576
  ...pipelineNodeEntryPayload(
3474
3577
  runGraphTemplate ?? { graphId: fallbackGraphIdentity.graphId, version: fallbackGraphIdentity.graphVersion, nodes: [] },
@@ -3476,7 +3579,15 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3476
3579
  ),
3477
3580
  node,
3478
3581
  round,
3582
+ ...contractAtNode,
3479
3583
  });
3584
+ if (contractAtNode?.contractHonored === false) {
3585
+ observeOuter('graph-contract-violation', {
3586
+ node, round,
3587
+ contractSubstrate: contractAtNode.contractSubstrate,
3588
+ actualSubstrate: contractAtNode.actualSubstrate,
3589
+ }, { level: 'warn' });
3590
+ }
3480
3591
  };
3481
3592
  const observeRoundClassification = (classification: LifecycleScreenComparison): void => {
3482
3593
  roundClassifications.push(classification);
@@ -3731,29 +3842,37 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3731
3842
  }),
3732
3843
  instrumentedOpts.seams.reworkBudgetReviewFindingRecurrence ?? (() => null),
3733
3844
  () => { mergeApprovalReceived = true; },
3845
+ () => { autoMergeAuthorizedBeforeSync = true; },
3734
3846
  (verdict) => { lastParsedSupervisorVerdict = verdict; },
3735
3847
  (reason) => { lastParsedSupervisorReason = reason; },
3736
3848
  (base) => { resolvedBase = base ?? undefined; },
3737
3849
  (basis) => { observationMeasurementBasis = basis; },
3738
3850
  (timeout) => { clarificationTimeout = timeout; },
3739
- () => providerErrorCount > 0,
3740
- () => credentialFailureCount > 0,
3741
- () => providerErrorsForResult().providerErrors?.category,
3851
+ hasCurrentProviderError,
3852
+ hasCurrentCredentialFailure,
3853
+ () => hasCurrentProviderError() ? providerErrorsForResult().providerErrors?.category : undefined,
3742
3854
  (rejectedCount) => { reviewReflectRejectedCount = (reviewReflectRejectedCount ?? 0) + rejectedCount; },
3743
3855
  observeOuter,
3744
3856
  (active) => { runActiveProvider = active; },
3745
3857
  (sessionId) => { terminalSessionId = sessionId; },
3858
+ (contract) => { runContract = contract; },
3859
+ recordFailureVerdict,
3860
+ () => providerErrorCount > 0,
3861
+ () => credentialFailureCount > 0,
3862
+ hasCurrentProviderError,
3863
+ hasCurrentCredentialFailure,
3746
3864
  );
3747
3865
  terminalNode = result.node;
3748
3866
  await mergeChildProviderErrors();
3749
3867
  const addressedResult = attachAbandonedClassification(
3750
3868
  attachReviewReflectionOutcome({ ...result, ...providerErrorsForResult(), runId, ...(lastParsedSupervisorReason ? { supervisorReason: lastParsedSupervisorReason } : {}), ...(mergeApprovalReceived ? { mergeApprovalReceived: true } : {}) }),
3751
3869
  opts.goalFile,
3752
- providerErrorCount > 0,
3753
- credentialFailureCount > 0,
3870
+ hasCurrentProviderError(),
3871
+ hasCurrentCredentialFailure(),
3754
3872
  opts.seams.inspectCodexRotation,
3755
- opts.seams.currentProviderName?.(),
3873
+ runProviderName,
3756
3874
  );
3875
+ if (isAbandonedClassificationOutcome(addressedResult.outcome)) logQuotaProvider(addressedResult.quotaExhaustionAssessment);
3757
3876
  observeOuter('child-provider-error-query', { status: childProviderErrorQueryStatus });
3758
3877
  if (lastProviderError) {
3759
3878
  observeOuter('provider-error-observed', { count: providerErrorCount, ...lastProviderError });
@@ -3823,14 +3942,15 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3823
3942
  branch,
3824
3943
  ...(worktreePath ? { worktreePath } : {}),
3825
3944
  ...(lastParsedSupervisorReason ? { supervisorReason: lastParsedSupervisorReason } : {}),
3826
- ...(mergeApprovalReceived ? { mergeApprovalReceived: true } : {}),
3945
+ ...(mergeApprovalReceived || (e.step === 'merge' && autoMergeAuthorizedBeforeSync) ? { mergeApprovalReceived: true } : {}),
3827
3946
  detail: worktreePath
3828
3947
  ? `자율 단계 '${e.step}' wall-clock ${e.ms}ms 초과 — hang 방지 종결(worktree 회수 경로: ${worktreePath})`
3829
3948
  : `자율 단계 '${e.step}' wall-clock ${e.ms}ms 초과 — hang 방지 종결(worktree 생성 전)`,
3830
3949
  };
3831
3950
  terminalNode = result.node;
3832
3951
  await mergeChildProviderErrors();
3833
- const addressedResult = attachAbandonedClassification(attachReviewReflectionOutcome({ ...result, ...providerErrorsForResult() }), opts.goalFile, providerErrorCount > 0, credentialFailureCount > 0, opts.seams.inspectCodexRotation, opts.seams.currentProviderName?.());
3952
+ const addressedResult = attachAbandonedClassification(attachReviewReflectionOutcome({ ...result, ...providerErrorsForResult() }), opts.goalFile, hasCurrentProviderError(), hasCurrentCredentialFailure(), opts.seams.inspectCodexRotation, runProviderName);
3953
+ logQuotaProvider(addressedResult.quotaExhaustionAssessment);
3834
3954
  observeOuter('child-provider-error-query', { status: childProviderErrorQueryStatus });
3835
3955
  if (lastProviderError) {
3836
3956
  observeOuter('provider-error-observed', { count: providerErrorCount, ...lastProviderError });
@@ -4012,12 +4132,24 @@ export function readQuotaExhausted(
4012
4132
  // ⛔⭐⭐⭐ 그리고 이 신호는 **codex 전용**이다(2R must-fix) — provider 를 «안 보면»
4013
4133
  // Claude·Grok 으로 돈 런까지 codex 쿼터로 «오분류»한다. 그건 이 PR 이 고치려던
4014
4134
  // 「잡통」의 «반대 방향» 오류다.
4015
- // ⚠️ 한계: 이것은 «부모의 현재 설정»이지 그 런이 실제로 쓴 provider 가 아니다
4016
- // (자식이 tier 를 올렸을 수 있다). 그 정확한 귀속은 자식 계측이 선결이라 별개 축이다.
4135
+ // 호출자는 구현 자식 provider 를 우선 넘긴다. 자식 선택이 없으면 프로세스 기본 provider 로 귀속한다.
4136
+ // 부모(리뷰·감독)의 별도 폴백이나 자식 내부 전환은 이 평가의 범위 밖이다.
4017
4137
  const snapshot = rotationInspector();
4018
4138
  // ⭐ 좁히지 않는다 — 스냅샷이 «이미 아는» 것을 증거로 그대로 옮긴다(`quotaAvailabilityEvidence`).
4019
4139
  // ⛔⭐ 「언제 읽었나」를 «값으로» 박는다 — 이 읽기는 런이 «끝난 뒤»다(타입 머리말 참조).
4020
- return assessQuotaExhaustion(providerName, { ...quotaAvailabilityEvidence(snapshot), readPoint: 'postmortem' });
4140
+ const evidence = { ...quotaAvailabilityEvidence(snapshot), readPoint: 'postmortem' as const };
4141
+ // ⛔⭐ 정본 스토어가 아는 계정이 «0개»면 회전이 구성되지 않은 것이다 — 「쓸 계정 없음」을 소진으로 읽지 않는다.
4142
+ // 🩸 P6(2026-09-26 Pod 실물): Pod 는 계정 사본 하나만 받고 회전 목록이 없어 no-candidate → 「할당량 소진」으로
4143
+ // 분류됐다. 진짜 원인(게이트의 tsc 127 · P5)이 그 오분류에 가려졌다. 호스트의 진짜 소진(계정은 있는데 전부 찼다)은 그대로다.
4144
+ if (snapshot.knownAccountCount === 0) return { exhausted: undefined, accountAvailability: evidence };
4145
+ // ⛔⭐ 아는 계정이 «하나»뿐이면 no-candidate 는 «돌릴 곳이 원래 없다»는 뜻이지 «찼다»가 아니다.
4146
+ // 🩸 P2 #20869(2026-09-27 Pod 실물): Pod 는 배분받은 계정 사본 «하나»(third · 잔량 넉넉)만 갖고 그 계정의 사용률 신호가
4147
+ // 없었다 → 회전은 no-candidate → 「할당량 소진」으로 분류돼 진짜 원인(리뷰 UNCONVERGEABLE)을 가렸다.
4148
+ // ⇒ 그 한 계정의 사용률도 도달 신호도 없으면 «모름». 사용률을 알면 종전 판정(임계 미만=false · 이상=true)에 맡긴다.
4149
+ if (snapshot.knownAccountCount === 1 && evidence.reason === 'no-candidate' && snapshot.currentUsedPercent === undefined && snapshot.currentReached !== true) {
4150
+ return { exhausted: undefined, accountAvailability: evidence };
4151
+ }
4152
+ return assessQuotaExhaustion(providerName, evidence);
4021
4153
  } catch {
4022
4154
  return { exhausted: undefined, accountAvailability: undefined }; // fail-soft — 관측은 결론을 막지 않는다
4023
4155
  }
@@ -4085,7 +4217,7 @@ export function attachAbandonedClassification(
4085
4217
  ...(quotaExhaustionAssessment.accountAvailability ? { quotaAccountAvailability: quotaExhaustionAssessment.accountAvailability } : {}),
4086
4218
  ...(credentialFailure ? { credentialFailure: true } : {}),
4087
4219
  ...(providerError ? { providerError: true } : {}),
4088
- ...(result.providerErrors?.category ? { providerErrorCategory: result.providerErrors.category } : {}),
4220
+ ...(providerError && result.providerErrors?.category ? { providerErrorCategory: result.providerErrors.category } : {}),
4089
4221
  worktreePorcelain: worktree.worktreePorcelain,
4090
4222
  ...(worktree.gitResidue ? { gitResidue: worktree.gitResidue } : {}),
4091
4223
  ...(result.completionDisposition ? { completionDisposition: result.completionDisposition } : {}),
@@ -4268,6 +4400,7 @@ async function runSelfImplementInner(
4268
4400
  * 이제 null 이면 measureReviewFindingRecurrence 가 «실제로» 잰다. */
4269
4401
  reworkBudgetReviewFindingRecurrence: () => ReviewFindingRecurrence | null = () => null,
4270
4402
  onMergeApprovalReceived: () => void = () => {},
4403
+ onAutoMergeAuthorizedBeforeSync: () => void = () => {},
4271
4404
  onSupervisorVerdictParsed: (verdict: ReworkBudgetVerdict) => void = () => {},
4272
4405
  onSupervisorReasonParsed: (reason: string | undefined) => void = () => {},
4273
4406
  onResolvedBase: (base: string | null) => void = () => {},
@@ -4282,16 +4415,20 @@ async function runSelfImplementInner(
4282
4415
  * (그러면 「런이 끝날 무렵의 provider」가 되어 `F45` 를 그대로 밟는다). 시작 시점 값을 넘긴다. */
4283
4416
  onActiveProvider: (active: { provider?: string; model?: string; auth?: string }) => void = () => {},
4284
4417
  onSessionCreated: (sessionId: string) => void = () => {},
4418
+ onRunContractResolved: (contract: RunContract) => void = () => {},
4419
+ onFailureVerdict: (kind: 'gate' | 'review') => Promise<void> = async () => {},
4420
+ hasObservedProviderError: () => boolean = hasProviderError,
4421
+ hasObservedCredentialFailure: () => boolean = hasCredentialFailure,
4422
+ hasCurrentProviderError: () => boolean = hasProviderError,
4423
+ hasCurrentCredentialFailure: () => boolean = hasCredentialFailure,
4285
4424
  ): Promise<Omit<SelfImplementResult, 'runId'>> {
4286
4425
  const s = opts.seams;
4287
4426
  const pipelineStartedAtMs = Date.now();
4288
- // Graph authority defaults ON and preserves flag → config → default provenance.
4427
+ // Graph authority is always ON; retain the resolved event with default provenance.
4289
4428
  // 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);
4429
+ const graphAuthority = resolveGraphAuthorityForUserConfig();
4292
4430
  // ⛔ 골 파일이 «없을 수» 있다 — 그때는 골 종류를 모르므로 implement-loop 으로 간다(없는 길로 안 보낸다).
4293
4431
  // ⭐ 대표 지시 ② «변형» — 「최초 결정 시 해당 템플릿 변형을 한다」.
4294
- // ⛔ 승격이 꺼져 있으면 `decideTemplate` 은 `activeTemplate` 과 «같은 값»을 낸다(고르지도 않는다).
4295
4432
  const graphGoalType = opts.goalFile === undefined ? undefined : (goalTypeFields(opts.goalFile).goalType as GoalType | undefined);
4296
4433
  // ⛔ 오버레이는 «한 번» 읽는다 — 라운드마다 디스크를 읽으면 도는 중에 파일이 바뀌어 걸음이 갈린다.
4297
4434
  // ⛔ 이름이 `graph`인 이유: launch(②)·runtime(③) «둘 다» 이 목록에서 고른다. 단계는 인자로 갈린다.
@@ -4308,24 +4445,28 @@ async function runSelfImplementInner(
4308
4445
  // ⛔⭐ `let` 인 이유는 ③ «다이나믹»이다 — 라운드마다 runtime 오버레이가 «앞을 보는 것»만 바꾼다.
4309
4446
  // ⛔ 지난 노드를 재정의하지 않는다(RFC §6: 그러면 원장을 사후에 해석할 수 없다).
4310
4447
  let graphTemplate = graphDecision.template;
4311
- /** 단계 이름 → 그 템플릿의 노드 이름. ⛔ 꺼져 있으면 «항등»이다. */
4448
+ /** 단계 이름 → 그 템플릿의 노드 이름. */
4312
4449
  const node = (stage: PipelineNodeId): PipelineNodeId => nodeNameForStage(stage, graphTemplate) as PipelineNodeId;
4313
4450
  // ⛔⭐ 맥락이 정해진 «직후» 관측기에 심는다 — 이 줄이 없으면 걸음은 YAML 을 따르고 «신원은 안 따른다».
4314
4451
  onGraphResolved(graphIdentityOf(graphTemplate));
4315
- // ⭐ 제어 «출처»를 런마다 «한 번» 남긴다 — ⛔ 승격 여부와 무관하게 «언제나».
4316
- // 🩸 2026-09-08: 이 값은 `gate-skipped-by-graph` «한 자리»에서만 났고, 그 사건은
4317
- // research-loop 이 문서만 바꿨을 때만 난다 ⇒ ***대부분의 런에서 「무엇이 켰나」가 원장에 없었다***.
4318
- // ⛔ 그래서 A/B 의 관문(「두 팔이 갈렸나」)이 «원리상» 답을 못 얻었다.
4319
- // ⛔ 「켜짐」만 남기지 않는다 — `source` 가 「안 켰다」와 「켰는데 안 먹었다」를 가른다.
4452
+ // 권위는 항상 켜지지만 이벤트의 필드 모양은 유지하고 출처를 default로 기록한다.
4320
4453
  observe('graph-authority-resolved', graphAuthorityFields(graphAuthority, graphTemplate));
4454
+ // ⭐ 런 계약 — 런 시작 «한 번» 해석한다(대표 2026-09-26 «초반 계약을 노드가 준수»). 해석 출처(source)와
4455
+ // 실제 칸(actualSubstrate)을 같이 남겨 「계약이 Pod 인데 로컬에서 돌았나」를 원장이 답하게 한다.
4456
+ // 노드 진입 대조는 관측만 하며 실행을 막지 않는다.
4457
+ {
4458
+ const { resolveRunContract } = await import('./graph-run-contract.js');
4459
+ const runContract = resolveRunContract({ ...(graphTemplate.runContract ? { graph: graphTemplate.runContract } : {}), env: process.env });
4460
+ onRunContractResolved(runContract);
4461
+ observe('graph-run-contract-resolved', { ...graphIdentityOf(graphTemplate), ...runContract, ...runContractAtNode(runContract) });
4462
+ }
4321
4463
  // ⛔ 승격이 꺼져 있으면 «심지 않는다» — 그러면 예산 관측도 안 난다(운영 원장이 오늘과 같다).
4322
4464
  if (graphAuthority.enabled) onGraphTemplateResolved(graphTemplate);
4323
4465
  // ⛔ 선택을 «전부» 싣는다 — 얹힌 것만 실으면 「왜 안 얹혔나」를 사후에 못 묻는다.
4324
- // ⛔ 「없음」과 「안 봤음」을 가른다: 승격이 꺼졌으면 selections 가 «빈 배열»이고 그것이 값이다.
4325
4466
  /** ⭐ ③ «다이나믹» — 라운드마다 runtime 오버레이를 다시 고른다.
4326
4467
  * ⛔ **매번 «기준 선언»에서 다시 얹는다** — 이전 라운드 결과 위에 겹쳐 얹으면
4327
4468
  * 「이 걸음을 무엇이 만들었나」가 «누적»이 되어 사후에 못 푼다.
4328
- * ⛔ 승격이 꺼져 있으면 아무 일도 안 한다(오늘과 같은 걸음). */
4469
+ * 오버레이 적용은 기존 실행 경로를 그대로 따른다. */
4329
4470
  const applyRuntimeOverlays = (round: number): void => {
4330
4471
  if (!graphAuthority.enabled) return;
4331
4472
  // ⛔ 「지금 아는 것」만 준다 — 없는 값을 0 으로 지어내지 않는다(key-absent 가 그것을 말한다).
@@ -4406,11 +4547,13 @@ async function runSelfImplementInner(
4406
4547
  // ⭐ 관측 이벤트와 «같은 값»을 원장으로도 보낸다 — 로그에만 있으면 원장 질의가 못 센다(`F12`).
4407
4548
  try { onActiveProvider(activeProvider); } catch { /* 보조 기록이 런을 죽이지 않는다 */ }
4408
4549
  const boundedFeature = boundReadableText(opts.feature, RUN_START_FEATURE_MAX_CHARS);
4550
+ const launchCwd = resolve(process.cwd());
4409
4551
  observe('start', {
4410
4552
  feature: boundedFeature.text, featureTruncated: boundedFeature.truncated, featureOriginalChars: boundedFeature.originalChars,
4411
4553
  branch, base: opts.base ?? null, draft: opts.draft ?? true,
4412
4554
  willFork: !!(opts.parentSessionId && s.forkSession), parentSessionId: opts.parentSessionId ?? null,
4413
- nestDepth: nestInfo().depth, goalSource, goalFile: opts.goalFile ?? null, ...originObservationFields(),
4555
+ nestDepth: nestInfo().depth, goalSource, goalFile: opts.goalFile === undefined ? null : resolve(launchCwd, opts.goalFile),
4556
+ targetRoot: gitRootOf(launchCwd) ?? launchCwd, ...originObservationFields(),
4414
4557
  provider: activeProvider.provider ?? null, model: activeProvider.model ?? null, auth: activeProvider.auth ?? null,
4415
4558
  ...(opts.correlationId !== undefined ? { correlationId: opts.correlationId } : {}),
4416
4559
  });
@@ -4777,12 +4920,15 @@ async function runSelfImplementInner(
4777
4920
  return occurrencePattern.test(reason) && roundsPattern.test(reason);
4778
4921
  };
4779
4922
  const failCounts: number[] = [];
4923
+ // 직전 gate 실패 라운드의 미검증 집합(정렬 키). 통과하면 비운다 — «연속» 반복만 센다.
4924
+ let lastGateUnverifiedKey: string | undefined;
4780
4925
  const reworkHistory: string[] = [];
4781
4926
  const supervisorDecisionHistory: Array<{ round: number; verdict: ReworkBudgetVerdict; reason: string }> = [];
4782
4927
  let judgedEffectiveMax: number | undefined;
4783
4928
  let lastReworkVerdict: ReworkBudgetVerdict | undefined;
4784
4929
  let lastSupervisorVerdict: ReworkBudgetVerdict | undefined;
4785
4930
  let lastSupervisorReason: string | undefined;
4931
+ let consecutiveUnresolvedBudget = 0;
4786
4932
  let pendingPlanRevision: ReworkPlanRevision | undefined;
4787
4933
  let lastPlanRevision: ReworkPlanRevision | undefined;
4788
4934
  const isReviewRework = (source: SupervisionReworkSource): boolean => {
@@ -4818,8 +4964,23 @@ async function runSelfImplementInner(
4818
4964
  observe('review-context-carried', { base: opts.base, basePrLocated: false, carriedItems: 0, headlineComments: 0, source: 'unavailable', error: true, reason: 'lookup-failed' }, { level: 'warn' });
4819
4965
  }
4820
4966
  }
4967
+ const goalTitle = opts.goalFile ? goalTitleFromTargetGoalFile(opts.goalFile, wt.path) : undefined;
4968
+ let priorRunFindings: Awaited<ReturnType<typeof collectPriorDraftFindings>> = [];
4969
+ if (goalTitle) {
4970
+ try {
4971
+ priorRunFindings = await (s.collectPriorDraftFindings ?? collectPriorDraftFindings)({ goalTitle, currentRunId: runId, repoPath: wt.path });
4972
+ } catch (error) {
4973
+ observe('prior-findings.unreadable', { error: error instanceof Error ? error.message : String(error) });
4974
+ }
4975
+ }
4976
+ if (priorRunFindings.length) {
4977
+ observe('prior-findings.loaded', {
4978
+ prs: priorRunFindings.length,
4979
+ items: priorRunFindings.reduce((sum, finding) => sum + finding.items.length, 0),
4980
+ });
4981
+ }
4821
4982
  let appliedLastRound: string[] | undefined;
4822
- let reviewIntent = buildReviewIntent({ goal: opts.feature, goalFile: opts.goalFile });
4983
+ let reviewIntent = buildReviewIntent({ goal: opts.feature, goalFile: opts.goalFile, ...(priorRunFindings.length ? { priorRunFindings } : {}) });
4823
4984
  // ⛔⭐ 리뷰 루프가 만든 마지막 컨텍스트를 잡아 둔다 — PR 본문 조립 직전에 **최종 커밋**의
4824
4985
  // 런 사실로 갱신하기 위해서다(3R must-fix). 루프 안 수집은 `openPr` 단계가 만드는 커밋을
4825
4986
  // 못 본다: 자식은 파일만 남기고 실제 커밋은 `commitWork` 가 루프 뒤에서 만든다.
@@ -4996,9 +5157,10 @@ async function runSelfImplementInner(
4996
5157
  }
4997
5158
  };
4998
5159
  let preservationBase = wt.resolvedBase;
5160
+ const runProviderName = opts.childLlm?.provider ?? (s.currentProviderName?.() ?? currentProviderName());
4999
5161
  let cachedQuotaExhaustionAssessment: QuotaExhaustionAssessment | undefined;
5000
5162
  const quotaExhaustionAssessmentForRun = (): QuotaExhaustionAssessment => {
5001
- cachedQuotaExhaustionAssessment ??= readQuotaExhausted(s.inspectCodexRotation, s.currentProviderName?.());
5163
+ cachedQuotaExhaustionAssessment ??= readQuotaExhausted(s.inspectCodexRotation, runProviderName);
5002
5164
  return cachedQuotaExhaustionAssessment;
5003
5165
  };
5004
5166
  const classifyUnfinishedRun = (stage: SelfImplementStage, verdict?: ReworkBudgetVerdict, decomposition?: TerminalDecomposition): AbandonedClassificationResult => {
@@ -5008,9 +5170,9 @@ async function runSelfImplementInner(
5008
5170
  ...(opts.goalFile ? { goalType: goalTypeFields(opts.goalFile).goalType } : {}),
5009
5171
  ...(quotaExhaustionAssessment.exhausted ? { quotaExhausted: true } : {}),
5010
5172
  ...(quotaExhaustionAssessment.accountAvailability ? { quotaAccountAvailability: quotaExhaustionAssessment.accountAvailability } : {}),
5011
- ...(hasCredentialFailure() ? { credentialFailure: true } : {}),
5012
- ...(hasProviderError() ? { providerError: true } : {}),
5013
- ...(providerErrorCategory() ? { providerErrorCategory: providerErrorCategory() } : {}),
5173
+ ...(hasCurrentCredentialFailure() ? { credentialFailure: true } : {}),
5174
+ ...(hasCurrentProviderError() ? { providerError: true } : {}),
5175
+ ...(hasCurrentProviderError() && providerErrorCategory() ? { providerErrorCategory: providerErrorCategory() } : {}),
5014
5176
  worktreePorcelain: worktree.worktreePorcelain,
5015
5177
  ...(worktree.gitResidue ? { gitResidue: worktree.gitResidue } : {}),
5016
5178
  ...(impl.completionDisposition ? { completionDisposition: impl.completionDisposition } : {}),
@@ -5145,30 +5307,76 @@ async function runSelfImplementInner(
5145
5307
  opts.goalFile,
5146
5308
  s.persistPrBodyArtifact,
5147
5309
  );
5148
- // worktree-only 는 원격이 없어 draft PR 을 열 수 없다. 시도 실패로 사유를 전하지 않고
5149
- // 같은 본문을 아티팩트로 남긴 뒤 워크트리·브랜치를 보존한다. no-changes 가 먼저다.
5150
- if (opts.completion === 'worktree-only') {
5310
+ // no-changes wins; worktree-only remains local even for environment stops.
5311
+ const environmentStop = blockedDraftDisposition(classificationRecord.classification) === 'preserve-branch';
5312
+ const worktreeOnly = opts.completion === 'worktree-only';
5313
+ if (worktreeOnly || environmentStop) {
5151
5314
  let artifactPath: string | undefined;
5152
5315
  let artifactError: string | undefined;
5153
5316
  try {
5154
5317
  artifactPath = persistFullPrBody(s.persistPrBodyArtifact, {
5155
- origin: 'self-implement-blocked-draft-pr-worktree-only',
5318
+ origin: worktreeOnly ? 'self-implement-blocked-draft-pr-worktree-only' : 'self-implement-blocked-draft-pr-environment-stop',
5156
5319
  body: assembled.body,
5157
5320
  originalChars: assembled.originalChars,
5158
5321
  });
5159
5322
  } catch (persistenceError) {
5160
5323
  artifactError = persistenceError instanceof Error ? persistenceError.message : String(persistenceError);
5161
5324
  }
5325
+ let pushed = false;
5326
+ let committed = false;
5327
+ let pushError: Error | undefined;
5328
+ let preservationErrorStep: 'worktree' | 'commit' | 'push' | undefined;
5329
+ if (environmentStop && !worktreeOnly) {
5330
+ try {
5331
+ if (!s.preserveBlockedBranch && !existsSync(wt.path)) {
5332
+ preservationErrorStep = 'worktree';
5333
+ throw new Error(`worktree not found: ${wt.path}`);
5334
+ }
5335
+ if (s.preserveBlockedBranch) {
5336
+ pushed = await s.preserveBlockedBranch({ cwd: wt.path, branch: wt.branch, title: prTitle(opts.feature) });
5337
+ if (!pushed) throw new Error('브랜치 push가 성공하지 않았음');
5338
+ } else {
5339
+ preservationErrorStep = 'commit';
5340
+ const commit = commitWorktree(wt.path, prTitle(opts.feature));
5341
+ if (!commit.ok && !/nothing to commit/.test(commit.out)) throw new Error(commit.out);
5342
+ committed = commit.ok;
5343
+ if (runGitCommand(wt.path, ['remote', 'get-url', 'origin']).status === 0) {
5344
+ preservationErrorStep = 'push';
5345
+ const push = runGitCommand(wt.path, ['push', '-u', 'origin', `HEAD:refs/heads/${wt.branch}`]);
5346
+ if (push.status !== 0) throw new Error(push.stderr || push.stdout);
5347
+ pushed = true;
5348
+ }
5349
+ }
5350
+ } catch (error) {
5351
+ pushError = error instanceof Error ? error : new Error(String(error));
5352
+ }
5353
+ }
5162
5354
  observe('rework-blocked-draft-pr', {
5163
5355
  ...observation,
5164
- skipped: 'worktree-only',
5356
+ skipped: worktreeOnly ? 'worktree-only' : 'environment-stop',
5357
+ ...(!worktreeOnly && environmentStop ? { pushed, committed } : {}),
5165
5358
  worktreePath: wt.path,
5359
+ ...(pushError ? { pushError: pushError.message, preservationErrorStep: preservationErrorStep ?? 'push' } : {}),
5166
5360
  ...(artifactPath ? { prBodyArtifactPath: artifactPath } : {}),
5167
5361
  ...(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})`);
5362
+ }, pushError ? { level: 'warn' } : undefined);
5363
+ if (pushError) {
5364
+ const failure = preservationErrorStep === 'worktree' ? '워크트리 부재로 보존 실패' : preservationErrorStep === 'commit' ? '로컬 브랜치 커밋 실패' : '원격 브랜치 보존 실패';
5365
+ progress('aborted', `환경 탓 중단 — ${failure}: ${wt.branch} (${pushError.message}; worktree: ${wt.path})`);
5366
+ if (preservationErrorStep === 'worktree') return undefined;
5367
+ throw new Error(`환경 탓 중단 — ${failure}: ${wt.branch} (worktree: ${wt.path})`, { cause: pushError });
5368
+ }
5369
+ if (worktreeOnly) {
5370
+ progress(stage, artifactPath
5371
+ ? `worktree-only 완료: draft PR을 열지 않음(worktree·branch 보존 · 중단 사유 보존: ${artifactPath} · worktree: ${wt.path} · branch: ${wt.branch})`
5372
+ : `worktree-only 완료: draft PR을 열지 않음(worktree·branch 보존 · 중단 사유 보존 실패: ${artifactError ?? 'unknown error'} · worktree: ${wt.path} · branch: ${wt.branch})`);
5373
+ } else {
5374
+ // No draft PR on this path, so the stop reason must be findable from the progress line itself.
5375
+ const reasonNote = artifactPath ? `중단 사유 보존: ${artifactPath}` : `중단 사유 보존 실패: ${artifactError ?? 'unknown error'}`;
5376
+ progress(stage, pushed
5377
+ ? `환경 탓 중단 — draft PR 없이 브랜치만 보존: ${wt.branch} · ${reasonNote}`
5378
+ : `환경 탓 중단 — draft PR 없이 로컬 브랜치만 보존(원격 origin 없음): ${wt.branch} · worktree: ${wt.path} · ${reasonNote}`);
5379
+ }
5172
5380
  return undefined;
5173
5381
  }
5174
5382
  progress('pr-opening', '중단 산출물을 draft PR로 보존…');
@@ -5315,6 +5523,23 @@ async function runSelfImplementInner(
5315
5523
  await flushPrComments(pr);
5316
5524
  return { decision, pr };
5317
5525
  };
5526
+ const baselineOnlyGate = (): boolean => {
5527
+ const failures = gate?.baselineFailures;
5528
+ return gate?.passed === false && !!failures?.length && gate.reflectGateFacts?.introduced === 0
5529
+ && gate.reflectGateFacts.unknown === 0
5530
+ && failures.every(({ attribution }) => attribution === 'preexisting' || attribution === 'flaky-timeout'
5531
+ || attribution === 'flaky-rerun' || attribution === 'precondition-unmet');
5532
+ };
5533
+ const noRetryBaseline = (): { terminationReason?: 'blocked-by-baseline' } => {
5534
+ if (!baselineOnlyGate()) return {};
5535
+ const failures = gate!.baselineFailures!;
5536
+ debug.log('self-implement.supervisor', 'no-retry-baseline', {
5537
+ runId,
5538
+ preexisting: failures.filter(({ attribution }) => attribution === 'preexisting').length,
5539
+ flaky: failures.filter(({ attribution }) => attribution === 'flaky-timeout' || attribution === 'flaky-rerun').length,
5540
+ });
5541
+ return { terminationReason: 'blocked-by-baseline' };
5542
+ };
5318
5543
  const salvageHardCap = async (hardCapBlockedExtend: boolean, pr?: { number: number }): Promise<'launched' | 'parked'> => {
5319
5544
  let evidence: ReworkSalvageEvidence | undefined;
5320
5545
  if (hardCapBlockedExtend) {
@@ -5333,21 +5558,27 @@ async function runSelfImplementInner(
5333
5558
  ...(opts.goalFile ? { goalType: goalTypeFields(opts.goalFile).goalType } : {}),
5334
5559
  ...(quotaExhaustionAssessment.exhausted ? { quotaExhausted: true } : {}),
5335
5560
  ...(quotaExhaustionAssessment.accountAvailability ? { quotaAccountAvailability: quotaExhaustionAssessment.accountAvailability } : {}),
5336
- ...(hasCredentialFailure() ? { credentialFailure: true } : {}),
5337
- ...(hasProviderError() ? { providerError: true } : {}),
5338
- ...(providerErrorCategory() ? { providerErrorCategory: providerErrorCategory() } : {}),
5561
+ ...(hasCurrentCredentialFailure() ? { credentialFailure: true } : {}),
5562
+ ...(hasCurrentProviderError() ? { providerError: true } : {}),
5563
+ ...(hasCurrentProviderError() && providerErrorCategory() ? { providerErrorCategory: providerErrorCategory() } : {}),
5339
5564
  worktreePorcelain: worktree.worktreePorcelain,
5340
5565
  ...(worktree.gitResidue ? { gitResidue: worktree.gitResidue } : {}),
5341
5566
  stage: isReviewRework(reworkKind) ? 'review-blocked' : 'gate-failed',
5342
5567
  reviewResultObserved: review !== undefined,
5343
5568
  mustFixReported: (review?.mustFix.length ?? 0) > 0,
5344
5569
  });
5570
+ observe('rework-salvage-classification', { ...abandonedClassification, branch: wt.branch });
5571
+ // Salvage may resume an observed environment interruption even when a later
5572
+ // gate/review verdict is the terminal classification. Keep its cause distinct.
5573
+ const salvageClassification = abandonedClassification.classification === 'implementation-deficit' && hasObservedProviderError()
5574
+ ? hasObservedCredentialFailure() ? 'credential-failure' : 'provider-error'
5575
+ : abandonedClassification.classification;
5345
5576
  const decision = decideReworkSalvage({
5346
5577
  hardCapBlockedExtend,
5347
5578
  goalFile: opts.goalFile,
5348
5579
  salvageAttempt: opts.salvageAttempt,
5349
5580
  evidence,
5350
- abandonedClassification: abandonedClassification.classification,
5581
+ abandonedClassification: salvageClassification,
5351
5582
  });
5352
5583
  if (decision.action !== 'launch') {
5353
5584
  const reason = decision.reason;
@@ -5360,7 +5591,7 @@ async function runSelfImplementInner(
5360
5591
  const launchObservation = {
5361
5592
  branch: wt.branch,
5362
5593
  goalFile: opts.goalFile,
5363
- ...(environmentReason ? { reason: environmentReason, abandonedClassification: abandonedClassification.classification } : {}),
5594
+ ...(environmentReason ? { reason: environmentReason, abandonedClassification: salvageClassification } : {}),
5364
5595
  ...(salvageEvidence ? { clean: salvageEvidence.clean, aheadCommits: salvageEvidence.aheadCommits } : {}),
5365
5596
  };
5366
5597
  observe('rework-salvage', { action: 'launching', ...launchObservation });
@@ -5437,36 +5668,48 @@ async function runSelfImplementInner(
5437
5668
  const judgmentCallLLM = s.judgmentCallLLM;
5438
5669
  if (diagnosedDecision?.verdict !== 'CONTRACT-CONFLICT' && !judgmentCallLLM) throw new Error('rework-budget@v1 requires a judgment provider');
5439
5670
  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');
5671
+ try {
5672
+ const result = diagnosedDecision?.verdict === 'CONTRACT-CONFLICT'
5673
+ ? undefined
5674
+ : await withStepTimeout(
5675
+ runWorkflowToCompletion(
5676
+ {
5677
+ workflow: reworkBudgetWorkflow,
5678
+ arguments: diagnosis,
5679
+ artifactsDir: '',
5680
+ persistRun: false,
5681
+ judgmentContext: { kind: reworkKind, history: priorHistory },
5682
+ },
5683
+ {
5684
+ callLLM: judgmentCallLLM!,
5685
+ runBash: async () => ({ stdout: '', stderr: '', exitCode: 0 }),
5686
+ runJudgment: judgmentProvider!,
5687
+ },
5688
+ ),
5689
+ T.review,
5690
+ 'review',
5691
+ );
5692
+ if (result) {
5693
+ const classified = result.outputs['rework-budget'];
5694
+ if (!result.ok || !classified?.ok || typeof classified.output !== 'string') {
5695
+ throw new Error(classified?.error ?? 'rework-budget@v1 judgment failed');
5696
+ }
5697
+ const picked = classified.output === 'EXTEND' || classified.output === 'SUFFICIENT' || classified.output === 'UNCONVERGEABLE'
5698
+ ? classified.output
5699
+ : undefined;
5700
+ if (!picked) throw new Error(`rework-budget@v1 returned unsupported class '${String(classified.output)}'`);
5701
+ parsedDecision = { verdict: picked, reason: diagnosedDecision?.reason ?? 'workflow-fabric classification' };
5464
5702
  }
5465
- const picked = classified.output === 'EXTEND' || classified.output === 'SUFFICIENT' || classified.output === 'UNCONVERGEABLE'
5466
- ? classified.output
5703
+ consecutiveUnresolvedBudget = 0;
5704
+ } catch (error) {
5705
+ const message = safeErrorDescription(error);
5706
+ if (!message.startsWith('rework-budget@v1 classification did not resolve a supported class')
5707
+ && !message.startsWith('rework-budget@v1 returned unsupported class')) throw error;
5708
+ consecutiveUnresolvedBudget++;
5709
+ observe('rework-budget-unresolved-fallback', { round, error: message.slice(0, 200), consecutive: consecutiveUnresolvedBudget }, { level: 'warn' });
5710
+ parsedDecision = consecutiveUnresolvedBudget >= 2
5711
+ ? { verdict: 'UNCONVERGEABLE', reason: 'rework-budget classification unresolved ×2' }
5467
5712
  : 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
5713
  }
5471
5714
  let fabricObservation: Record<string, unknown> | undefined;
5472
5715
  if (s.classifyCallLLM) {
@@ -5497,7 +5740,7 @@ async function runSelfImplementInner(
5497
5740
  selfImplementConfig.reworkBudget.maxRounds,
5498
5741
  reworkKind,
5499
5742
  priorHistory.length,
5500
- shadowStop,
5743
+ consecutiveUnresolvedBudget >= 2 ? false : shadowStop,
5501
5744
  supervisorDecisionHistory.at(-1)?.verdict,
5502
5745
  );
5503
5746
  effectiveMax = budgetDecision.effectiveMax;
@@ -5688,9 +5931,11 @@ async function runSelfImplementInner(
5688
5931
  const quotaExhaustionAssessment = quotaExhaustionAssessmentForRun();
5689
5932
  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
5933
  }
5691
- const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', verdict: parsedDecision.verdict, reason: parsedDecision.reason, gate, decomposition: terminalDecomposition, salvageStatusExpected: false });
5934
+ const baselineStop = noRetryBaseline();
5935
+ const reason = baselineStop.terminationReason ?? parsedDecision.reason;
5936
+ const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', verdict: parsedDecision.verdict, reason, gate, decomposition: terminalDecomposition, salvageStatusExpected: false });
5692
5937
  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}` };
5938
+ 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
5939
  }
5695
5940
  } else {
5696
5941
  const repeatedBlockingIds = repeatedBlockingFindingIds(currentBlockingFindings, previousBlockingFindings);
@@ -5699,7 +5944,10 @@ async function runSelfImplementInner(
5699
5944
  }
5700
5945
  } catch (error) {
5701
5946
  if (judgmentStarted) throw error;
5947
+ consecutiveUnresolvedBudget = 0;
5702
5948
  }
5949
+ } else if (round > 0) {
5950
+ consecutiveUnresolvedBudget = 0;
5703
5951
  }
5704
5952
  if (round > effectiveMax) {
5705
5953
  finalizeSupervisorDeliveries('rework-round-limit');
@@ -5711,8 +5959,9 @@ async function runSelfImplementInner(
5711
5959
  const pr = await preserveBlockedArtifacts({ stage: 'review-blocked', verdict: lastReworkVerdict, reason, gate, salvageStatusExpected: false });
5712
5960
  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
5961
  }
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 };
5962
+ const baselineStop = noRetryBaseline();
5963
+ const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', verdict: lastReworkVerdict, reason: baselineStop.terminationReason ?? reason, gate, salvageStatusExpected: false });
5964
+ 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
5965
  }
5717
5966
  const terminal = resolveRunOutcome({ termination: 'budget-exhausted', ...(lastReworkVerdict ? { lastVerdict: lastReworkVerdict } : {}) });
5718
5967
  // ⛔⭐ **보존(=커밋·push) 뒤에 발사한다.** 종전엔 발사가 먼저라, 인수 자식이 `--base <그 브랜치>`
@@ -5751,10 +6000,11 @@ async function runSelfImplementInner(
5751
6000
  const disposition = { ...terminal, ...(salvage ? { salvage } : {}) };
5752
6001
  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
6002
  }
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 } : {}) };
6003
+ const baselineStop = noRetryBaseline();
6004
+ const reason = baselineStop.terminationReason ?? `gate failed after ${round - 1} rework round(s)`;
6005
+ const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate, salvageStatusExpected: !baselineStop.terminationReason });
6006
+ const salvage = baselineStop.terminationReason ? 'parked' : await salvageHardCap(canSalvage, pr);
6007
+ const disposition = { ...terminal, ...(salvage ? { salvage } : {}), ...baselineStop };
5758
6008
  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
6009
  }
5760
6010
 
@@ -5787,6 +6037,9 @@ async function runSelfImplementInner(
5787
6037
  progress('implementing', round === 0
5788
6038
  ? '구현 중 (헤드리스 goal-loop·수분 소요)…'
5789
6039
  : formatReworkProgressLine(round, effectiveMax, escalateTier, attemptOrdinal));
6040
+ if (round > 0) {
6041
+ try { emitDecision(reworkDecision({ runId, round, effectiveMax, escalateTier, kind: reworkKind })); } catch { /* observation must not interrupt rework */ }
6042
+ }
5790
6043
  let reworkArtifactPath: string | undefined;
5791
6044
  if (round > 0) {
5792
6045
  try {
@@ -6111,7 +6364,9 @@ async function runSelfImplementInner(
6111
6364
  progress('gated', !runsGate
6112
6365
  ? `gate 미실행 — 이 그래프(${graphTemplate.graphId})는 gate 노드를 갖지 않는다`
6113
6366
  : gate.passed ? 'gate 통과' : `gate 실패(라운드 ${round})`);
6367
+ if (gate.passed) lastGateUnverifiedKey = undefined;
6114
6368
  if (!gate.passed) {
6369
+ await onFailureVerdict('gate');
6115
6370
  const facts = gate.reflectGateFacts;
6116
6371
  const failureDisposition = decideGateFailureDisposition(facts);
6117
6372
  // 타임아웃«뿐» — 도입 0 · 미분류 0 · 자식 책임 없음. 재작업으로 보내지 않고 리뷰로 진행한다.
@@ -6183,6 +6438,23 @@ async function runSelfImplementInner(
6183
6438
  const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate, salvageStatusExpected: false });
6184
6439
  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
6440
  }
6441
+ // ⭐ 반복 열쇠 = 미검증 집합. 실패 시험 0건인데 직전 gate 실패와 «같은» 집합이면 재작업이 그 신호를 못 바꾼다
6442
+ // (run-7dd4cce6: 리뷰 지적 비교는 incomparable · 점수 1/3 · 예산 판정 EXTEND 로 헛돌았다).
6443
+ if (isRepeatedUnverifiedOnlyGateFailure({ previousKey: lastGateUnverifiedKey, unverified: gate.unverified, gateLog: gate.log, ...(facts ? { introduced: facts.introduced } : {}) })) {
6444
+ finalizeSupervisorDeliveries('gate-failed-unverified-repeat');
6445
+ const unverifiedFiles = [...new Set(gate.unverified ?? [])].sort();
6446
+ 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`;
6447
+ observe('gate-failed-unverified-repeat-escalated', {
6448
+ round,
6449
+ unverified: unverifiedFiles.slice(0, 20),
6450
+ unverifiedCount: unverifiedFiles.length,
6451
+ reason,
6452
+ }, { level: 'warn' });
6453
+ progress('gate-failed', `중단 — 실패 시험 0건 · 같은 미검증 파일 ${unverifiedFiles.length}개가 되풀이(재작업으로 안 바뀐다 · 사람 판단 대기)`);
6454
+ const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate, salvageStatusExpected: false });
6455
+ 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 };
6456
+ }
6457
+ lastGateUnverifiedKey = unverifiedRepeatKey(gate.unverified);
6186
6458
  round++;
6187
6459
  continue;
6188
6460
  }
@@ -6225,6 +6497,26 @@ async function runSelfImplementInner(
6225
6497
  path: designCheck.path,
6226
6498
  });
6227
6499
  }
6500
+ const runFacts = collectRunFacts(wt.path);
6501
+ let designGate: ReviewDiffContext['designGate'];
6502
+ // Git porcelain collapses untracked directories to `site/`; inspect their files too.
6503
+ let untrackedFiles: string[] = [];
6504
+ if (runFacts.changedFiles?.some((file) => file.endsWith('/'))) {
6505
+ try {
6506
+ const untracked = runGitCommand(wt.path, ['ls-files', '--others', '--exclude-standard'], { encoding: 'utf8' });
6507
+ if (untracked.status === 0) untrackedFiles = untracked.stdout.split(/\r?\n/).filter(Boolean);
6508
+ } catch { /* change discovery must not stop review */ }
6509
+ }
6510
+ if ([...(runFacts.changedFiles ?? []), ...(gateRouteFiles ?? []), ...untrackedFiles].some((file) => /\.(?:html|css)$/i.test(file))) {
6511
+ try {
6512
+ designGate = (s.runDesignGate ?? runDesignGate)({ projectDir: wt.path, base: wt.resolvedBase });
6513
+ } catch (error) {
6514
+ designGate = { unmeasured: safeErrorDescription(error) };
6515
+ }
6516
+ observe('design-gate', 'unmeasured' in designGate
6517
+ ? { verdict: null, reason: null, p0Total: null, advisoryTotal: null, files: null, unmeasured: designGate.unmeasured }
6518
+ : { verdict: designGate.verdict, reason: designGate.reason ?? null, p0Total: designGate.p0Total, advisoryTotal: designGate.advisoryTotal, files: designGate.files.length });
6519
+ }
6228
6520
  let goalDocumentPath: string | undefined;
6229
6521
  try {
6230
6522
  goalDocumentPath = opts.goalId ? s.goalDocumentPathByGoalId?.(opts.goalId) : undefined;
@@ -6233,9 +6525,10 @@ async function runSelfImplementInner(
6233
6525
  }
6234
6526
  const reviewContext = {
6235
6527
  runId,
6236
- ...collectRunFacts(wt.path),
6528
+ ...runFacts,
6237
6529
  goal: opts.feature,
6238
6530
  goalFile: opts.goalFile,
6531
+ ...(priorRunFindings.length ? { priorRunFindings } : {}),
6239
6532
  ...(goalDocumentPath ? { goalDocumentPath } : {}),
6240
6533
  round,
6241
6534
  ...((round === 0 ? carriedAppliedItems : appliedLastRound)?.length
@@ -6248,6 +6541,7 @@ async function runSelfImplementInner(
6248
6541
  // ⛔⭐ 하니스가 이미 센 것을 판정자에게 준다(원장 `JDG-S4`·`JDG-S5` — 로그에만 있으면 못 본다).
6249
6542
  ...(evidenceCoverage ? { evidenceCoverage } : {}),
6250
6543
  ...(designCheck ? { designCheck } : {}),
6544
+ ...(designGate ? { designGate } : {}),
6251
6545
  ...(gateEvidence ? { gateEvidenceNote: gateEvidence } : {}),
6252
6546
  ...(gate.baselineFailures?.some((failure) => failure.attribution === 'preexisting')
6253
6547
  ? { preexistingTestFailures: gate.baselineFailures
@@ -6274,6 +6568,7 @@ async function runSelfImplementInner(
6274
6568
  throw error;
6275
6569
  }
6276
6570
  onReviewFindings(round, review.mustFix);
6571
+ if (review.mustFix.length > 0) await onFailureVerdict('review');
6277
6572
  const reviewFindings = snapshotMustFixFindings([...review.mustFix, ...review.shouldFix]);
6278
6573
  const reviewMustFixFindings = reviewFindings.slice(0, review.mustFix.length);
6279
6574
  observeReviewFindingRecurrence(round, review.mustFix);
@@ -6507,7 +6802,7 @@ async function runSelfImplementInner(
6507
6802
  const { latestSignalIncomplete } = signalIncompleteState(roundClassifications);
6508
6803
  const autoMerge = autoMergeEnabled(opts);
6509
6804
  const gateTimeoutUnmeasured = isTimeoutOnlyUnmeasuredGate(gate.reflectGateFacts);
6510
- const canAuto = !gateTimeoutUnmeasured && autoMerge && reviewReal && review!.verdict !== 'fail' && reviewDiffComplete && !requiredEvidenceMissing && !latestSignalIncomplete && !decisionSignalRed;
6805
+ let canAuto = !gateTimeoutUnmeasured && autoMerge && reviewReal && review!.verdict !== 'fail' && reviewDiffComplete && !requiredEvidenceMissing && !latestSignalIncomplete && !decisionSignalRed;
6511
6806
  // ⭐⭐ 통과의 «이유»를 둘로 가른다 — ⛔ 막지는 «않는다»(대표 판단 2026-08-11: ⓐ 문면만).
6512
6807
  // 📏 근거(`JDG-T36` · merge-decision 300건 전수): `verifyByBreaking` 이 실린 8건의 auto 중 ***5건***이
6513
6808
  // ***ran=true 인데 distinguishes=0***(아무것도 안 가르는 자기검증)이었고, 그 다섯이 «전부»
@@ -6518,7 +6813,7 @@ async function runSelfImplementInner(
6518
6813
  // 그건 `skippedReason` 이 이미 가른다. 그래서 여기 조건에 넣지 않는다.
6519
6814
  const verifyInconclusive = gate.verifyByBreaking?.ran === true && (gate.verifyByBreaking.distinguishes ?? 0) === 0;
6520
6815
  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')
6816
+ let mergeReason = canAuto ? (verifyNothingAtBase ? 'review-clean-verify-nothing-at-base' : verifyInconclusive ? 'review-clean-verify-inconclusive' : 'review-clean-armed')
6522
6817
  : gateTimeoutUnmeasured ? GATE_TIMEOUT_UNMEASURED_MERGE_REASON
6523
6818
  : !autoMerge ? 'no-auto-flag'
6524
6819
  : requiredEvidenceMissing ? 'required-evidence-uncovered'
@@ -6528,9 +6823,9 @@ async function runSelfImplementInner(
6528
6823
  : review!.verdict === 'fail' ? 'review-must-fix'
6529
6824
  : review!.diffTruncated === true ? 'review-diff-truncated'
6530
6825
  : 'review-diff-budget-unknown';
6531
- const mergeSkipReason = canAuto ? undefined : mergeReason;
6532
- if (canAuto) onMergeApprovalReceived();
6533
- observe('merge-decision', {
6826
+ let mergeSkipReason = canAuto ? undefined : mergeReason;
6827
+ if (canAuto) onAutoMergeAuthorizedBeforeSync();
6828
+ const mergeDecisionObservation = {
6534
6829
  autoMerge, reviewed: reviewReal, verdict: review?.verdict ?? 'none',
6535
6830
  decision: canAuto ? 'auto' : 'hitl', reason: mergeReason,
6536
6831
  ...mergeDecisionEvidenceCoverage(evidenceCoverage),
@@ -6552,8 +6847,15 @@ async function runSelfImplementInner(
6552
6847
  ...(gate.verifyByBreaking ? { verifyByBreaking: gate.verifyByBreaking } : {}),
6553
6848
  ...(decisionSignalPress ? { decisionSignalPress, decisionSignalBaselineOnly } : {}),
6554
6849
  ...(decisionSignalPressReason ? { decisionSignalPressReason } : {}),
6555
- });
6850
+ };
6851
+ const recordMergeDecision = () => {
6852
+ observe('merge-decision', {
6853
+ ...mergeDecisionObservation,
6854
+ decision: canAuto ? 'auto' : 'hitl', reason: mergeReason,
6855
+ });
6856
+ };
6556
6857
  if (opts.completion === 'worktree-only' && !decisionSignalRed) {
6858
+ recordMergeDecision();
6557
6859
  progress('worktree-completed', '✅ 작업 트리 완료 — PR 생성 없이 worktree 보존');
6558
6860
  observe('worktree-completed', { branch: wt.branch, hadApprover: !!s.approvePr });
6559
6861
  return {
@@ -6561,10 +6863,11 @@ async function runSelfImplementInner(
6561
6863
  detail: 'worktree-only completion: PR creation skipped',
6562
6864
  };
6563
6865
  }
6564
- const approved = canAuto ? true : (s.approvePr
6866
+ let approved = canAuto ? true : (s.approvePr
6565
6867
  ? await s.approvePr({ branch: wt.branch, ...(gate.log ? { gateLog: gate.log } : {}), implSummary: impl.summary, ...(review ? { review } : {}) })
6566
6868
  : false);
6567
6869
  if (!approved) {
6870
+ recordMergeDecision();
6568
6871
  observe('pr-declined', { branch: wt.branch, hadApprover: !!s.approvePr });
6569
6872
  return {
6570
6873
  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 +6888,9 @@ async function runSelfImplementInner(
6585
6888
  ...(resolvedTarget.error === undefined ? {} : { resolveError: resolvedTarget.error }),
6586
6889
  });
6587
6890
  progress('merge-conflict', '⚠️ 기본 브랜치 해석 실패 — 자동병합 차단(수동 정합 필요·HITL 결정)');
6891
+ canAuto = false;
6892
+ mergeReason = 'default-branch-unresolved';
6893
+ recordMergeDecision();
6588
6894
  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
6895
  }
6590
6896
  progress('gating', `최신 ${mergeTarget} 정합 (병렬 드리프트·LLM 충돌해결)…`);
@@ -6593,6 +6899,9 @@ async function runSelfImplementInner(
6593
6899
  observe('pre-pr-sync', mainSyncObservation(sync, mergeTarget, opts.base, wt.branch));
6594
6900
  if (sync.status === 'conflict-unresolved' || sync.status === 'error') {
6595
6901
  progress('merge-conflict', `⚠️ ${mergeTarget} 정합 ${sync.status}${sync.errorStep === undefined ? '' : ` (${sync.errorStep})`} — 자동병합 차단(수동 정합 필요·HITL 결정)`);
6902
+ canAuto = false;
6903
+ mergeReason = `main-sync-${sync.status}`;
6904
+ recordMergeDecision();
6596
6905
  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
6906
  }
6598
6907
  if (sync.status === 'llm-resolved' || sync.status === 'merged') {
@@ -6602,14 +6911,33 @@ async function runSelfImplementInner(
6602
6911
  : `${mergeTarget} 정합됨 — 통합 결과 full 재-gate…`);
6603
6912
  onNodeEntry('regate', round);
6604
6913
  const regate = await withStepTimeout(s.gate(wt.path, { runId, mode: 'postsync' }), T.gate, 'gate');
6914
+ if (!regate.passed) await onFailureVerdict('gate');
6605
6915
  // `mode` name/meaning stay: `full` = existing gate including tests. Both
6606
6916
  // conflict-resolved and clean-merge reuse this same `s.gate` invocation.
6917
+ const timeoutOnlyPostSync = !regate.passed && postSyncTimeoutOnly(regate.reflectGateFacts);
6607
6918
  const postSyncPolicy = postSyncGatePolicy(
6608
6919
  regate.passed,
6609
- regate.reflectGateFacts?.childResponsibility,
6920
+ regate.reflectGateFacts,
6610
6921
  sync.status,
6611
6922
  );
6612
6923
  observe('gate.postsync', postSyncGateObservation(regate, wt.branch, hasModuleLoadFailure, sync.status));
6924
+ if (timeoutOnlyPostSync) {
6925
+ const facts = regate.reflectGateFacts!;
6926
+ observe('post-sync-gate-timeout-only-continued', {
6927
+ introduced: facts.introduced, unknown: facts.unknown, timedOut: facts.timedOut ?? 0,
6928
+ }, { level: 'warn' });
6929
+ canAuto = false;
6930
+ mergeReason = GATE_TIMEOUT_UNMEASURED_MERGE_REASON;
6931
+ mergeSkipReason = mergeReason;
6932
+ approved = s.approvePr
6933
+ ? await s.approvePr({
6934
+ branch: wt.branch,
6935
+ 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'),
6936
+ implSummary: impl.summary,
6937
+ ...(review ? { review } : {}),
6938
+ })
6939
+ : false;
6940
+ }
6613
6941
  if (postSyncPolicy.mustStop) {
6614
6942
  progress('gate-failed', sync.status === 'llm-resolved'
6615
6943
  ? '중단 — main 충돌해결 후 gate 실패(면책 보류·통합 깨짐)'
@@ -6619,16 +6947,27 @@ async function runSelfImplementInner(
6619
6947
  : sync.status === 'llm-resolved'
6620
6948
  ? 'gate failed after main-sync (conflict-resolved integration break)'
6621
6949
  : 'gate failed after main-sync (clean-merge integration break)';
6950
+ canAuto = false;
6951
+ mergeReason = 'post-sync-gate-failed';
6952
+ recordMergeDecision();
6622
6953
  const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate: regate, salvageStatusExpected: false });
6623
6954
  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
6955
  }
6625
6956
  if (!regate.passed) {
6626
- progress('gating', 'main 정합 후 gate 실패는 자식 책임 없음으로 면책 — 통합 깨짐으로 중단하지 않고 계속 진행');
6957
+ progress('gating', timeoutOnlyPostSync
6958
+ ? 'main 정합 후 gate 타임아웃만 — 사람 확인으로 진행'
6959
+ : 'main 정합 후 gate 실패는 자식 책임 없음으로 면책 — 통합 깨짐으로 중단하지 않고 계속 진행');
6627
6960
  }
6628
6961
  gate = regate;
6629
6962
  }
6630
6963
  }
6631
6964
 
6965
+ recordMergeDecision();
6966
+ if (!approved) {
6967
+ observe('pr-declined', { branch: wt.branch, hadApprover: !!s.approvePr });
6968
+ 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(자동승인 금지)' };
6969
+ }
6970
+ if (canAuto) onMergeApprovalReceived();
6632
6971
  const extractedOriginalAsk = extractVerbatimOriginalAsk(opts.feature);
6633
6972
  const { labels, declineReasons, eligibility } = resolveAutoReviewLabels(!!opts.autoReview, {
6634
6973
  objective: opts.feature,
@@ -6670,8 +7009,8 @@ async function runSelfImplementInner(
6670
7009
  // 재면 각각 셋·다섯 칸이 «비어» 있었고, 그중 「원장」과 「위험」은 «둘 다» 0이었다.
6671
7010
  // `prBody` 는 모든 인자가 optional 이라 비면 그 절이 «조용히 사라진다» — 그래서 결손이
6672
7011
  // 정상 산출과 구별되지 않았다. 이 관문이 그 부재를 «이름으로» 말한다.
6673
- // ⛔ 기본은 «막지 않는다»(config `tools.selfImplement.prEvidenceArtifactEnforce`) — 골의 내용과
6674
- // 무관하게 착지를 죽이지 않기 위한 의도적 결정이다. 다만 ***거절은 항상 관측으로 남는다***.
7012
+ // ⛔ «막지 않는다» — 골의 내용과 무관하게 착지를 죽이지 않는다. ***거절은 항상 관측으로 남는다***.
7013
+ // (차단 스위치 `prEvidenceArtifactEnforce` 는 2026-09-26 설정 졸업으로 지웠다 — 한 번도 기본으로 안 켜졌다.)
6675
7014
  const prEvidence = collectPrEvidence({
6676
7015
  feature: opts.feature,
6677
7016
  goalFile: opts.goalFile,
@@ -6686,28 +7025,19 @@ async function runSelfImplementInner(
6686
7025
  provider: activeProvider.provider,
6687
7026
  planRevision: lastPlanRevision,
6688
7027
  });
6689
- const prEvidenceDecision = decidePrEvidenceGate(prEvidence, {
6690
- enforce: userConfig.tools.selfImplement.prEvidenceArtifactEnforce === true,
6691
- });
7028
+ const prEvidenceDecision = decidePrEvidenceGate(prEvidence);
6692
7029
  observe('pr-evidence-artifact', {
6693
7030
  accepted: prEvidenceDecision.missing.length === 0,
6694
- blocked: prEvidenceDecision.blocked,
6695
- enforced: prEvidenceDecision.enforced,
6696
7031
  axes: PR_EVIDENCE_AXES.length,
6697
7032
  missingCount: prEvidenceDecision.missing.length,
6698
7033
  missing: prEvidenceDecision.missing,
6699
7034
  ...(prEvidenceDecision.reason ? { reason: prEvidenceDecision.reason } : {}),
6700
7035
  ...(prEvidenceDecision.body ? { bodyChars: prEvidenceDecision.body.length } : {}),
6701
7036
  });
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
- }
7037
+ const releaseNote = harnessReleaseNote(goalDocumentForReleaseNote(opts.goalFile), prTitle(opts.feature));
6708
7038
  const preparedPrBody = preparePrBody(
6709
7039
  [
6710
- prBody(opts.feature, impl.summary, gate.log, review, reviewIntent, declineReasons, harvestedForPr(), opts.goalFile, lastPlanRevision),
7040
+ prBody(opts.feature, impl.summary, gate.log, review, reviewIntent, declineReasons, harvestedForPr(), opts.goalFile, lastPlanRevision, releaseNote),
6711
7041
  ...(prEvidenceDecision.body ? ['', '---', '', prEvidenceDecision.body] : []),
6712
7042
  ].join('\n'),
6713
7043
  s.persistPrBodyArtifact,
@@ -6747,7 +7077,7 @@ async function runSelfImplementInner(
6747
7077
  });
6748
7078
  await flushPrComments(pr);
6749
7079
 
6750
- if (canAuto && s.mergePr) {
7080
+ if (canAuto && (s.mergePr || opts.mergeByHost)) {
6751
7081
  let docsMarkdownDeletions: number | undefined;
6752
7082
  let nonDocsMarkdownDeletions: number | undefined;
6753
7083
  let checkedHeadCommit: string | undefined;
@@ -6777,6 +7107,7 @@ async function runSelfImplementInner(
6777
7107
  guardFailure = `${checkedHeadCommit === undefined ? 'readPrCommitShas' : 'readPrDiff'} failed: ${error instanceof Error ? error.message : String(error)}`;
6778
7108
  }
6779
7109
  }
7110
+ if (opts.mergeByHost && checkedHeadCommit && !/^[0-9a-f]{40}$/i.test(checkedHeadCommit)) guardFailure = 'checked head SHA is not a full commit hash';
6780
7111
  const blocked = guardFailure !== undefined || docsMarkdownDeletions! >= DOCS_MARKDOWN_AUTO_MERGE_DELETION_THRESHOLD;
6781
7112
  observe('auto-merge-docs-deletion-guard', {
6782
7113
  number: pr.number, threshold: DOCS_MARKDOWN_AUTO_MERGE_DELETION_THRESHOLD, blocked,
@@ -6795,11 +7126,29 @@ async function runSelfImplementInner(
6795
7126
  const guardSkipReason = mergeSkipReason ?? (guardFailure ? 'merge-guard-unevaluated' : 'docs-deletion-threshold');
6796
7127
  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
7128
  }
7129
+ if (opts.mergeByHost) {
7130
+ observe('merge-ready', { number: pr.number, checkedHeadCommit });
7131
+ progress('pr-opened', `호스트 재게이트 대기 (#${pr.number})`);
7132
+ 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 };
7133
+ }
6798
7134
  onNodeEntry('merge', round);
6799
7135
  progress('merging', '자동 병합 (리뷰 clean·squash)…');
6800
- const m = await withStepTimeout(s.mergePr({ number: pr.number, cwd: wt.path, matchHeadCommit: checkedHeadCommit! }), T.pr, 'pr');
7136
+ const m = await withStepTimeout(s.mergePr!({ number: pr.number, cwd: wt.path, matchHeadCommit: checkedHeadCommit! }), T.pr, 'pr');
6801
7137
  observe('merged', { number: pr.number, merged: m.merged, detail: m.detail ?? null });
6802
7138
  if (m.merged) {
7139
+ const directory = releaseNotesDir(elanousStateRoot());
7140
+ const fragment: ReleaseNoteFragment = {
7141
+ pr: pr.number,
7142
+ ...releaseNote,
7143
+ source: 'harness',
7144
+ ...(m.mergeCommit ? { mergeSha: m.mergeCommit } : {}),
7145
+ };
7146
+ try {
7147
+ writeReleaseNote(directory, fragment);
7148
+ } catch (error) {
7149
+ observe('release-note-write-failed', { number: pr.number, prUrl: pr.url, directory, fragment, error: safeErrorDescription(error) }, { level: 'error' });
7150
+ throw new MergedReleaseNoteWriteError(pr.url, directory, fragment, error);
7151
+ }
6803
7152
  const mergedBase = m.baseRefName?.trim() || observedPrBase;
6804
7153
  const defaultBranch = resolveDefaultBranchTarget(s.defaultBranchRef ?? defaultBranchRef, wt.path).target ?? undefined;
6805
7154
  progress('merged', formatAutoMergeSuccessMessage({ prNumber: pr.number, mergedBase, defaultBranch }));