elanous 0.2.29 → 0.2.32

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 (775) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → IVKr3AlRUVLKsw2fh7eXF}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{058a98ba.7eb28d5e6dc03565.js → 0bb0ff36.b8d418980951e5ba.js} +7 -7
  5. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +27 -0
  8. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +287 -0
  9. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +62 -0
  10. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{6013-2f769370d8b4c2c6.js → 1335-6731f392c35216eb.js} +3 -3
  12. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{8332.6f0f49df772e163b.js → 1654.32de4b324981a188.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +149 -0
  17. package/apps/pwa/out/_next/static/chunks/{8795.32573a185af18c7b.js → 1913.7cc6fb6055b1ed3f.js} +2 -2
  18. package/apps/pwa/out/_next/static/chunks/{419.736c0d6f426249a7.js → 2001.6c7e0fd02190886c.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{6767.1fcfc9b8be83975f.js → 2213.2ccbada92c33ea0f.js} +16 -16
  24. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{4759.1f76713aefb87db5.js → 2871.0bca6137343b3f76.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/{6776.06ff1e3b464cc607.js → 2898.fd781bc7cf01a7b7.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{1782-59db1b5aa06df38a.js → 2940-619bfd8ef337c611.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/{8471.8d2a8c74f09c36ff.js → 2985.39ccdecd36848b12.js} +4 -4
  31. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +115 -0
  32. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +64 -0
  33. package/apps/pwa/out/_next/static/chunks/{bc324b7c.02a09dd93f6a399b.js → 3267c0e6.d34854e7b3984a6e.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3278.2e5d15b53a4091c8.js +2 -0
  35. package/apps/pwa/out/_next/static/chunks/{7725-4f83d5541fbdb81b.js → 3541-ce3a5424ed5ad7f1.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +34 -0
  39. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/{46bd8bea.2f4b4099172fcdb7.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{1142.65d002789ab3af7d.js → 4174.92ed04922709ac9e.js} +2 -2
  43. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +36 -0
  45. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +286 -0
  49. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +77 -0
  50. package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +226 -0
  51. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +79 -0
  53. package/apps/pwa/out/_next/static/chunks/5173-233188df2f42c626.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +148 -0
  57. package/apps/pwa/out/_next/static/chunks/5307.60f2209e809bd627.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{3396-97b97928c49190c9.js → 5458-16cd7a2b51b74c8c.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/{3403.7199205e65124486.js → 5525.86debf231e181813.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9143.ff14585db1d275ff.js → 5543.a438b8ab5a13ea47.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +74 -0
  65. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +94 -0
  67. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{8398.73a19b39715eda04.js → 6092.a7f99e68b188ca66.js} +1 -1
  70. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/{5591.a35e7a217734a8b9.js → 6157.0c9af021de4fb31b.js} +2 -2
  72. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/{7375.050ea0d72968e49f.js → 6433.fc573af22bbc9ab7.js} +17 -17
  75. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +90 -0
  77. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +32 -0
  78. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +104 -0
  80. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +24 -0
  85. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +93 -0
  86. package/apps/pwa/out/_next/static/chunks/69-0a2c8209c6d4a158.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
  94. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
  95. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
  110. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
  123. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/control/page-a27b1e5a0d1b308f.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/morning/page-32866485913d6a04.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-8c66a3b24a745630.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-c219f2ed171131be.js} +1 -1
  163. package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/term/page-04d00ae9b0890349.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
  184. package/apps/pwa/out/_next/static/css/b5d88eba78a3d7bf.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +26 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/bin/elanous.mjs +7 -3
  279. package/graphs/context/nightly-condense.yaml +1 -0
  280. package/graphs/implement-loop.yaml +5 -0
  281. package/graphs/intake/intake-daily.yaml +8 -1
  282. package/graphs/intake/recipes.yaml +5 -0
  283. package/graphs/lecture/lecture-note.yaml +2 -2
  284. package/graphs/ops/harness-gc.yaml +1 -0
  285. package/graphs/release/recipes.yaml +3 -0
  286. package/graphs/release/release-loop.yaml +9 -5
  287. package/graphs/units/recipes.yaml +3 -0
  288. package/graphs/units/release-gate-recheck.yaml +15 -0
  289. package/package.json +2 -1
  290. package/scripts/check-native-tool-wiring.ts +3 -2
  291. package/scripts/ci-android-unit-tests.ts +16 -0
  292. package/scripts/ci-typecheck-changed.ts +63 -10
  293. package/scripts/coord-channel-watch.sh +22 -16
  294. package/scripts/coord-role-pack.ts +81 -2
  295. package/scripts/cron-run.ts +96 -3
  296. package/scripts/detect-test-interference.ts +38 -5
  297. package/scripts/gate-pr-cache.ts +65 -0
  298. package/scripts/gh-surface/capture.ts +126 -0
  299. package/scripts/gh-surface/gh +40 -0
  300. package/scripts/import-graph-scc.ts +38 -0
  301. package/scripts/install.ps1 +19 -0
  302. package/scripts/intake-social.ts +181 -0
  303. package/scripts/lecture-note/node.ts +71 -4
  304. package/scripts/lib/android-toolchain.ts +32 -0
  305. package/scripts/lib/deterministic-env.ts +62 -0
  306. package/scripts/lib/gate-test-env.ts +19 -0
  307. package/scripts/measure-goal-grounding-corpus.ts +2 -1
  308. package/scripts/measure-si-task-cpu.ts +143 -0
  309. package/scripts/ratchets/test-interference-patterns.allowlist.txt +255 -0
  310. package/scripts/ratchets/test-interference-patterns.ts +367 -0
  311. package/scripts/release-loop/cut-branch.ts +4 -3
  312. package/scripts/release-loop/export-check-node.ts +0 -1
  313. package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
  314. package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
  315. package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
  316. package/scripts/release-loop/gate-closure.ts +12 -8
  317. package/scripts/release-loop/gate-diff.ts +1 -1
  318. package/scripts/release-loop/gate-host-mirror.ts +66 -0
  319. package/scripts/release-loop/gate-node.ts +523 -75
  320. package/scripts/release-loop/gate-partial.ts +106 -9
  321. package/scripts/release-loop/gate-pr-cache.ts +66 -0
  322. package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
  323. package/scripts/release-loop/gate-r2-verdict.ts +189 -0
  324. package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
  325. package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
  326. package/scripts/release-loop/import-graph-scc-run.ts +54 -0
  327. package/scripts/release-loop/import-graph-scc.ts +215 -0
  328. package/scripts/release-loop/node-verdict.ts +2 -0
  329. package/scripts/release-loop/prepare-node.ts +102 -4
  330. package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
  331. package/scripts/release-loop/resume-release.ts +33 -4
  332. package/scripts/release-loop/resume.ts +13 -5
  333. package/scripts/release-loop/spawn-lane.ts +2 -19
  334. package/scripts/release-loop/tui-sim-node.ts +3 -2
  335. package/scripts/release-loop/unattended-release.ts +16 -0
  336. package/scripts/test-deterministic.ts +5 -61
  337. package/scripts/train-reach-grouping.ts +48 -0
  338. package/scripts/tsc-incremental-cache.ts +86 -0
  339. package/scripts/tsc-incremental-diagnostics.ts +76 -0
  340. package/scripts/tsc-main-safety-net.ts +2 -2
  341. package/src/acp/client.ts +4 -1
  342. package/src/acp/core-turn-bridge.ts +65 -8
  343. package/src/acp/elanous-extensions.ts +3 -0
  344. package/src/acp/server.ts +3 -0
  345. package/src/acp/tool-trace.ts +186 -11
  346. package/src/ad-pipeline/run.ts +4 -2
  347. package/src/agent/runner.ts +169 -3
  348. package/src/agent/self-ambient-cache.ts +156 -0
  349. package/src/agent/self-ambient.ts +8 -1
  350. package/src/agent/subagent-callable.ts +3 -2
  351. package/src/agent/task-notification.ts +5 -0
  352. package/src/agent-mission/review-loop.ts +6 -3
  353. package/src/agent-substrate/acp-implementer.ts +14 -2
  354. package/src/agent-substrate/pr-reviewer.ts +14 -0
  355. package/src/agent-substrate/self-review-cli.ts +30 -4
  356. package/src/ask-user-question/tool.ts +22 -0
  357. package/src/autopilot/build/llm-conflict-merge.ts +56 -10
  358. package/src/autopilot/pr-manager.ts +80 -7
  359. package/src/briefing/brief-items.ts +24 -22
  360. package/src/capture/frame-state-detect.ts +39 -0
  361. package/src/capture/tui-self-report.ts +149 -6
  362. package/src/chat/chat-cli.ts +10 -2
  363. package/src/chat/index.ts +138 -26
  364. package/src/chat/input-control-key.ts +5 -3
  365. package/src/chat/pickers/modal-runtime.ts +6 -0
  366. package/src/chat/pickers/modals.ts +8 -2
  367. package/src/chat/tool-interrupt-behavior.ts +38 -0
  368. package/src/chat/tool-render/dispatch.ts +5 -1
  369. package/src/chat/turn-typeahead.ts +75 -20
  370. package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
  371. package/src/cli/agent-cli.ts +41 -13
  372. package/src/cli/ask-bare.ts +1 -0
  373. package/src/cli/config-audit.ts +123 -0
  374. package/src/cli/decisions-cli.ts +80 -6
  375. package/src/cli/import-cli.ts +12 -0
  376. package/src/cli/log-event-names.ts +17 -0
  377. package/src/cli/mcp-login.ts +21 -5
  378. package/src/cli/msg-cli.ts +89 -0
  379. package/src/cli/pod-cli.ts +14 -3
  380. package/src/cli/pr-cli.ts +273 -81
  381. package/src/cli/pr-land-base-read.ts +34 -0
  382. package/src/cli/pr-land-heavy-remote.ts +82 -26
  383. package/src/cli/pr-land-overlap-evidence.ts +109 -11
  384. package/src/cli/pr-land-pod-shadow-job.ts +106 -0
  385. package/src/cli/pr-land-pod-shadow.ts +16 -3
  386. package/src/cli/pr-land-refusal.ts +20 -5
  387. package/src/cli/pr-land-virtual-rebase.ts +108 -0
  388. package/src/cli/pty-takeover-cli.ts +88 -14
  389. package/src/cli/release-cli.ts +80 -14
  390. package/src/cli/seat-cli.ts +138 -3
  391. package/src/cli/self-update.ts +5 -2
  392. package/src/cli/sim-cli.ts +18 -0
  393. package/src/cli/tasks-cli.ts +97 -19
  394. package/src/context-bus/context-first.ts +13 -0
  395. package/src/context-bus/context-now.ts +13 -2
  396. package/src/context-bus/ops-events.ts +79 -0
  397. package/src/control-plane/lease-holder.ts +12 -8
  398. package/src/control-plane/ledger.ts +163 -4
  399. package/src/control-plane/server.ts +91 -11
  400. package/src/core-turn/run-core-turn.ts +2 -0
  401. package/src/core-turn/run-goal-loop.ts +243 -3
  402. package/src/core-turn/seat-turn-cap.ts +79 -0
  403. package/src/core-turn/short-question.ts +38 -6
  404. package/src/core-turn/types.ts +6 -0
  405. package/src/dashboard/acp-active-model.ts +42 -1
  406. package/src/dashboard/acp-boot.ts +3 -0
  407. package/src/dashboard/background-jobs-status.ts +66 -0
  408. package/src/dashboard/index.ts +339 -657
  409. package/src/dashboard/input/agent-wake.ts +242 -0
  410. package/src/dashboard/input/chat-main-entry-runtime.ts +6 -1
  411. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
  412. package/src/dashboard/input/chat-main-session.ts +8 -1
  413. package/src/dashboard/input/chat-main-turn.ts +12 -3
  414. package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
  415. package/src/dashboard/input/external-input-host.ts +49 -9
  416. package/src/dashboard/input/internal-turn.ts +261 -0
  417. package/src/dashboard/input/mouse-wiring.ts +108 -11
  418. package/src/dashboard/input/seat-autowake.ts +318 -0
  419. package/src/dashboard/input/turn-steer-bridge.ts +70 -0
  420. package/src/dashboard/log-click-runtime.ts +118 -2
  421. package/src/dashboard/loop-scheduler.ts +72 -0
  422. package/src/dashboard/seat-boot-preamble.ts +18 -0
  423. package/src/dashboard/skill-runtime.ts +2 -0
  424. package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
  425. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
  426. package/src/dashboard/slash-runtime/index.ts +13 -0
  427. package/src/dashboard/turn-busy-teardown.ts +50 -0
  428. package/src/dashboard/turn-preamble.ts +116 -40
  429. package/src/dashboard/turn-session-layers.ts +4 -2
  430. package/src/dashboard/turn-start-segments.ts +222 -0
  431. package/src/decisions/decision-ledger.ts +45 -4
  432. package/src/discord-self-message.ts +4 -4
  433. package/src/display/prompt-row-owner.ts +146 -0
  434. package/src/display/resize-listener.ts +33 -2
  435. package/src/domains/release-tool.ts +18 -1
  436. package/src/field-note/transcribe.ts +17 -0
  437. package/src/fold-stack.ts +4 -2
  438. package/src/git-fs/index.ts +263 -36
  439. package/src/github/remote-call.ts +81 -0
  440. package/src/goals/registry.ts +46 -6
  441. package/src/goals/types.ts +7 -1
  442. package/src/graph-runner/runner.ts +1 -0
  443. package/src/grok/credential.ts +26 -0
  444. package/src/harness/gate-reserve.ts +87 -0
  445. package/src/harness/harness-clean.ts +2 -1
  446. package/src/harness/harness-cli-command.ts +52 -5
  447. package/src/harness/harness-gc.ts +2 -1
  448. package/src/harness/harness-incidents.ts +70 -20
  449. package/src/harness/harness-pod-dispatch.ts +87 -10
  450. package/src/harness/harness-queue.ts +68 -4
  451. package/src/harness/harness-stop.ts +4 -3
  452. package/src/harness/harness-substrate-default.ts +78 -7
  453. package/src/harness/harness-worktree-auto.ts +2 -1
  454. package/src/harness/harness-worktrees.ts +3 -2
  455. package/src/hooks/dispatch.ts +2 -1
  456. package/src/index.ts +156 -27
  457. package/src/input/external-input-queue.ts +64 -7
  458. package/src/intake-plane/slash.ts +14 -3
  459. package/src/keybindings.ts +4 -1
  460. package/src/llm/route-decision.ts +36 -0
  461. package/src/llm/tool-loop-steered-rejection.ts +41 -0
  462. package/src/llm-request-shape.ts +209 -0
  463. package/src/llm.ts +301 -283
  464. package/src/loops/consensus.ts +348 -0
  465. package/src/loops/msg-wake.ts +206 -4
  466. package/src/loops/observe.ts +19 -3
  467. package/src/loops/orchestrator/tick.ts +88 -12
  468. package/src/loops/orchestrator/traffic.ts +64 -1
  469. package/src/loops/registry.ts +30 -0
  470. package/src/market/signed-index.ts +14 -0
  471. package/src/maturity/feature-maturity.ts +1 -1
  472. package/src/mcp/mcp-oauth.ts +54 -5
  473. package/src/models/prompts.ts +28 -0
  474. package/src/msg/msg-sse-client.ts +223 -0
  475. package/src/msg/msg-store.ts +86 -2
  476. package/src/mss/logging/log-store.ts +225 -1
  477. package/src/mss/logging/render-categories.ts +5 -0
  478. package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
  479. package/src/nexus/api/http-server.ts +54 -15
  480. package/src/nexus/api/loop-resources.ts +19 -3
  481. package/src/nexus/api/ops-api.ts +11 -0
  482. package/src/nexus/daemon-thin-inventory.md +37 -0
  483. package/src/nexus/index.ts +70 -0
  484. package/src/nexus/state/state.ts +1 -0
  485. package/src/oauth/store.ts +32 -7
  486. package/src/onboarding/first-run.ts +28 -3
  487. package/src/ops/overview-cache.ts +16 -4
  488. package/src/ops/overview.ts +59 -2
  489. package/src/ops/resources.ts +82 -0
  490. package/src/plugins/maker/connector-maker.ts +41 -0
  491. package/src/plugins/maker/skill-maker.ts +42 -0
  492. package/src/pr-tool/census.ts +303 -0
  493. package/src/pr-tool/inflight-registry.ts +143 -0
  494. package/src/prompt-library/chat-conciseness.ts +13 -0
  495. package/src/prompt-library/universal-preamble.ts +10 -5
  496. package/src/pty-shell/pty-manifest.ts +12 -3
  497. package/src/pty-shell/tui-run-state.ts +34 -3
  498. package/src/release-loop/gate-host-reservation.ts +97 -0
  499. package/src/release-loop/landing-freeze.ts +5 -0
  500. package/src/release-loop/light-rc.ts +5 -2
  501. package/src/release-loop/placement.ts +92 -1
  502. package/src/release-loop/rehearsal-shard-plan.ts +149 -0
  503. package/src/release-loop/rehearsal.ts +73 -17
  504. package/src/repl/index.ts +20 -2
  505. package/src/seat-loop/seat-knowhow.ts +282 -0
  506. package/src/seat-loop/seat-loop.ts +41 -2
  507. package/src/seat-loop/traffic-signal.ts +5 -1
  508. package/src/self-dev/ask-launch-flow.ts +37 -3
  509. package/src/self-dev/decompose-compose-graph.ts +28 -27
  510. package/src/self-dev/decompose-proposal.ts +53 -38
  511. package/src/self-dev/decompose.ts +17 -0
  512. package/src/self-dev/dev-pipeline.ts +31 -2
  513. package/src/self-dev/draft-residue.ts +267 -33
  514. package/src/self-dev/draft-sweep.ts +59 -4
  515. package/src/self-dev/external-call-zero.ts +77 -0
  516. package/src/self-dev/launch-preflight-text.ts +6 -0
  517. package/src/self-dev/launch-preflight.ts +25 -3
  518. package/src/self-dev/local-supervisor-judge.ts +185 -0
  519. package/src/self-dev/run-supervisor.ts +229 -19
  520. package/src/self-dev/run-types.ts +20 -0
  521. package/src/self-dev/shard-aggregate.ts +13 -2
  522. package/src/self-dev/shard-plan.ts +56 -1
  523. package/src/self-dev/shard-run.ts +207 -12
  524. package/src/self-dev/spawn-lane-files.ts +19 -0
  525. package/src/self-implement/app-api-budget.ts +51 -11
  526. package/src/self-implement/config-gate.ts +2 -1
  527. package/src/self-implement/elanous-tui-spawn.ts +14 -0
  528. package/src/self-implement/expose-gate.ts +2 -1
  529. package/src/self-implement/follow-up-placement.ts +79 -0
  530. package/src/self-implement/gate-artifacts.ts +416 -0
  531. package/src/self-implement/gate-baseline.ts +96 -5
  532. package/src/self-implement/gate-cli.ts +207 -17
  533. package/src/self-implement/gate-remote.ts +136 -26
  534. package/src/self-implement/gate-scenario.ts +85 -0
  535. package/src/self-implement/goal-author.ts +160 -8
  536. package/src/self-implement/graph-authority.ts +38 -6
  537. package/src/self-implement/graph-overlay-condition.ts +92 -1
  538. package/src/self-implement/heal-triage.ts +79 -0
  539. package/src/self-implement/host-regate.ts +97 -7
  540. package/src/self-implement/orchestrator.ts +115 -134
  541. package/src/self-implement/pr-title.ts +123 -0
  542. package/src/self-implement/run-checkpoint.ts +235 -0
  543. package/src/self-implement/run-ledger.ts +162 -15
  544. package/src/self-implement/run-stop.ts +4 -3
  545. package/src/self-implement/run-ttl.ts +28 -4
  546. package/src/self-implement/seams.ts +2 -0
  547. package/src/self-implement/shadow-stage.ts +7 -6
  548. package/src/self-implement/stop-autoheal.ts +2 -1
  549. package/src/self-implement/train-gate-remote.ts +37 -8
  550. package/src/self-implement/train-reach-grouping.ts +157 -0
  551. package/src/self-implement/train-scenario-layers.ts +133 -0
  552. package/src/self-implement/uncommitted-work.ts +2 -0
  553. package/src/session/pending-input.ts +19 -0
  554. package/src/session/session-start.ts +224 -0
  555. package/src/session-runtime/index.ts +22 -267
  556. package/src/session-runtime/parallel-dispatch.ts +22 -5
  557. package/src/shell-runner/background-surface.ts +15 -5
  558. package/src/skills/tools/agent.ts +39 -6
  559. package/src/skills/tools/dev-harness.ts +6 -4
  560. package/src/skills/tools/list-dir.ts +11 -0
  561. package/src/skills/tools/schedule-wakeup.ts +408 -0
  562. package/src/skills/tools/shell.ts +246 -4
  563. package/src/status/bar.ts +26 -0
  564. package/src/steward/digest-delivery.ts +118 -0
  565. package/src/steward/hold-hygiene.ts +120 -0
  566. package/src/steward/resync-tick.ts +114 -23
  567. package/src/steward/ta-repair-event-collect.ts +158 -0
  568. package/src/steward/triage.ts +10 -0
  569. package/src/surface/shell-runner-boot.ts +5 -2
  570. package/src/task-agent/card-evidence.ts +25 -1
  571. package/src/task-agent/green-sweep.ts +8 -3
  572. package/src/task-agent/judge.ts +76 -0
  573. package/src/task-agent/land-queue.ts +79 -0
  574. package/src/task-agent/live-moves.ts +30 -9
  575. package/src/task-agent/postland-card.ts +5 -0
  576. package/src/task-agent/prelaunch-already-done.ts +98 -0
  577. package/src/task-agent/real-launch-guard.ts +37 -0
  578. package/src/task-agent/rejudge-on-head.ts +89 -12
  579. package/src/task-agent/remote-rejudge-bind.ts +28 -8
  580. package/src/task-agent/repair-cycle.ts +45 -7
  581. package/src/task-agent/repair-worker.ts +7 -0
  582. package/src/task-agent/run-identity.ts +200 -0
  583. package/src/task-agent/shadow.ts +50 -3
  584. package/src/task-agent/task-hand.ts +182 -5
  585. package/src/task-agent/train-landing.ts +77 -0
  586. package/src/task-agent/work-order.ts +104 -0
  587. package/src/task-orchestrator/surfaces/pod-command-job.ts +151 -37
  588. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
  589. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
  590. package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
  591. package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
  592. package/src/task-orchestrator/surfaces/pod-lease.ts +118 -6
  593. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +1 -1
  594. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
  595. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
  596. package/src/task-orchestrator/surfaces/pod-pool.ts +3 -1
  597. package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
  598. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +67 -0
  599. package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
  600. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
  601. package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
  602. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +525 -0
  603. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
  604. package/src/task-orchestrator/surfaces/pod-warm-worker-runner.ts +90 -0
  605. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +362 -0
  606. package/src/task-orchestrator/surfaces/self-implement-pod.ts +138 -19
  607. package/src/telegram.ts +2 -4
  608. package/src/tui/chat/execution-badge.ts +5 -1
  609. package/src/tui/input/pickers.ts +732 -0
  610. package/src/tui/input-lag-probe.ts +230 -0
  611. package/src/tui/slash/mission.ts +492 -0
  612. package/src/tui/slash/term.ts +877 -0
  613. package/src/tui-client/dashboard-session.ts +9 -0
  614. package/src/tui.ts +52 -0
  615. package/src/user-config/gemini-server-tools.ts +9 -0
  616. package/src/user-config.ts +53 -16
  617. package/src/util/spawn-sync-output.ts +7 -0
  618. package/src/ux-sim/fake-bin.ts +154 -0
  619. package/src/ux-sim/fake-clock.ts +36 -0
  620. package/src/ux-sim/headless-tui.ts +72 -0
  621. package/src/ux-sim/in-process-cli.ts +2 -1
  622. package/src/ux-sim/scenario.ts +255 -0
  623. package/src/ux-sim/temp-git-remote.ts +82 -0
  624. package/src/version/packed-revision.json +1 -1
  625. package/src/video-pipeline/recipes/vlog.ts +25 -7
  626. package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
  630. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
  632. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
  635. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
  636. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
  639. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
  641. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
  647. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
  651. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
  662. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
  668. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
  671. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
  672. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
  673. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
  676. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
  678. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
  679. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
  680. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
  682. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
  688. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
  695. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
  698. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
  703. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
  705. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/botlab/page-a5635eba0d73b84e.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9f92737b8766009a.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
  768. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
  774. package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +0 -1
  775. /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → IVKr3AlRUVLKsw2fh7eXF}/_ssgManifest.js +0 -0
@@ -9,7 +9,7 @@ import { appendRunLedgerEntry, listRunLedgers, loadRunLedger, runLedgerDir, type
9
9
  import { queryRunningRuns } from '../self-implement/running-runs.js';
10
10
  import { clipRegateDetail, regateFailureFacts, type HostRegateFailure } from '../self-implement/regate-detail.js';
11
11
  import { DRAFT_SWEEP_CLOSE_CAP } from './draft-sweep.js';
12
- import { PROTECTED_LABELS, sameVerifiedGoal, type DraftTriagePr } from './draft-triage-rules.js';
12
+ import { PROTECTED_LABELS, type DraftTriagePr } from './draft-triage-rules.js';
13
13
 
14
14
  export type PodTerminalClass = 'landed' | 'merge-ready-not-merged' | 'failed-with-pr' | 'failed-no-pr' | 'failed-pr-unobserved' | 'timed-out-harvestable';
15
15
  export interface PrTerminalRecord {
@@ -43,7 +43,26 @@ export interface PodTerminalInput {
43
43
  at?: string;
44
44
  }
45
45
 
46
- const cardOf = (text?: string): string | null => /^칸:\s*(\S.*?)\s*$/m.exec(text ?? '')?.[1]?.trim() || null;
46
+ function cardOf(text?: string): string | null {
47
+ const lines = (text ?? '').split(/\r?\n/).filter((line) => line.startsWith('칸:'));
48
+ if (lines.length !== 1) return null;
49
+ const slot = lines[0]!.slice('칸:'.length).trim();
50
+ // A blank marker cannot borrow an ID from the following line. Duplicate markers are
51
+ // ambiguous even when they happen to name the same card.
52
+ return slot && !/\s/.test(slot) ? slot : null;
53
+ }
54
+ const validCardSlot = (text: string | null): text is string => !!text && /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/.test(text);
55
+ const goalLineage = (pr: ResiduePr): string | undefined =>
56
+ /(?:^|[-/])goalid-([a-f0-9]+)(?=-|\/|$)/i.exec(pr.branch)?.[1]?.toLowerCase()
57
+ ?? /^골(?: ID)?:\s*(\S.*?)\s*$/m.exec(pr.body ?? '')?.[1];
58
+ const hasCodeDiff = (paths: readonly string[]): boolean => paths.some((path) =>
59
+ !path.startsWith('docs/') && (
60
+ /\.(?:[cm]?[jt]sx?|py|sh|bash|zsh|rs|go|c|cc|cpp|h|hpp|java|kt|swift|rb|php|lua|sql)$/.test(path)
61
+ || /(?:^|\/)(?:Dockerfile|Containerfile|Makefile)(?:\.[^/]*)?$/.test(path)
62
+ || (path.startsWith('graphs/') && /\.ya?ml$/.test(path))));
63
+ function sameCardSlot(previous: ResiduePr, current: ResiduePr, slot: string): boolean {
64
+ return cardOf(previous.body) === slot && cardOf(current.body) === slot;
65
+ }
47
66
  const harvestable = PR_LABELS.find((label) => label.name === 'elanous:harvestable')!.name;
48
67
  const superseded = PR_LABELS.find((label) => label.name === 'elanous:superseded')!.name;
49
68
 
@@ -83,6 +102,8 @@ export function classifyPodTerminal(input: PodTerminalInput): PrTerminalRecord {
83
102
  export interface ResiduePr extends DraftTriagePr {
84
103
  createdAt: string;
85
104
  labels: readonly string[];
105
+ headSha?: string;
106
+ isDraft?: boolean;
86
107
  body?: string;
87
108
  comments?: readonly string[];
88
109
  /** GitHub PR state at lookup time (review r8) — absent only from injected inventories. */
@@ -92,7 +113,12 @@ export interface DraftResidueAdapters {
92
113
  loadLedger(runId: string, ledgerDir: string): readonly RunLedgerEntry[] | null;
93
114
  appendLedger(entry: RunLedgerEntry, ledgerDir: string): void;
94
115
  getPr(number: number): Promise<ResiduePr | undefined> | ResiduePr | undefined;
116
+ /** Return all issue comments only after pagination completes; undefined means completeness is unknown. */
117
+ getAllComments?(repository: string, number: number): Promise<readonly string[] | undefined> | readonly string[] | undefined;
118
+ /** Undefined means the open-draft inventory could not be observed («못 셌음») — never a disguised zero count. */
95
119
  listOpenDrafts(repository: string): Promise<readonly ResiduePr[] | undefined> | readonly ResiduePr[] | undefined;
120
+ /** Complete changed-path inventory for the newly opened PR; undefined is unmeasured. */
121
+ listPrChangedPaths?(repository: string, number: number): Promise<readonly string[] | undefined> | readonly string[] | undefined;
96
122
  addLabel(repository: string, number: number, label: string): Promise<void> | void;
97
123
  setLabels(repository: string, number: number, change: { add: string; remove: readonly string[] }): Promise<void> | void;
98
124
  comment(repository: string, number: number, body: string): Promise<void> | void;
@@ -112,14 +138,21 @@ export interface DraftResidueContext {
112
138
  }
113
139
  export type DraftResidueResult = { status: 'recorded' | 'skipped' | 'failed'; reason?: string; step?: string };
114
140
 
141
+ /** A REST pulls page carries up to 100 full PR bodies; the spawn default buffer (1 MiB) overflowed daily as
142
+ * `spawnSync gh ENOBUFS`, so every gh call gets an explicit ceiling that fits a full page of large-bodied drafts. */
143
+ const GH_MAX_BUFFER = 64 * 1024 * 1024;
144
+ /** Only the fields the residue consumes. The raw REST page (base/head repo objects, _links, review metadata, …) is
145
+ * several times larger than this projection, so the listing asks gh to project each page down to these fields. */
146
+ const OPEN_DRAFT_FIELDS = '[.[] | {number, title, headRefName: .head.ref, createdAt: .created_at, body, labels: [.labels[] | {name}], draft}]';
147
+
115
148
  function gh(args: string[]): string {
116
- const result = spawnSync('gh', args, { cwd: findGitDir(process.cwd())?.root ?? process.cwd(), encoding: 'utf8', timeout: 60_000 });
149
+ const result = spawnSync('gh', args, { cwd: findGitDir(process.cwd())?.root ?? process.cwd(), encoding: 'utf8', timeout: 60_000, maxBuffer: GH_MAX_BUFFER });
117
150
  if (result.status !== 0) throw new Error((result.stderr || result.error?.message || `gh exited ${result.status}`).trim().slice(0, 200));
118
151
  return result.stdout.trim();
119
152
  }
120
- function ghPr(row: { number: number; title: string; headRefName: string; createdAt: string; body: string; labels: Array<{ name: string }>; comments?: Array<{ body: string }>; state?: string }): ResiduePr {
153
+ function ghPr(row: { number: number; title: string; headRefName: string; headRefOid?: string; isDraft?: boolean; createdAt: string; body: string; labels: Array<{ name: string }>; comments?: Array<{ body: string }>; state?: string }): ResiduePr {
121
154
  const state = row.state === 'OPEN' || row.state === 'CLOSED' || row.state === 'MERGED' ? row.state : undefined;
122
- return { number: row.number, title: row.title, branch: row.headRefName, createdAt: row.createdAt, body: row.body,
155
+ return { number: row.number, title: row.title, branch: row.headRefName, headSha: row.headRefOid, isDraft: row.isDraft, createdAt: row.createdAt, body: row.body,
123
156
  labels: row.labels.map((label) => label.name), comments: row.comments?.map((comment) => comment.body), ...(state ? { state } : {}) };
124
157
  }
125
158
  /** Where the default `getRunStatus` reads run facts. Production reads the federated host ledgers and the running-runs
@@ -166,25 +199,54 @@ export function residueRunStatus(draft: Pick<ResiduePr, 'number'>, repository: s
166
199
  }
167
200
 
168
201
  export function defaultAdapters(sources: ResidueRunStatusSources = defaultRunStatusSources): DraftResidueAdapters {
169
- const fields = 'number,title,headRefName,createdAt,body,labels,comments,state';
202
+ const fields = 'number,title,headRefName,headRefOid,isDraft,createdAt,body,labels,comments,state';
170
203
  return {
171
204
  loadLedger: loadRunLedger,
172
205
  appendLedger: appendRunLedgerEntry,
173
206
  getPr: (number) => ghPr(JSON.parse(gh(['pr', 'view', String(number), '-R', hostRepository() ?? '', '--json', fields]))),
207
+ getAllComments: (repository, number) => {
208
+ try {
209
+ const pages: unknown = JSON.parse(gh(['api', `repos/${repository}/issues/${number}/comments?per_page=100`, '--paginate', '--slurp']));
210
+ if (!Array.isArray(pages) || !pages.every((page) => Array.isArray(page)
211
+ && page.every((row: unknown) => !!row && typeof row === 'object' && typeof (row as { body?: unknown }).body === 'string'))) return undefined;
212
+ return (pages as Array<Array<{ body: string }>>).flat().map((row) => row.body);
213
+ } catch (error) {
214
+ debug.log('draft.residue', 'comments-unobserved', { repository, number, reason: error instanceof Error ? error.message : String(error) });
215
+ return undefined;
216
+ }
217
+ },
174
218
  listOpenDrafts: (repository) => {
175
219
  const rows: ResiduePr[] = [];
176
- for (let page = 1; page <= 100; page++) {
177
- const result = JSON.parse(gh(['api', `repos/${repository}/pulls?state=open&per_page=100&page=${page}`])) as Array<{
178
- number: number; title: string; head: { ref: string }; created_at: string; body: string; draft: boolean; labels: Array<{ name: string }>;
179
- }>;
180
- if (!Array.isArray(result)) throw new Error('Invalid open PR inventory');
181
- rows.push(...result.filter((pr) => pr.draft).map((pr) => ghPr({ number: pr.number, title: pr.title, headRefName: pr.head.ref, createdAt: pr.created_at, body: pr.body, labels: pr.labels })));
182
- if (result.length < 100) return rows;
220
+ try {
221
+ for (let page = 1; page <= 100; page++) {
222
+ const result = JSON.parse(gh(['api', `repos/${repository}/pulls?state=open&per_page=100&page=${page}`, '--jq', OPEN_DRAFT_FIELDS])) as Array<{
223
+ number: number; title: string; headRefName: string; createdAt: string; body: string;
224
+ labels: Array<{ name: string }>; draft: boolean;
225
+ }>;
226
+ if (!Array.isArray(result)) throw new Error('Invalid open PR inventory');
227
+ rows.push(...result.filter((pr) => pr.draft).map((pr) => ghPr({ number: pr.number, title: pr.title, headRefName: pr.headRefName, createdAt: pr.createdAt, body: pr.body, labels: pr.labels })));
228
+ if (result.length < 100) return rows;
229
+ }
230
+ throw new Error('Open PR inventory exceeded pagination limit');
231
+ } catch (error) {
232
+ // «못 셌음»: a failed (or truncated) listing is unmeasurable — it must never surface as a counted zero.
233
+ debug.log('draft.residue', 'list-open-drafts-unobserved', { repository, reason: error instanceof Error ? error.message : String(error) });
234
+ return undefined;
183
235
  }
184
- throw new Error('Open PR inventory exceeded pagination limit');
236
+ },
237
+ listPrChangedPaths: (repository, number) => {
238
+ try {
239
+ const pages: unknown = JSON.parse(gh(['api', `repos/${repository}/pulls/${number}/files?per_page=100`, '--paginate', '--slurp']));
240
+ if (!Array.isArray(pages) || !pages.every((page) => Array.isArray(page)
241
+ && page.every((row: unknown) => !!row && typeof row === 'object' && typeof (row as { filename?: unknown }).filename === 'string'))) return undefined;
242
+ return (pages as Array<Array<{ filename: string }>>).flat().map((row) => row.filename);
243
+ } catch { return undefined; }
185
244
  },
186
245
  addLabel: (repository, number, label) => { gh(['pr', 'edit', String(number), '-R', repository, '--add-label', label]); },
187
- setLabels: (repository, number, change) => { gh(['pr', 'edit', String(number), '-R', repository, '--add-label', change.add, ...change.remove.flatMap((label) => ['--remove-label', label])]); },
246
+ setLabels: (repository, number, change) => {
247
+ const flags = [...(change.add ? ['--add-label', change.add] : []), ...change.remove.flatMap((label) => ['--remove-label', label])];
248
+ if (flags.length) gh(['pr', 'edit', String(number), '-R', repository, ...flags]);
249
+ },
188
250
  comment: (repository, number, body) => { gh(['pr', 'comment', String(number), '-R', repository, '--body', body]); },
189
251
  closePr: (repository, number) => { gh(['pr', 'close', String(number), '-R', repository]); },
190
252
  listLiveBranches: (repository) => {
@@ -319,7 +381,7 @@ export async function replayPodTerminals(options: DraftResidueReplayOptions = {}
319
381
  const outcome = await applyPodTerminal(record, { ledgerDir, ledgerRunId, adapters: replayAdapters, closeBudget });
320
382
  if (outcome.status === 'recorded' || outcome.reason === 'already-recorded') recovered++;
321
383
  else if (outcome.status === 'skipped' && outcome.reason === 'repository-unobserved') unresolved++;
322
- else if (outcome.status === 'skipped' && !['previous-run-unverified', 'previous-run-live', 'close-cap', 'host-repository-unobserved'].includes(outcome.reason ?? '')) recovered++;
384
+ else if (outcome.status === 'skipped' && !['previous-run-unverified', 'previous-run-live', 'close-cap', 'host-repository-unobserved', 'restore-unverified'].includes(outcome.reason ?? '')) recovered++;
323
385
  else pending++;
324
386
  }
325
387
  }
@@ -333,6 +395,7 @@ export async function applyPodTerminal(record: PrTerminalRecord, ctx: DraftResid
333
395
  const skipped = (reason: string): DraftResidueResult => { log('skipped', { reason }); return { status: 'skipped', reason }; };
334
396
  const budget: DraftCloseBudget = ctx.closeBudget ?? { remaining: DRAFT_SWEEP_CLOSE_CAP };
335
397
  let step = 'ledger';
398
+ let pendingSupersession: { repository: string; number: number; prNumber: number; commentMayExist: boolean } | null = null;
336
399
  try {
337
400
  const ledger = adapters.loadLedger(ctx.ledgerRunId, ctx.ledgerDir);
338
401
  if (ledger === undefined) throw new Error('Terminal ledger unavailable');
@@ -407,6 +470,28 @@ export async function applyPodTerminal(record: PrTerminalRecord, ctx: DraftResid
407
470
  step = 'ledger';
408
471
  acknowledge('owner-comment', pr.number);
409
472
  }
473
+ // PR1a records a recovery pointer but never closes this failed draft. PR1b owns the close decision.
474
+ if (record.terminalClass === 'failed-with-pr' && !completed('restore-comment', pr.number)) {
475
+ step = 'get-pr';
476
+ let latest: ResiduePr | undefined;
477
+ try { latest = await adapters.getPr(pr.number); }
478
+ catch { return skipped('restore-unverified'); }
479
+ if (!latest || latest.state !== 'OPEN' || latest.isDraft !== true || !record.headSha
480
+ || latest.headSha?.toLowerCase() !== record.headSha.toLowerCase()
481
+ || !latest.branch?.trim() || latest.branch !== pr.branch || (record.branch && latest.branch !== record.branch)
482
+ || !Array.isArray(latest.labels) || latest.labels.some((label) => PROTECTED_LABELS.has(label))) {
483
+ return skipped('restore-unverified');
484
+ }
485
+ step = 'list-comments';
486
+ let comments: readonly string[] | undefined;
487
+ try { comments = await adapters.getAllComments?.(record.repository, pr.number); }
488
+ catch { return skipped('restore-unverified'); }
489
+ if (!Array.isArray(comments) || comments.some((comment) => typeof comment !== 'string'
490
+ || /landing-verified\s*:|land-enqueue\s*:/i.test(comment))) return skipped('restore-unverified');
491
+ const restore = `Draft residue: failed-run recovery · run=${record.childRunId} · head=${record.headSha} · branch=${latest.branch} preserved. Restore from this branch.`;
492
+ if (!comments.includes(restore)) { step = 'comment'; await adapters.comment(record.repository, pr.number, restore); }
493
+ step = 'ledger'; acknowledge('restore-comment', pr.number);
494
+ }
410
495
  } else skipped('landed');
411
496
  step = 'list-open-drafts';
412
497
  const drafts = await adapters.listOpenDrafts(record.repository);
@@ -415,12 +500,33 @@ export async function applyPodTerminal(record: PrTerminalRecord, ctx: DraftResid
415
500
  throw new Error('Open draft lookup unavailable or incomplete');
416
501
  }
417
502
  const newerAt = Date.parse(pr.createdAt);
418
- const candidates = drafts.filter((draft: ResiduePr) => draft.number !== pr.number && draft.branch.startsWith('self-impl/')
503
+ const slot = cardOf(pr.body);
504
+ const taSlot = validCardSlot(slot) ? slot : undefined;
505
+ const earlier: ResiduePr[] = drafts.filter((draft: ResiduePr) => draft.number !== pr.number && draft.branch.startsWith('self-impl/')
419
506
  && Date.parse(draft.createdAt) < newerAt && !draft.labels.some((label: string) => PROTECTED_LABELS.has(label))
420
- && !completed('superseded-close', draft.number)
421
- && (!draft.labels.includes(superseded) || completed('supersede-intent', draft.number))
422
- // Only a verified goal identifier may close a PR — a shared «칸:» value or seat is not the same goal.
423
- && sameVerifiedGoal(draft, pr));
507
+ && !completed('superseded-close', draft.number));
508
+ const sameSlot = taSlot ? earlier.filter((draft) => /^[a-f0-9]{40}$/i.test(draft.headSha ?? '') && sameCardSlot(draft, pr, taSlot)
509
+ && !draft.labels.some((label) => label === 'elanous:running' || label.includes('harvest-claimed'))) : [];
510
+ let codeDiff = false;
511
+ if (taSlot && sameSlot.length) {
512
+ // A changed PR head can turn a measured code PR into a goal-only PR while files are being fetched.
513
+ step = 'get-pr';
514
+ const beforeFiles = await adapters.getPr(pr.number);
515
+ if (!beforeFiles || beforeFiles.number !== pr.number || beforeFiles.state !== pr.state
516
+ || !pr.headSha || beforeFiles.headSha !== pr.headSha || beforeFiles.branch !== pr.branch
517
+ || !sameCardSlot(beforeFiles, pr, taSlot)) return skipped('new-pr-changed-before-files');
518
+ step = 'list-pr-changed-paths';
519
+ const paths = await adapters.listPrChangedPaths?.(record.repository, pr.number);
520
+ if (!paths || !Array.isArray(paths) || paths.some((path) => typeof path !== 'string')) return skipped('new-pr-code-diff-unobserved');
521
+ step = 'get-pr';
522
+ const afterFiles = await adapters.getPr(pr.number);
523
+ if (!afterFiles || afterFiles.number !== pr.number || afterFiles.state !== pr.state
524
+ || afterFiles.headSha !== pr.headSha || afterFiles.branch !== pr.branch
525
+ || !sameCardSlot(afterFiles, pr, taSlot)) return skipped('new-pr-changed-after-files');
526
+ codeDiff = hasCodeDiff(paths);
527
+ if (!codeDiff) log('skipped', { reason: 'new-pr-goal-only', prNumber: pr.number });
528
+ }
529
+ const candidates = codeDiff ? sameSlot : [];
424
530
  let liveBranches: ReadonlySet<string> | undefined;
425
531
  if (candidates.length) {
426
532
  step = 'list-live-branches';
@@ -431,6 +537,16 @@ export async function applyPodTerminal(record: PrTerminalRecord, ctx: DraftResid
431
537
  let capped = false;
432
538
  for (const draft of candidates) {
433
539
  if (budget.remaining <= 0) { capped = true; break; }
540
+ if (taSlot) {
541
+ step = 'get-pr';
542
+ const latest = await adapters.getPr(draft.number);
543
+ if (!latest || latest.number !== draft.number || latest.state !== 'OPEN' || latest.isDraft !== true
544
+ || !draft.headSha
545
+ || latest.branch !== draft.branch || latest.headSha !== draft.headSha
546
+ || !Array.isArray(latest.labels) || latest.labels.some((label) => PROTECTED_LABELS.has(label)
547
+ || label === 'elanous:running' || label.includes('harvest-claimed'))
548
+ || !sameCardSlot(latest, pr, taSlot)) { deferred = true; skipped('previous-pr-changed'); continue; }
549
+ }
434
550
  step = 'get-run-status';
435
551
  const status = await adapters.getRunStatus(draft, record.repository);
436
552
  if (liveBranches!.has(draft.branch) || !['completed', 'failed', 'cancelled', 'abandoned', 'self-implement.result final'].includes(status ?? '')) {
@@ -438,38 +554,145 @@ export async function applyPodTerminal(record: PrTerminalRecord, ctx: DraftResid
438
554
  skipped(`previous-run-${status === 'running' || status === 'probable-running' || liveBranches!.has(draft.branch) ? 'live' : 'unobserved'}`);
439
555
  continue;
440
556
  }
557
+ if (taSlot) {
558
+ step = 'list-live-branches';
559
+ const liveNow = await adapters.listLiveBranches(record.repository);
560
+ step = 'get-run-status';
561
+ const statusNow = await adapters.getRunStatus(draft, record.repository);
562
+ if (!liveNow || liveNow.has(draft.branch)
563
+ || !['completed', 'failed', 'cancelled', 'abandoned', 'self-implement.result final'].includes(statusNow ?? '')) {
564
+ deferred = true; skipped('previous-run-changed-before-label'); continue;
565
+ }
566
+ }
567
+ // Revalidate the effective diff and both PRs before applying any public supersession marker.
568
+ if (taSlot) {
569
+ const newBeforeClose = await adapters.getPr(pr.number);
570
+ if (!newBeforeClose || newBeforeClose.number !== pr.number || newBeforeClose.state !== pr.state
571
+ || newBeforeClose.headSha !== pr.headSha || newBeforeClose.branch !== pr.branch
572
+ || !sameCardSlot(newBeforeClose, pr, taSlot)) { deferred = true; skipped('new-pr-changed-before-close'); continue; }
573
+ // The base can move without changing this PR's head. Re-read the effective diff before closing the old draft.
574
+ step = 'list-pr-changed-paths';
575
+ const currentPaths = await adapters.listPrChangedPaths?.(record.repository, pr.number);
576
+ if (!currentPaths || !Array.isArray(currentPaths) || currentPaths.some((path) => typeof path !== 'string')
577
+ || !hasCodeDiff(currentPaths)) { deferred = true; skipped('new-pr-code-diff-changed-before-close'); continue; }
578
+ step = 'get-pr';
579
+ const afterCloseDiff = await adapters.getPr(pr.number);
580
+ if (!afterCloseDiff || afterCloseDiff.number !== pr.number || afterCloseDiff.state !== pr.state
581
+ || afterCloseDiff.headSha !== pr.headSha || afterCloseDiff.branch !== pr.branch
582
+ || !sameCardSlot(afterCloseDiff, pr, taSlot)) { deferred = true; skipped('new-pr-changed-after-close-diff'); continue; }
583
+ const beforeClose = await adapters.getPr(draft.number);
584
+ if (!beforeClose || beforeClose.number !== draft.number || beforeClose.state !== 'OPEN' || beforeClose.isDraft !== true
585
+ || !draft.headSha
586
+ || beforeClose.branch !== draft.branch || beforeClose.headSha !== draft.headSha
587
+ || !Array.isArray(beforeClose.labels) || beforeClose.labels.some((label) => PROTECTED_LABELS.has(label)
588
+ || label === 'elanous:running' || label.includes('harvest-claimed'))
589
+ || !sameCardSlot(beforeClose, pr, taSlot)) { deferred = true; skipped('previous-pr-changed-before-close'); continue; }
590
+ step = 'list-live-branches';
591
+ const liveBeforeClose = await adapters.listLiveBranches(record.repository);
592
+ step = 'get-run-status';
593
+ const statusBeforeClose = await adapters.getRunStatus(draft, record.repository);
594
+ if (!liveBeforeClose || liveBeforeClose.has(draft.branch)
595
+ || !['completed', 'failed', 'cancelled', 'abandoned', 'self-implement.result final'].includes(statusBeforeClose ?? '')) {
596
+ deferred = true; skipped('previous-run-changed-before-close'); continue;
597
+ }
598
+ }
441
599
  if (!completed('supersede-intent', draft.number)) {
442
600
  step = 'ledger';
443
601
  acknowledge('supersede-intent', draft.number);
444
602
  }
445
- if (!completed('superseded-label', draft.number)) {
446
- if (!draft.labels.includes(superseded)) {
447
- step = 'set-labels';
448
- await adapters.setLabels(record.repository, draft.number, { add: superseded,
449
- remove: PR_LABELS.filter((label) => label.axis === 'state' && draft.labels.includes(label.name) && label.name !== superseded).map((label) => label.name) });
450
- }
451
- step = 'ledger';
452
- acknowledge('superseded-label', draft.number);
603
+ // The inventory was read before the liveness and diff checks. Labels can change while
604
+ // those checks run, so ownership and the state to restore come from a fresh PR read.
605
+ step = 'get-pr';
606
+ const beforeLabel = await adapters.getPr(draft.number);
607
+ if (!beforeLabel || beforeLabel.number !== draft.number || beforeLabel.state !== 'OPEN'
608
+ || beforeLabel.isDraft !== true || beforeLabel.branch !== draft.branch
609
+ || beforeLabel.headSha !== draft.headSha || !Array.isArray(beforeLabel.labels)
610
+ || beforeLabel.labels.some((label) => PROTECTED_LABELS.has(label)
611
+ || label === 'elanous:running' || label.includes('harvest-claimed'))
612
+ || (taSlot && !sameCardSlot(beforeLabel, pr, taSlot))) {
613
+ deferred = true; skipped('previous-pr-changed-before-label-write'); continue;
453
614
  }
454
- const body = `Draft residue: superseded-by #${pr.number} (newer run ${record.childRunId} of the same goal). Branch preserved.`;
615
+ // There is no conditional GitHub add-label operation. A label written before close
616
+ // cannot be safely removed on a race: another run may have added that same label
617
+ // between our read and write. Apply the public state marker only after close succeeds.
618
+ pendingSupersession = { repository: record.repository, number: draft.number, prNumber: pr.number,
619
+ commentMayExist: false };
620
+ const body = taSlot
621
+ ? `Draft residue: superseded-by #${pr.number} (same card ${taSlot}; old goalid=${goalLineage(draft) ?? 'unobserved'}; new goalid=${goalLineage(pr) ?? 'unobserved'}; newer run ${record.childRunId}). Branch preserved.`
622
+ : `Draft residue: superseded-by #${pr.number} (newer run ${record.childRunId} of the same goal). Branch preserved.`;
623
+ pendingSupersession.commentMayExist = completed('supersede-comment', draft.number);
455
624
  if (!completed('supersede-comment', draft.number)) {
456
- // REST draft listings do not contain comments; fetch them on a retry after the label was applied.
625
+ // REST draft listings do not contain comments; fetch them before deciding whether to comment.
457
626
  let comments = draft.comments;
458
- if (comments === undefined && completed('superseded-label', draft.number)) {
627
+ if (comments === undefined) {
459
628
  step = 'get-pr';
460
629
  const prior = await adapters.getPr(draft.number);
461
630
  if (!prior || prior.number !== draft.number) throw new Error('Previous PR lookup unavailable');
462
631
  comments = prior.comments;
463
632
  }
464
- if (!comments?.includes(body)) { step = 'comment'; await adapters.comment(record.repository, draft.number, body); }
633
+ if (!comments?.includes(body)) {
634
+ pendingSupersession.commentMayExist = true;
635
+ step = 'comment'; await adapters.comment(record.repository, draft.number, body);
636
+ }
465
637
  step = 'ledger';
466
638
  acknowledge('supersede-comment', draft.number);
467
639
  }
640
+ if (taSlot) {
641
+ // A claimant or new commit can arrive while GitHub accepts the label/comment writes.
642
+ step = 'list-pr-changed-paths';
643
+ const pathsAfterEffects = await adapters.listPrChangedPaths?.(record.repository, pr.number);
644
+ // The diff lookup can race a new head; bind its result to the head read after it.
645
+ step = 'get-pr';
646
+ const newAfterEffects = await adapters.getPr(pr.number);
647
+ step = 'list-live-branches';
648
+ const liveAfterEffects = await adapters.listLiveBranches(record.repository);
649
+ step = 'get-run-status';
650
+ const statusAfterEffects = await adapters.getRunStatus(draft, record.repository);
651
+ step = 'get-pr';
652
+ const oldAfterEffects = await adapters.getPr(draft.number);
653
+ if (!newAfterEffects || newAfterEffects.number !== pr.number || newAfterEffects.state !== pr.state
654
+ || newAfterEffects.headSha !== pr.headSha || newAfterEffects.branch !== pr.branch
655
+ || !sameCardSlot(newAfterEffects, pr, taSlot)
656
+ || !pathsAfterEffects || !Array.isArray(pathsAfterEffects)
657
+ || pathsAfterEffects.some((path) => typeof path !== 'string') || !hasCodeDiff(pathsAfterEffects)
658
+ || !oldAfterEffects || oldAfterEffects.number !== draft.number || oldAfterEffects.state !== 'OPEN'
659
+ || oldAfterEffects.isDraft !== true || oldAfterEffects.headSha !== draft.headSha
660
+ || oldAfterEffects.branch !== draft.branch || !Array.isArray(oldAfterEffects.labels)
661
+ || oldAfterEffects.labels.some((label) => PROTECTED_LABELS.has(label)
662
+ || label === 'elanous:running' || label.includes('harvest-claimed'))
663
+ || !sameCardSlot(oldAfterEffects, pr, taSlot)
664
+ || !liveAfterEffects || liveAfterEffects.has(draft.branch)
665
+ || !['completed', 'failed', 'cancelled', 'abandoned', 'self-implement.result final'].includes(statusAfterEffects ?? '')) {
666
+ const correction = `Draft residue: supersession by #${pr.number} deferred after PR or run changed; branch preserved. Prior superseded-by comment is no longer a close decision.`;
667
+ if (!oldAfterEffects?.comments?.includes(correction)) {
668
+ step = 'comment';
669
+ await adapters.comment(record.repository, draft.number, correction);
670
+ }
671
+ pendingSupersession = null;
672
+ deferred = true; skipped('supersession-changed-after-effects'); continue;
673
+ }
674
+ }
468
675
  step = 'close-pr';
469
676
  await adapters.closePr(record.repository, draft.number);
677
+ pendingSupersession = null;
470
678
  budget.remaining--;
471
679
  step = 'ledger';
472
680
  acknowledge('superseded-close', draft.number);
681
+ // The close is irreversible. Label failure is diagnostic, never a reason to retry
682
+ // supersession or to roll back a label whose writer cannot be identified.
683
+ if (!beforeLabel.labels.includes(superseded)) {
684
+ try {
685
+ step = 'set-labels';
686
+ // A state label read before close may have been written by another run
687
+ // before this call. Its writer is unknown, so only add our marker.
688
+ await adapters.setLabels(record.repository, draft.number, { add: superseded, remove: [] });
689
+ step = 'ledger';
690
+ if (!completed('superseded-label', draft.number)) acknowledge('superseded-label', draft.number);
691
+ } catch (labelError) {
692
+ log('superseded-label-unobserved', { previousPrNumber: draft.number,
693
+ reason: labelError instanceof Error ? labelError.message : String(labelError) });
694
+ }
695
+ }
473
696
  log('superseded-previous', { previousPrNumber: draft.number });
474
697
  }
475
698
  if (deferred) return skipped('previous-run-unverified');
@@ -479,6 +702,17 @@ export async function applyPodTerminal(record: PrTerminalRecord, ctx: DraftResid
479
702
  return { status: 'recorded' };
480
703
  } catch (error) {
481
704
  const reason = error instanceof Error ? error.message : String(error);
705
+ if (pendingSupersession) {
706
+ const pending = pendingSupersession;
707
+ try {
708
+ if (pending.commentMayExist) await adapters.comment(pending.repository, pending.number,
709
+ `Draft residue: supersession by #${pending.prNumber} deferred after an interrupted check; branch preserved. Prior superseded-by comment is no longer a close decision.`);
710
+ log('supersession-compensated', { previousPrNumber: pending.number, failedStep: step });
711
+ } catch (compensationError) {
712
+ log('supersession-compensation-failed', { previousPrNumber: pending.number,
713
+ reason: compensationError instanceof Error ? compensationError.message : String(compensationError) });
714
+ }
715
+ }
482
716
  log('failed', { step, reason });
483
717
  return { status: 'failed', step, reason };
484
718
  }
@@ -154,6 +154,12 @@ export interface DraftMetrics {
154
154
  readonly inventory: number;
155
155
  readonly oldestAgeHours: number | null;
156
156
  readonly needsOwner: number;
157
+ /**
158
+ * Per-seat needsOwner counts (own keys, finite numbers only). Unattributed drafts
159
+ * stay in the global `needsOwner` total and are absent here. Optional so existing
160
+ * screen/ledger constructors stay valid; collectDraftMetrics always fills it.
161
+ */
162
+ readonly needsOwnerBySeat?: Readonly<Record<string, number>>;
157
163
  /** Open running claims whose last update cannot be read; neither owned nor needs-owner. */
158
164
  readonly claimUnobserved?: number;
159
165
  readonly converted48h: number;
@@ -164,6 +170,8 @@ export interface DraftMetrics {
164
170
  /** Default maximum unclaimed open harness drafts for one seat. */
165
171
  export const DRAFT_NEEDS_OWNER_SEAT_CAP = 15;
166
172
 
173
+ const NEEDS_OWNER_SEATS = ['OP', 'TC', 'MK', 'UX'] as const;
174
+
167
175
  /** Compare one seat's observed needsOwner count; the caller supplies counts of open drafts by seat. */
168
176
  export function isSeatDraftNeedsOwnerOverCap(
169
177
  seat: string,
@@ -174,6 +182,50 @@ export function isSeatDraftNeedsOwnerOverCap(
174
182
  return typeof count === 'number' && Number.isFinite(count) && count > cap;
175
183
  }
176
184
 
185
+ /** Hold that seat's new launches when its needsOwner drafts exceed the default cap of 15. */
186
+ export function shouldHoldSeatNewLaunch(
187
+ seat: string,
188
+ needsOwnerBySeat: Readonly<Record<string, number>>,
189
+ ): boolean {
190
+ return isSeatDraftNeedsOwnerOverCap(seat, needsOwnerBySeat, DRAFT_NEEDS_OWNER_SEAT_CAP);
191
+ }
192
+
193
+ function draftNeedsOwner(draft: SweepDraft, owner: string | undefined, now: Date): boolean {
194
+ const state = draftClaimState(draft, now);
195
+ return state !== 'unobserved' && (state !== 'claimed' || !owner?.trim());
196
+ }
197
+
198
+ /** Seat for a needsOwner draft: active claim owner, else a unique `elanous:seat-<자리>` label. */
199
+ function needsOwnerSeatOf(draft: SweepDraft, owner: string | undefined): string | undefined {
200
+ const claimed = owner?.trim();
201
+ if (claimed && (NEEDS_OWNER_SEATS as readonly string[]).includes(claimed)) return claimed;
202
+ const found = new Set<string>();
203
+ for (const name of draft.labels) {
204
+ const seat = /^elanous:seat-(OP|TC|MK|UX)$/.exec(name)?.[1];
205
+ if (seat) found.add(seat);
206
+ }
207
+ return found.size === 1 ? [...found][0] : undefined;
208
+ }
209
+
210
+ /** Own-key, finite-number per-seat counts of drafts that still need an owner. */
211
+ export function aggregateNeedsOwnerBySeat(
212
+ drafts: readonly SweepDraft[],
213
+ owners: readonly (string | undefined)[],
214
+ now: Date,
215
+ ): Record<string, number> {
216
+ const needsOwnerBySeat: Record<string, number> = {};
217
+ for (let index = 0; index < drafts.length; index++) {
218
+ const draft = drafts[index]!;
219
+ if (!draftNeedsOwner(draft, owners[index], now)) continue;
220
+ const seat = needsOwnerSeatOf(draft, owners[index]);
221
+ if (typeof seat !== 'string' || !seat) continue;
222
+ const current = Object.hasOwn(needsOwnerBySeat, seat) ? needsOwnerBySeat[seat] : 0;
223
+ if (typeof current !== 'number' || !Number.isFinite(current)) continue;
224
+ needsOwnerBySeat[seat] = current + 1;
225
+ }
226
+ return needsOwnerBySeat;
227
+ }
228
+
177
229
  export async function collectDraftMetrics(repository: string, adapters: Pick<DraftSweepAdapters, 'listDrafts' | 'listRecentClosed' | 'getActiveClaimOwner'>, now: Date): Promise<DraftMetrics> {
178
230
  const clock = now.getTime();
179
231
  if (!Number.isFinite(clock)) throw new Error('Invalid draft metric clock');
@@ -209,13 +261,16 @@ export async function collectDraftMetrics(repository: string, adapters: Pick<Dra
209
261
  const converted48h = cohort.filter((pr) => 'mergedAt' in pr && typeof pr.mergedAt === 'string'
210
262
  && Date.parse(pr.mergedAt) >= Date.parse(pr.createdAt!) && Date.parse(pr.mergedAt) <= clock
211
263
  && Date.parse(pr.mergedAt) - Date.parse(pr.createdAt!) <= 48 * 3_600_000).length;
264
+ const needsOwnerBySeat = aggregateNeedsOwnerBySeat(open, owners, now);
265
+ // This observation reports over-cap seats; the dispatchers enforce the hold before launch.
266
+ const heldSeats = Object.keys(needsOwnerBySeat).filter((seat) =>
267
+ isSeatDraftNeedsOwnerOverCap(seat, needsOwnerBySeat, DRAFT_NEEDS_OWNER_SEAT_CAP));
268
+ try { debug.log('self-dev.draft-metrics', 'seat-launch-hold', { heldSeats, needsOwnerBySeat }); } catch { /* fail-soft */ }
212
269
  return {
213
270
  inventory: open.length,
214
271
  oldestAgeHours: open.length ? Math.max(...open.map((pr) => Math.max(0, (clock - Date.parse(pr.createdAt)) / 3_600_000))) : null,
215
- needsOwner: open.filter((draft, index) => {
216
- const state = draftClaimState(draft, now);
217
- return state !== 'unobserved' && (state !== 'claimed' || !owners[index]?.trim());
218
- }).length,
272
+ needsOwner: open.filter((draft, index) => draftNeedsOwner(draft, owners[index], now)).length,
273
+ needsOwnerBySeat,
219
274
  claimUnobserved: open.filter((draft) => draftClaimState(draft, now) === 'unobserved').length,
220
275
  converted48h,
221
276
  cohort48h: cohort.length,
@@ -0,0 +1,77 @@
1
+ // ── 외부 호출 0 모드 가드 — LLM·검색·크롤 외부 호출을 «거부하고 남긴다» ─────────────
2
+ //
3
+ // «외부 호출 0 모드»(external-call-zero mode)가 켜져 있으면 LLM·검색·크롤 외부 호출
4
+ // 시도는 전부 거부되고, 거부된 시도마다 감사 원장에 한 줄이 덧붙는다(타임스탬프 ·
5
+ // 호출 범주 · 호출자 맥락). 원장은 append-only — 이력은 «덧붙일 수만» 있고,
6
+ // 읽는 쪽이 고치거나 지울 수는 없다.
7
+ //
8
+ // 이 모듈은 순수 가드다. run-supervisor.ts 로의 배선(LLM/검색/크롤 시도를 이 가드로
9
+ // 돌리는 시임)은 이 정의를 소비하는 별도 의존 조각의 몫이다 — 여기서 운영 경로를
10
+ // 건드리지 않는 것은 의도된 경계다.
11
+
12
+ export const EXTERNAL_CALL_CATEGORIES = ['llm', 'search', 'crawl'] as const;
13
+
14
+ export type ExternalCallCategory = (typeof EXTERNAL_CALL_CATEGORIES)[number];
15
+
16
+ /** 거부된 외부 호출 시도 한 건 — 감사 원장의 한 줄. */
17
+ export interface ExternalCallAuditEntry {
18
+ /** 0부터 매 거부 시도마다 하나씩 — 같은 원장에서 재사용되지 않는다. */
19
+ readonly seq: number;
20
+ /** 시각(ISO 8601). */
21
+ readonly at: string;
22
+ /** 시도한 외부 표면(llm | search | crawl). */
23
+ readonly category: ExternalCallCategory;
24
+ /** 호출자 맥락 — 누가(어느 파일·함수·지점) 외부 호출을 청했나. */
25
+ readonly caller: string;
26
+ }
27
+
28
+ export interface ExternalCallZeroVerdict {
29
+ readonly denied: boolean;
30
+ /** 거부되어 원장에 덧붙은 줄 — 거부된 시도에만 있다. */
31
+ readonly entry?: ExternalCallAuditEntry;
32
+ }
33
+
34
+ export interface ExternalCallZeroOptions {
35
+ /** true = 외부 호출 0 모드. 기본 false — 평소 동작(호출 통과 · 기록 없음). */
36
+ readonly enabled?: boolean;
37
+ /** 시험용 시계 주입 — 운영은 벽시계를 쓴다. */
38
+ readonly now?: () => Date;
39
+ }
40
+
41
+ export class ExternalCallZeroGuard {
42
+ private readonly zeroMode: boolean;
43
+ private readonly clock: () => Date;
44
+ private readonly entries: ExternalCallAuditEntry[] = [];
45
+
46
+ constructor(options: ExternalCallZeroOptions = {}) {
47
+ this.zeroMode = options.enabled ?? false;
48
+ this.clock = options.now ?? (() => new Date());
49
+ }
50
+
51
+ /** 외부 호출 0 모드가 켜져 있는가. */
52
+ get enabled(): boolean {
53
+ return this.zeroMode;
54
+ }
55
+
56
+ /**
57
+ * 외부 호출 시도를 가드로 돌린다. 켜진 모드에서는 모든 llm/search/crawl 시도를
58
+ * 거부하고 시도마다 감사 원장에 한 줄을 덧붙인다. 꺼진 모드는 시도를 그대로
59
+ * 통과시키고 아무것도 기록하지 않는다.
60
+ */
61
+ attempt(category: ExternalCallCategory, caller: string): ExternalCallZeroVerdict {
62
+ if (!this.zeroMode) return { denied: false };
63
+ const entry: ExternalCallAuditEntry = Object.freeze({
64
+ seq: this.entries.length,
65
+ at: this.clock().toISOString(),
66
+ category,
67
+ caller,
68
+ });
69
+ this.entries.push(entry);
70
+ return { denied: true, entry };
71
+ }
72
+
73
+ /** Append-only 읽기 뷰 — 얼린 스냅숏. 읽는 쪽은 이력을 못 고친다. */
74
+ ledger(): readonly ExternalCallAuditEntry[] {
75
+ return Object.freeze([...this.entries]);
76
+ }
77
+ }
@@ -22,6 +22,12 @@ export interface LaunchPreflightBlocker {
22
22
  readonly name: string;
23
23
  /** 왜 막혔는지 한 줄 — 경로와 수를 포함한다. */
24
24
  readonly detail: string;
25
+ /** 골 판독 실패(`goal-unreadable`)와 traced-path 오류(`missing-traced-path`)를 가르는 사유 코드. */
26
+ readonly reasonCode?: 'goal-unreadable' | 'missing-traced-path';
27
+ /** 어느 검사인지 — 경로를 접지 않은 검사 이름. */
28
+ readonly checkName?: string;
29
+ /** 잘리지 않은 대상 경로. 경로 없는 검사(빈 traced paths)는 생략한다. */
30
+ readonly targetPath?: string;
25
31
  /** draft PR 경고가 연 검사 대상 경로. 동일 경로의 경고를 렌더에서 묶는다. */
26
32
  readonly draftPaths?: readonly string[];
27
33
  /** 라이브 런 충돌의 경로별 역할. ask 대상 표지가 없으면 미상이라 생략한다. */