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
@@ -5,7 +5,9 @@
5
5
  * Past `tools.selfImplement.runTtlHours` (default 24) since its last commit, the sweep makes one pre-emptive move:
6
6
  * · live owning run → one resync memo in its control inbox (same path as SIBLING-RESYNC #24893/#24899),
7
7
  * at most once per (PR, head sha) — a rebase moves the head and re-arms it
8
- * · no live run → the registered `elanous:needs-rebase` label, once (QUIET-PR-COMMENTS: never a comment)
8
+ * · no live run → the registered `elanous:needs-rebase` label, once (QUIET-PR-COMMENTS: never a comment);
9
+ * when `requestRegate` is supplied, at most one of those stale PRs is also selected
10
+ * for a re-gate request (shadow: would-regate observation only; live: one call)
9
11
  *
10
12
  * Mode `tools.selfImplement.runTtl.mode`: `shadow` (default) only logs what it would do; `live` writes.
11
13
  * Cost bound: a PR opened inside the TTL is still inside its own time-to-landing and is never fetched
@@ -63,6 +65,8 @@ export interface RunTtlResult {
63
65
  readonly memo: readonly number[];
64
66
  /** Label added (live) or would be added (shadow). */
65
67
  readonly label: readonly number[];
68
+ /** Re-gate requested (live) or would be requested (shadow). Empty when the adapter is omitted. */
69
+ readonly regate: readonly number[];
66
70
  readonly alreadyMarked: readonly number[];
67
71
  readonly alreadyMemoed: readonly number[];
68
72
  /** Owning run lookup failed — left alone (a failed lookup is not a dead run). */
@@ -109,6 +113,8 @@ export async function runRunTtlSweep(input: {
109
113
  concurrency?: number;
110
114
  now?: () => number;
111
115
  log?: (category: string, event: string, data: Record<string, unknown>) => void;
116
+ /** Optional: among stale PRs with no live run, request a re-gate for at most one per sweep. */
117
+ requestRegate?: (pr: RunTtlCandidate) => Promise<void> | void;
112
118
  }): Promise<RunTtlResult> {
113
119
  const { adapters } = input;
114
120
  const now = input.now ?? Date.now;
@@ -132,6 +138,7 @@ export async function runRunTtlSweep(input: {
132
138
  const stale: number[] = [];
133
139
  const memo: number[] = [];
134
140
  const label: number[] = [];
141
+ const regate: number[] = [];
135
142
  const alreadyMarked: number[] = [];
136
143
  const alreadyMemoed: number[] = [];
137
144
  const unresolved: number[] = [];
@@ -139,17 +146,17 @@ export async function runRunTtlSweep(input: {
139
146
  const skippedFetchCap: number[] = [];
140
147
  const failed: number[] = [];
141
148
  const result = (reason?: string): RunTtlResult => ({
142
- mode, ttlHours, considered, freshByCreation, fetched, fresh, unknown, stale, memo, label, alreadyMarked,
149
+ mode, ttlHours, considered, freshByCreation, fetched, fresh, unknown, stale, memo, label, regate, alreadyMarked,
143
150
  alreadyMemoed, unresolved, skippedOverCap, skippedFetchCap, failed, durationMs: Math.max(0, now() - startedAt),
144
151
  ...(reason ? { reason } : {}),
145
152
  });
146
153
  const summary = (out: RunTtlResult): RunTtlResult => {
147
154
  emit('summary', {
148
155
  ttlHours, cap, maxFetch, concurrency, considered, freshByCreation, fetched, fresh,
149
- unknown: unknown.length, stale: stale.length, memo: memo.length, label: label.length,
156
+ unknown: unknown.length, stale: stale.length, memo: memo.length, label: label.length, regate: regate.length,
150
157
  alreadyMarked: alreadyMarked.length, alreadyMemoed: alreadyMemoed.length, unresolved: unresolved.length,
151
158
  skippedOverCap: skippedOverCap.length, skippedFetchCap: skippedFetchCap.length, failed: failed.length,
152
- memoPrs: memo, labelPrs: label, durationMs: out.durationMs, ...(out.reason ? { reason: out.reason } : {}),
159
+ memoPrs: memo, labelPrs: label, regatePrs: regate, durationMs: out.durationMs, ...(out.reason ? { reason: out.reason } : {}),
153
160
  });
154
161
  return out;
155
162
  };
@@ -200,6 +207,7 @@ export async function runRunTtlSweep(input: {
200
207
  }
201
208
  stalePrs.sort((a, b) => b.ageMs - a.ageMs || a.pr.number - b.pr.number);
202
209
  let actions = 0;
210
+ let selectedRegate = false;
203
211
  for (const { pr, target, ageMs } of stalePrs) {
204
212
  const ageHours = ageMs / 3_600_000;
205
213
  const key = `${pr.number}:${pr.headSha}`;
@@ -240,9 +248,15 @@ export async function runRunTtlSweep(input: {
240
248
  }
241
249
  }
242
250
  const reason = target.alive ? 'memo-failed' : target.reason;
251
+ const canRegate = Boolean(input.requestRegate) && !target.alive && !selectedRegate;
243
252
  if (mode === 'shadow') {
244
253
  label.push(pr.number);
245
254
  emit('would-label', { pr: pr.number, label: RUN_TTL_MARKER_LABEL, reason, ageHours: Math.floor(ageHours) });
255
+ if (canRegate) {
256
+ selectedRegate = true;
257
+ regate.push(pr.number);
258
+ emit('would-regate', { pr: pr.number, reason, ageHours: Math.floor(ageHours) });
259
+ }
246
260
  continue;
247
261
  }
248
262
  try {
@@ -253,6 +267,16 @@ export async function runRunTtlSweep(input: {
253
267
  failed.push(pr.number);
254
268
  emit('label-failed', { pr: pr.number, error: String(error) });
255
269
  }
270
+ if (canRegate) {
271
+ selectedRegate = true;
272
+ try {
273
+ await input.requestRegate!(pr);
274
+ regate.push(pr.number);
275
+ emit('regate-requested', { pr: pr.number, reason, ageHours: Math.floor(ageHours) });
276
+ } catch (error) {
277
+ emit('regate-failed', { pr: pr.number, error: String(error) });
278
+ }
279
+ }
256
280
  }
257
281
  return summary(result());
258
282
  }
@@ -2493,6 +2493,7 @@ export function defaultSeams(o: DefaultSeamsOptions = {}): SelfImplementSeams {
2493
2493
 
2494
2494
  openPr: async ({ title, body, head, base, draft, labels, cwd }) => {
2495
2495
  const resolvedBase = assertBaseBranchOnOrigin(cwd, base);
2496
+ const harnessSeat = process.env.ELANOUS_HARNESS_SEAT;
2496
2497
  const outcome = (o.prManager ?? makePrManager()).upsertPr({
2497
2498
  branch: head,
2498
2499
  worktreePath: cwd,
@@ -2501,6 +2502,7 @@ export function defaultSeams(o: DefaultSeamsOptions = {}): SelfImplementSeams {
2501
2502
  commitMessage: title,
2502
2503
  ...(resolvedBase ? { base: resolvedBase } : {}),
2503
2504
  ...(draft !== undefined ? { draft } : {}),
2505
+ ...(harnessSeat === 'OP' || harnessSeat === 'TC' || harnessSeat === 'MK' || harnessSeat === 'UX' ? { seat: harnessSeat } : {}),
2504
2506
  // BENCH-ISOLATED-ARMS ② — base 가 `bench/<id>/base` 면 라벨 `elanous:bench` 를 더한다.
2505
2507
  ...(() => {
2506
2508
  const all = benchIdFromBase(resolvedBase) && !labels?.includes(BENCH_LABEL) ? [...(labels ?? []), BENCH_LABEL] : labels;
@@ -10,6 +10,7 @@
10
10
  // 배선은 P4(현재 비-git 은 front door 에서 refuse 유지 → 이 적용 경로는 프로덕션 미도달).
11
11
 
12
12
  import { spawnSync } from 'node:child_process';
13
+ import { SPAWN_SYNC_MAX_BUFFER } from '../util/spawn-sync-output.js';
13
14
  import { cpSync, existsSync, statSync } from 'node:fs';
14
15
  import { tmpdir } from 'node:os';
15
16
  import { basename, dirname, join } from 'node:path';
@@ -49,7 +50,7 @@ export function stageNonGitDir(opts: { target: string; branch: string }): StageN
49
50
  const slug = basename(target).replace(/[^a-zA-Z0-9._-]/g, '-');
50
51
  const shadowPath = join(tmpdir(), `elanous-shadow-${slug}-${process.pid}`);
51
52
  // 이전 세대 잔여 정리(고아 방지·createWorktree resetExisting 정합).
52
- try { spawnSync('rm', ['-rf', shadowPath], { timeout: GIT_TIMEOUT_MS }); } catch { /* fail-soft */ }
53
+ try { spawnSync('rm', ['-rf', shadowPath], { timeout: GIT_TIMEOUT_MS, maxBuffer: SPAWN_SYNC_MAX_BUFFER }); } catch { /* fail-soft */ }
53
54
 
54
55
  // ② 대상 → 그림자 복사(내용 전체·심볼릭 보존 X: cpSync 기본).
55
56
  cpSync(target, shadowPath, { recursive: true });
@@ -69,7 +70,7 @@ export function stageNonGitDir(opts: { target: string; branch: string }): StageN
69
70
  path: shadowPath,
70
71
  branch,
71
72
  base,
72
- cleanup: () => { try { spawnSync('rm', ['-rf', shadowPath], { timeout: GIT_TIMEOUT_MS }); } catch { /* fail-soft */ } },
73
+ cleanup: () => { try { spawnSync('rm', ['-rf', shadowPath], { timeout: GIT_TIMEOUT_MS, maxBuffer: SPAWN_SYNC_MAX_BUFFER }); } catch { /* fail-soft */ } },
73
74
  };
74
75
  }
75
76
 
@@ -94,9 +95,9 @@ export function stageFile(opts: { target: string; branch: string }): StageFileRe
94
95
  const fileName = basename(target);
95
96
  const slug = fileName.replace(/[^a-zA-Z0-9._-]/g, '-');
96
97
  const shadowPath = join(tmpdir(), `elanous-shadow-file-${slug}-${process.pid}`);
97
- try { spawnSync('rm', ['-rf', shadowPath], { timeout: GIT_TIMEOUT_MS }); } catch { /* fail-soft */ }
98
+ try { spawnSync('rm', ['-rf', shadowPath], { timeout: GIT_TIMEOUT_MS, maxBuffer: SPAWN_SYNC_MAX_BUFFER }); } catch { /* fail-soft */ }
98
99
 
99
- spawnSync('mkdir', ['-p', shadowPath], { timeout: GIT_TIMEOUT_MS });
100
+ spawnSync('mkdir', ['-p', shadowPath], { timeout: GIT_TIMEOUT_MS, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
100
101
  cpSync(target, join(shadowPath, fileName));
101
102
 
102
103
  git(shadowPath, ['init', '-b', 'shadow-base']);
@@ -113,7 +114,7 @@ export function stageFile(opts: { target: string; branch: string }): StageFileRe
113
114
  fileName,
114
115
  branch,
115
116
  base,
116
- cleanup: () => { try { spawnSync('rm', ['-rf', shadowPath], { timeout: GIT_TIMEOUT_MS }); } catch { /* fail-soft */ } },
117
+ cleanup: () => { try { spawnSync('rm', ['-rf', shadowPath], { timeout: GIT_TIMEOUT_MS, maxBuffer: SPAWN_SYNC_MAX_BUFFER }); } catch { /* fail-soft */ } },
117
118
  };
118
119
  }
119
120
 
@@ -166,7 +167,7 @@ export function applyShadowToTarget(opts: { shadowPath: string; target: string;
166
167
  debug.log('harness.target', 'apply.backup', { target: target.slice(-48), backup: backup.slice(-48) });
167
168
 
168
169
  // ② rsync 미러링(--delete·그림자 git 메타 제외). rsync 부재 = fail-closed(백업만 남기고 미적용).
169
- const probe = spawnSync('rsync', ['--version'], { encoding: 'utf8', timeout: 5_000 });
170
+ const probe = spawnSync('rsync', ['--version'], { encoding: 'utf8', timeout: 5_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
170
171
  if (probe.status !== 0) {
171
172
  debug.log('harness.target', 'apply.no-rsync', { target: target.slice(-48) });
172
173
  return { backup, applied: false, log: 'rsync 미설치 → 적용 안 함(백업만 생성·fail-closed). 수동 적용 필요.' };
@@ -13,7 +13,7 @@
13
13
  * main-sync → rebase-regate 리베이스(MERGE-INTENT-RESOLVE 의도 해석) 뒤 재게이트
14
14
  * pod-died → resume-from-salvage `salvage/run-<6hex>/<leaf>` 가지에서 resume(DRAFT-NOT-ARCHIVE)
15
15
  * evidence-uncovered → derive-evidence-rejudge 런 출력·시험·배선에서 증거를 끌어내 1회 재판정
16
- * review-repeat · review-out-of-scope · fabric · launch-failed · unclassified → needs-owner(새 라운드 없음)
16
+ * review-repeat · review-out-of-scope · fabric · launch-failed · gate-failed · unclassified → needs-owner(새 라운드 없음)
17
17
  *
18
18
  * 사다리의 «출처»: `graphs/overlays/stop-heal-ladder.yaml` 이 갈래마다 처방 노드(id = 처방 이름)를 선언한다.
19
19
  * 그 갈래에 얹힌 오버레이가 더한 노드 id 가 처방이다(source='graph'). 선언이 없거나 못 읽으면
@@ -52,6 +52,7 @@ export const AUTOHEAL_ACTION_BY_CLASS: Readonly<Record<RunStopClass, AutohealAct
52
52
  'review-out-of-scope': 'needs-owner',
53
53
  fabric: 'needs-owner',
54
54
  'launch-failed': 'needs-owner',
55
+ 'gate-failed': 'needs-owner',
55
56
  unclassified: 'needs-owner',
56
57
  };
57
58
 
@@ -3,9 +3,10 @@
3
3
  * Unlike `dispatchHeavyCheck` it never falls back to a local run: a busy host or an infra failure is «unmeasured».
4
4
  * The only local commands are git (cat-file · rev-parse · push · diff). */
5
5
  import { debug } from '../debug/log.js';
6
+ import { parseGateScenario, readGateScenarioFile } from './gate-scenario.js';
6
7
  import { getDefaultLogStore } from '../mss/logging/log-store.js';
7
8
  import {
8
- realGateRemoteRunner, resolveGateRemoteSettings, runOnRemote,
9
+ gateRemoteHostCap, realGateRemoteRunner, resolveGateRemoteSettings, runOnRemote,
9
10
  type GateRemoteRunner, type GateRemoteSettings, type RemoteRunOutcome,
10
11
  } from './gate-remote.js';
11
12
 
@@ -21,6 +22,9 @@ export interface TrainGateInput {
21
22
  changedFiles: readonly string[];
22
23
  /** Paths deleted by the integration commit — kept in `changedFiles` for tsc/PWA reach, never run as tests. */
23
24
  deletedFiles?: readonly string[];
25
+ /** Optional v0 JSON scenario. Selected tests are additive; invalid input is unmeasured. */
26
+ scenario?: unknown;
27
+ scenarioFile?: string;
24
28
  settings?: GateRemoteSettings;
25
29
  }
26
30
 
@@ -42,9 +46,10 @@ const quote = (value: string) => `'${value.replaceAll("'", `'\\''`)}'`;
42
46
  const TEST_FILE = /\.test\.[cm]?[jt]sx?$/;
43
47
 
44
48
  /** The host-side shell body: each step runs only if the one before it passed. Exported for tests. */
45
- export function trainGateScript(baseSha: string, changedFiles: readonly string[], deleted: ReadonlySet<string> = new Set()): string {
49
+ export function trainGateScript(baseSha: string, changedFiles: readonly string[], deleted: ReadonlySet<string> = new Set(), scenarioTests: readonly string[] = []): string {
46
50
  // A deleted test file is a changed path (tsc/PWA reach) but not something to run.
47
- const tests = changedFiles.filter((file) => TEST_FILE.test(file) && !deleted.has(file));
51
+ const changedTests = changedFiles.filter((file) => TEST_FILE.test(file) && !deleted.has(file));
52
+ const tests = scenarioTests.length ? [...new Set([...changedTests, ...scenarioTests])] : changedTests;
48
53
  const steps = [
49
54
  `TSC_BASE_REF=${quote(baseSha)} bun scripts/ci-typecheck-changed.ts --local`,
50
55
  ...(tests.length ? [`bun run test:deterministic ${tests.map(quote).join(' ')}`] : []),
@@ -72,6 +77,30 @@ export const TRAIN_GATE_HOST = 'node-b';
72
77
  export async function runTrainGateOnHost(input: TrainGateInput, runner: GateRemoteRunner = realGateRemoteRunner, deps: TrainGateDeps = {}): Promise<TrainGateResult> {
73
78
  const settings = input.settings ?? await loadSettings();
74
79
  const host = settings.host;
80
+ const hostCap = gateRemoteHostCap(settings, host);
81
+ let scenarioTests: string[] = [];
82
+ if (input.scenario !== undefined || input.scenarioFile !== undefined) {
83
+ try {
84
+ if (input.scenario !== undefined && input.scenarioFile !== undefined) throw new Error('choose scenario or scenarioFile');
85
+ const scenario = parseGateScenario(input.scenarioFile === undefined ? input.scenario : readGateScenarioFile(input.scenarioFile), { baseSha: input.baseSha, headSha: input.commit, changedFiles: input.changedFiles });
86
+ if (scenario.selectedTests.some(({ path }) => input.deletedFiles?.includes(path))) throw new Error('selected test deleted');
87
+ scenarioTests = scenario.selectedTests.map(({ path }) => path);
88
+ // The remote checks out this exact commit. Verify every path against its tree locally before spending a host slot.
89
+ for (const path of scenarioTests) {
90
+ const file = runner.local('git', ['cat-file', '-e', `${input.commit}:${path}`], input.repo);
91
+ if (file.rc !== 0 || file.error) throw new Error(`selected test missing at head: ${path}`);
92
+ const tree = runner.local('git', ['ls-tree', '-z', input.commit, '--', path], input.repo);
93
+ if (tree.rc !== 0 || tree.error || !/^100(?:644|755) blob [0-9a-f]{40}\t/.test(tree.stdout)
94
+ || !tree.stdout.endsWith(`\t${path}\0`)) throw new Error(`selected test is not a regular file at head: ${path}`);
95
+ }
96
+ } catch (error) {
97
+ const reason = error instanceof Error ? error.message : String(error);
98
+ const entry: TrainGateObservation = { host, commit: input.commit, baseSha: input.baseSha, outcome: 'unmeasured', reason, changedFiles: input.changedFiles.length };
99
+ debug.log('merge-queue', 'train-gate', entry);
100
+ try { (deps.observe ?? defaultObserve)(entry); } catch { /* observation only */ }
101
+ return { outcome: 'unmeasured', host, reason };
102
+ }
103
+ }
75
104
  if (host !== TRAIN_GATE_HOST) {
76
105
  const entry: TrainGateObservation = { host, commit: input.commit, baseSha: input.baseSha, outcome: 'unmeasured', reason: `host-not-gate-host (${host} ≠ ${TRAIN_GATE_HOST})`, changedFiles: input.changedFiles.length };
77
106
  debug.log('merge-queue', 'train-gate', entry);
@@ -81,13 +110,13 @@ export async function runTrainGateOnHost(input: TrainGateInput, runner: GateRemo
81
110
  const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
82
111
  const now = deps.now ?? Date.now;
83
112
  const deadline = now() + settings.slotWaitSeconds * 1000;
84
- const script = trainGateScript(input.baseSha, input.changedFiles, new Set(input.deletedFiles ?? []));
113
+ const script = trainGateScript(input.baseSha, input.changedFiles, new Set(input.deletedFiles ?? []), scenarioTests);
85
114
  let outcome: RemoteRunOutcome;
86
115
  for (;;) {
87
116
  try {
88
117
  outcome = runOnRemote({
89
118
  repo: input.repo, host, mirror: settings.mirror, commit: input.commit, refs: [input.baseSha],
90
- argv: ['sh', '-c', script], installPwa: true, hostCap: settings.hostCap,
119
+ argv: ['sh', '-c', script], installPwa: true, hostCap,
91
120
  }, runner);
92
121
  } catch (error) {
93
122
  outcome = { kind: 'infra', reason: `exception: ${error instanceof Error ? error.message : String(error)}` };
@@ -100,7 +129,7 @@ export async function runTrainGateOnHost(input: TrainGateInput, runner: GateRemo
100
129
  }
101
130
  const result: TrainGateResult = outcome.kind === 'ran'
102
131
  ? { outcome: outcome.rc === 0 ? 'pass' : 'fail', host, ms: outcome.ms, rc: outcome.rc }
103
- : { outcome: 'unmeasured', host, reason: outcome.kind === 'busy' ? `host-busy (cap ${settings.hostCap} held for ${settings.slotWaitSeconds}s)` : outcome.reason };
132
+ : { outcome: 'unmeasured', host, reason: outcome.kind === 'busy' ? `host-busy (occupied ${outcome.occupied ?? 'unknown'}/${hostCap}, held for ${settings.slotWaitSeconds}s)` : outcome.reason };
104
133
  const entry: TrainGateObservation = {
105
134
  host, commit: input.commit, baseSha: input.baseSha, outcome: result.outcome,
106
135
  rc: result.rc, ms: result.ms, reason: result.reason, changedFiles: input.changedFiles.length,
@@ -116,7 +145,7 @@ export async function runTrainGateOnHost(input: TrainGateInput, runner: GateRemo
116
145
  * integration commit's diff against `baseSha` (local git only); a diff failure is «unmeasured», never a local run. */
117
146
  export type TrainGate = (commitSha: string, prNumbers: readonly number[]) => Promise<TrainGateOutcome>;
118
147
 
119
- export function trainGateOnHost(opts: { repo: string; baseSha: string; settings?: GateRemoteSettings }, runner: GateRemoteRunner = realGateRemoteRunner, deps: TrainGateDeps = {}): TrainGate {
148
+ export function trainGateOnHost(opts: { repo: string; baseSha: string; settings?: GateRemoteSettings; scenario?: unknown; scenarioFile?: string }, runner: GateRemoteRunner = realGateRemoteRunner, deps: TrainGateDeps = {}): TrainGate {
120
149
  const unmeasured = (commitSha: string, reason: string): 'unmeasured' => {
121
150
  const entry: TrainGateObservation = { host: opts.settings?.host ?? TRAIN_GATE_HOST, commit: commitSha, baseSha: opts.baseSha, outcome: 'unmeasured', reason, changedFiles: 0 };
122
151
  debug.log('merge-queue', 'train-gate', entry);
@@ -128,7 +157,7 @@ export function trainGateOnHost(opts: { repo: string; baseSha: string; settings?
128
157
  const diff = runner.local('git', ['diff', '--name-status', '-z', opts.baseSha, commitSha], opts.repo);
129
158
  if (diff.rc !== 0 || diff.error) return unmeasured(commitSha, 'changed-files-unavailable');
130
159
  const { changedFiles, deletedFiles } = parseNameStatus(diff.stdout);
131
- return (await runTrainGateOnHost({ repo: opts.repo, commit: commitSha, baseSha: opts.baseSha, changedFiles, deletedFiles, settings: opts.settings }, runner, deps)).outcome;
160
+ return (await runTrainGateOnHost({ repo: opts.repo, commit: commitSha, baseSha: opts.baseSha, changedFiles, deletedFiles, settings: opts.settings, scenario: opts.scenario, scenarioFile: opts.scenarioFile }, runner, deps)).outcome;
132
161
  } catch (error) {
133
162
  // Any preparation failure (local git spawn, parse, settings) is «unmeasured» — never a rejected promise, never a local run.
134
163
  return unmeasured(commitSha, `prepare-failed: ${error instanceof Error ? error.message : String(error)}`.slice(0, 200));
@@ -0,0 +1,157 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { SPAWN_SYNC_MAX_BUFFER } from '../util/spawn-sync-output.js';
3
+ import { isAbsolute } from 'node:path';
4
+ import { selectGateTestFiles } from './gate-cli.js';
5
+
6
+ export interface TrainReachCandidate {
7
+ pr: string;
8
+ headSha: string;
9
+ tree: string;
10
+ changedFiles: string[];
11
+ }
12
+
13
+ export interface TrainReachInput {
14
+ version: 1;
15
+ baseSha: string;
16
+ queueSig: string;
17
+ prs: TrainReachCandidate[];
18
+ }
19
+
20
+ export interface TrainReachObservation {
21
+ changedFiles: readonly string[];
22
+ testFiles: readonly string[];
23
+ unverified: readonly string[];
24
+ unrunImporterTotal: number | null;
25
+ lookupFailed?: string;
26
+ routeLookupFailures: readonly { source: string; reason: string }[];
27
+ callerTestsOverflow: readonly { file: string }[];
28
+ alwaysIncludeMissing: readonly string[];
29
+ }
30
+
31
+ export interface TrainReachGroup {
32
+ prs: string[];
33
+ reachTests: string[];
34
+ interactionTests: string[];
35
+ overlapEdges: Array<{ a: string; b: string; tests: string[]; paths: string[] }>;
36
+ status: 'measured' | 'unmeasured';
37
+ capacityBlocked: boolean;
38
+ reasons: string[];
39
+ }
40
+
41
+ export interface TrainReachDecision {
42
+ version: 1;
43
+ baseSha: string;
44
+ queueSig: string;
45
+ parallelSafe: boolean;
46
+ groups: TrainReachGroup[];
47
+ deferred: Array<{ pr: string; reason: string }>;
48
+ }
49
+
50
+ type InspectCandidate = (candidate: TrainReachCandidate, baseSha: string) => TrainReachObservation;
51
+
52
+ const SHA40 = /^[a-f0-9]{40}$/i;
53
+ const SHA256 = /^[a-f0-9]{64}$/i;
54
+ const safePath = (path: string) => path.length > 0 && !path.startsWith('/')
55
+ && !path.includes('\\') && !/[\x00-\x1f\x7f]/.test(path)
56
+ && !path.split('/').some((part) => part === '..' || part === '.');
57
+ const sortedUnique = (values: readonly string[]) => [...new Set(values)].sort();
58
+
59
+ function git(tree: string, ...args: string[]): string {
60
+ const result = spawnSync('git', args, { cwd: tree, encoding: 'utf8', timeout: 15_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
61
+ if (result.status !== 0 || result.error) {
62
+ throw new Error(`git ${args[0]} unmeasured: ${result.error?.message ?? result.stderr?.trim() ?? `rc=${result.status}`}`);
63
+ }
64
+ return result.stdout.trim();
65
+ }
66
+
67
+ /** The selector's own base...HEAD comparison is independently checked against the queue snapshot. */
68
+ function inspectTrainReachCandidate(candidate: TrainReachCandidate, baseSha: string): TrainReachObservation {
69
+ if (git(candidate.tree, 'rev-parse', 'HEAD').toLowerCase() !== candidate.headSha.toLowerCase()) {
70
+ throw new Error('tree HEAD differs from queued headSha');
71
+ }
72
+ if (git(candidate.tree, 'status', '--porcelain=v1')) throw new Error('tree is dirty');
73
+ git(candidate.tree, 'cat-file', '-e', `${baseSha}^{commit}`);
74
+ const observation = selectGateTestFiles(candidate.tree, { base: baseSha, includeImporterTests: true });
75
+ if (git(candidate.tree, 'rev-parse', 'HEAD').toLowerCase() !== candidate.headSha.toLowerCase()) {
76
+ throw new Error('tree HEAD changed during reach selection');
77
+ }
78
+ if (git(candidate.tree, 'status', '--porcelain=v1')) throw new Error('tree changed during reach selection');
79
+ return observation;
80
+ }
81
+
82
+ function validateInput(input: TrainReachInput): void {
83
+ if (input?.version !== 1 || !SHA40.test(input.baseSha) || !SHA256.test(input.queueSig) || !Array.isArray(input.prs)) {
84
+ throw new Error('train reach input identity unmeasured');
85
+ }
86
+ const seen = new Set<string>();
87
+ for (const candidate of input.prs) {
88
+ if (!/^[1-9]\d*$/.test(candidate?.pr) || seen.has(candidate.pr) || !SHA40.test(candidate.headSha)
89
+ || !isAbsolute(candidate.tree) || !Array.isArray(candidate.changedFiles) || candidate.changedFiles.length === 0
90
+ || !candidate.changedFiles.every((path) => typeof path === 'string' && safePath(path))) {
91
+ throw new Error(`train reach candidate invalid: ${candidate?.pr ?? 'unknown'}`);
92
+ }
93
+ seen.add(candidate.pr);
94
+ }
95
+ }
96
+
97
+ /** Pure grouping after one independently measured selector observation per queued PR. */
98
+ export function buildTrainReachDecision(input: TrainReachInput, inspect: InspectCandidate = inspectTrainReachCandidate): TrainReachDecision {
99
+ validateInput(input);
100
+ const measured: Array<{ candidate: TrainReachCandidate; tests: string[]; files: string[] }> = [];
101
+ const deferred: TrainReachDecision['deferred'] = [];
102
+ for (const candidate of input.prs) {
103
+ try {
104
+ const observed = inspect(candidate, input.baseSha);
105
+ const actual = sortedUnique(observed.changedFiles);
106
+ const expected = sortedUnique(candidate.changedFiles);
107
+ if (actual.length !== expected.length || actual.some((path, index) => path !== expected[index])) {
108
+ throw new Error('changedFiles differ from selector observation');
109
+ }
110
+ if (observed.lookupFailed || observed.routeLookupFailures.length || observed.unrunImporterTotal !== 0
111
+ || observed.callerTestsOverflow.length || observed.alwaysIncludeMissing.length || observed.unverified.length) {
112
+ throw new Error('test selection has unmeasured reach');
113
+ }
114
+ if (!observed.testFiles.every(safePath)) throw new Error('selected test path invalid');
115
+ measured.push({ candidate, tests: sortedUnique(observed.testFiles), files: sortedUnique(observed.changedFiles) });
116
+ } catch (error) {
117
+ deferred.push({ pr: candidate.pr, reason: error instanceof Error ? error.message : String(error) });
118
+ }
119
+ }
120
+
121
+ const parent = measured.map((_, index) => index);
122
+ const find = (index: number): number => {
123
+ while (parent[index] !== index) index = parent[index] = parent[parent[index]];
124
+ return index;
125
+ };
126
+ const edges: Array<{ left: number; right: number; tests: string[]; paths: string[] }> = [];
127
+ for (let left = 0; left < measured.length; left++) {
128
+ for (let right = left + 1; right < measured.length; right++) {
129
+ const tests = measured[left].tests.filter((path) => measured[right].tests.includes(path));
130
+ const paths = measured[left].files.filter((path) => measured[right].files.includes(path));
131
+ if (!tests.length && !paths.length) continue;
132
+ edges.push({ left, right, tests, paths });
133
+ parent[find(right)] = find(left);
134
+ }
135
+ }
136
+ const components = new Map<number, number[]>();
137
+ for (let index = 0; index < measured.length; index++) {
138
+ const root = find(index);
139
+ components.set(root, [...(components.get(root) ?? []), index]);
140
+ }
141
+ const groups = [...components.values()].map((indices): TrainReachGroup => {
142
+ const prs = indices.map((index) => measured[index].candidate.pr);
143
+ const counts = new Map<string, number>();
144
+ for (const index of indices) for (const test of measured[index].tests) counts.set(test, (counts.get(test) ?? 0) + 1);
145
+ const reachTests = sortedUnique([...counts.keys()]);
146
+ const interactionTests = reachTests.filter((test) => (counts.get(test) ?? 0) > 1);
147
+ const overlapEdges = edges.filter(({ left, right }) => indices.includes(left) && indices.includes(right))
148
+ .map(({ left, right, tests, paths }) => ({ a: measured[left].candidate.pr, b: measured[right].candidate.pr, tests, paths }));
149
+ const capacityBlocked = indices.length > 5;
150
+ const reasons = capacityBlocked ? ['connected reach group exceeds five PR train limit'] : [];
151
+ return { prs, reachTests, interactionTests, overlapEdges,
152
+ status: 'measured', capacityBlocked, reasons };
153
+ });
154
+ return { version: 1, baseSha: input.baseSha, queueSig: input.queueSig,
155
+ parallelSafe: deferred.length === 0 && groups.every(({ status, capacityBlocked }) => status === 'measured' && !capacityBlocked),
156
+ groups, deferred };
157
+ }
@@ -0,0 +1,133 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { isGateSpawnLaneFile } from '../self-dev/spawn-lane-files.js';
4
+ import { isTestPath } from './importer-test-index.js';
5
+ import type { TrainReachDecision, TrainReachInput } from './train-reach-grouping.js';
6
+
7
+ export interface TrainRiskEvidence {
8
+ /** Only evidence-backed paths; an empty list asserts no known hot paths for this queue. */
9
+ verifiedHotFiles: Array<{ path: string; evidence: string }>;
10
+ /** Both endpoints are test paths; evidence must describe a reproduced interaction. */
11
+ verifiedInterferencePairs: Array<{ a: string; b: string; evidence: string }>;
12
+ /** Unreproduced pairs remain visible and prohibit parallel apply when either endpoint is reached. */
13
+ suspectedPairs: Array<{ a: string; b: string; reason: string }>;
14
+ }
15
+
16
+ export interface TrainScenarioGroup {
17
+ prs: string[];
18
+ reachTests: string[];
19
+ interactionTests: string[];
20
+ riskTests: string[];
21
+ riskReasons: Array<{ test: string; reason: string; evidence: string }>;
22
+ groupRiskReasons: Array<{ reason: string; evidence: string }>;
23
+ canaryTests: string[];
24
+ scenarioTests: string[];
25
+ populationSize: number;
26
+ eligiblePopulationSize: number;
27
+ canaryTarget: number;
28
+ /** Reproducible SHA-256 input prefix: baseSha, queueSig, and sorted PRs separated by NUL. */
29
+ canarySelectionKey: string;
30
+ canaryHashMethod: string;
31
+ unmeasured: string[];
32
+ }
33
+
34
+ export interface TrainScenarioDecision {
35
+ version: 1;
36
+ baseSha: string;
37
+ queueSig: string;
38
+ parallelSafe: boolean;
39
+ groups: TrainScenarioGroup[];
40
+ unmeasured: string[];
41
+ }
42
+
43
+ const sorted = (paths: readonly string[]) => [...new Set(paths)].sort();
44
+ const validPath = (path: unknown): path is string => typeof path === 'string' && !!path && !path.startsWith('/') && !path.includes('\\')
45
+ && !/[\x00-\x1f\x7f]/.test(path) && !path.split('/').some((part) => part === '.' || part === '..');
46
+ const hash = (value: string) => createHash('sha256').update(value).digest('hex');
47
+
48
+ /** Read the tracked test population from the pinned base commit, including paths containing spaces. */
49
+ export function readTrainTestPopulation(tree: string, baseSha: string): string[] {
50
+ if (!/^[a-f0-9]{40}$/i.test(baseSha)) throw new Error('invalid baseSha for test population');
51
+ const result = spawnSync('git', ['ls-tree', '-r', '-z', '--name-only', baseSha],
52
+ { cwd: tree, encoding: 'utf8', timeout: 30_000, maxBuffer: 256 * 1024 * 1024 });
53
+ if (result.error || result.status !== 0) throw new Error(`test population unmeasured: ${result.error?.message ?? result.stderr?.trim() ?? result.status}`);
54
+ return sorted(result.stdout.split('\0').filter(isTestPath));
55
+ }
56
+
57
+ /** Pure scenario composition. No unverified hot path or interference guess is promoted to a verified risk. */
58
+ export function buildTrainScenarioDecision(
59
+ input: TrainReachInput, reach: TrainReachDecision, population: readonly string[], evidence: TrainRiskEvidence,
60
+ ): TrainScenarioDecision {
61
+ if (reach.version !== 1 || reach.baseSha !== input.baseSha || reach.queueSig !== input.queueSig
62
+ || !Array.isArray(population) || !population.every((path) => typeof path === 'string' && validPath(path) && isTestPath(path))
63
+ || !evidence || !Array.isArray(evidence.verifiedHotFiles) || !Array.isArray(evidence.verifiedInterferencePairs)
64
+ || !Array.isArray(evidence.suspectedPairs)) throw new Error('scenario identity or population unmeasured');
65
+ const tests = sorted(population);
66
+ const commonTests = new Set(tests);
67
+ const known = new Set([...tests, ...reach.groups.flatMap((group) => group.reachTests)]);
68
+ const validEvidence = (value: unknown): value is string => typeof value === 'string' && value.trim().length > 0;
69
+ for (const item of evidence.verifiedHotFiles) {
70
+ if (!validPath(item?.path) || !validEvidence(item?.evidence)) throw new Error('hot-file evidence unmeasured');
71
+ }
72
+ for (const item of [...evidence.verifiedInterferencePairs, ...evidence.suspectedPairs]) {
73
+ if (!validPath(item?.a) || !validPath(item?.b) || !known.has(item.a) || !known.has(item.b)
74
+ || item.a === item.b || !validEvidence(item && 'evidence' in item ? item.evidence : item?.reason)) {
75
+ throw new Error('interference-pair evidence unmeasured');
76
+ }
77
+ }
78
+ const changedByPr = new Map(input.prs.map(({ pr, changedFiles }) => [pr, changedFiles]));
79
+ const groups = reach.groups.map((group): TrainScenarioGroup => {
80
+ const reached = new Set(group.reachTests);
81
+ if ([...reached].some((path) => !validPath(path) || !isTestPath(path))) throw new Error('reached test path invalid');
82
+ const riskReasons: TrainScenarioGroup['riskReasons'] = [];
83
+ const groupRiskReasons: TrainScenarioGroup['groupRiskReasons'] = [];
84
+ const unavailable: string[] = [];
85
+ const risk = new Set<string>();
86
+ const addRisk = (test: string, reason: string, source: string): void => {
87
+ risk.add(test);
88
+ riskReasons.push({ test, reason, evidence: source });
89
+ };
90
+ for (const test of reached) if (isGateSpawnLaneFile(test)) addRisk(test, 'spawn-lane', 'src/self-dev/spawn-lane-files.ts');
91
+ const changed = new Set(group.prs.flatMap((pr) => changedByPr.get(pr) ?? []));
92
+ for (const hot of evidence.verifiedHotFiles) if (changed.has(hot.path)) {
93
+ groupRiskReasons.push({ reason: `hot-file:${hot.path}`, evidence: hot.evidence });
94
+ }
95
+ for (const pair of evidence.verifiedInterferencePairs) {
96
+ if (reached.has(pair.a) || reached.has(pair.b)) {
97
+ const endpoints: Array<[string, string]> = [[pair.a, pair.b], [pair.b, pair.a]];
98
+ for (const [test, other] of endpoints) {
99
+ if (reached.has(test) || commonTests.has(test)) addRisk(test, `interference-with:${other}`, pair.evidence);
100
+ else unavailable.push(`verified interference endpoint unavailable in every PR head: ${test}`);
101
+ }
102
+ }
103
+ }
104
+ const canaryPrefix = `${input.baseSha}\0${input.queueSig}\0${sorted(group.prs).join(',')}`;
105
+ const used = new Set([...reached, ...risk]);
106
+ const eligible = tests.filter((test) => !used.has(test));
107
+ const canaryTarget = eligible.length ? Math.max(1, Math.round(eligible.length * 0.02)) : 0;
108
+ const canaryTests = eligible
109
+ .sort((a, b) => hash(`${canaryPrefix}\0${a}`).localeCompare(hash(`${canaryPrefix}\0${b}`)) || a.localeCompare(b))
110
+ .slice(0, canaryTarget).sort();
111
+ const scenarioTests = sorted([...reached, ...risk, ...canaryTests]);
112
+ const scenarioSet = new Set(scenarioTests);
113
+ const unmeasured = [...unavailable, ...evidence.suspectedPairs
114
+ .filter((pair) => scenarioSet.has(pair.a) || scenarioSet.has(pair.b))
115
+ .map((pair) => `suspected interference ${pair.a} ↔ ${pair.b}: ${pair.reason}`)];
116
+ return { prs: group.prs, reachTests: group.reachTests, interactionTests: group.interactionTests,
117
+ riskTests: sorted([...risk]), riskReasons, groupRiskReasons, canaryTests,
118
+ scenarioTests, populationSize: tests.length, eligiblePopulationSize: eligible.length,
119
+ canaryTarget, canarySelectionKey: canaryPrefix,
120
+ canaryHashMethod: 'sha256(canarySelectionKey\\0path)', unmeasured };
121
+ });
122
+ const unmeasured = groups.flatMap((group) => group.unmeasured);
123
+ // A verified interference pair executed by multiple scenarios bars parallel trains, including canary selection.
124
+ for (const pair of evidence.verifiedInterferencePairs) {
125
+ const aOwners = groups.flatMap((group, index) => group.scenarioTests.includes(pair.a) ? [index] : []);
126
+ const bOwners = groups.flatMap((group, index) => group.scenarioTests.includes(pair.b) ? [index] : []);
127
+ if (aOwners.some((a) => bOwners.some((b) => a !== b))) {
128
+ unmeasured.push(`verified interference crosses groups ${pair.a} ↔ ${pair.b}: ${pair.evidence}`);
129
+ }
130
+ }
131
+ return { version: 1, baseSha: input.baseSha, queueSig: input.queueSig,
132
+ parallelSafe: reach.parallelSafe && unmeasured.length === 0, groups, unmeasured };
133
+ }
@@ -1,4 +1,5 @@
1
1
  import { spawnSync } from 'node:child_process';
2
+ import { SPAWN_SYNC_MAX_BUFFER } from '../util/spawn-sync-output.js';
2
3
  import { isElanousRuntimeArtifactPath } from './gate-scope.js';
3
4
 
4
5
  export type UncommittedWork =
@@ -19,6 +20,7 @@ export function detectUncommittedWork(worktree: string): UncommittedWork {
19
20
  env: gitEnv,
20
21
  encoding: 'utf8',
21
22
  timeout: 10_000,
23
+ maxBuffer: SPAWN_SYNC_MAX_BUFFER,
22
24
  });
23
25
  } catch (error) {
24
26
  return { status: 'unavailable', reason: error instanceof Error ? error.message : String(error) };
@@ -99,6 +99,25 @@ export function removePendingUserInput(
99
99
  return removedIds.length;
100
100
  }
101
101
 
102
+ /**
103
+ * id 로 고른 항목을 버킷 «맨 앞»으로 옮긴다(주어진 순서대로) — «지금 밀어 넣기»가 끊을 수 없는 도구 때문에
104
+ * 다음 경계로 떨어질 때, 같은 버킷의 다른 항목(goal-loop 메모 등)보다 먼저 들어가게 한다. 옮긴 수를 낸다.
105
+ */
106
+ export function prioritizePendingUserInput(ids: readonly string[]): number {
107
+ if (ids.length === 0) return 0;
108
+ const order = new Map(ids.map((id, index) => [id, index]));
109
+ let moved = 0;
110
+ for (const bucket of buckets.values()) {
111
+ const front = bucket.items.filter(item => order.has(item.id))
112
+ .sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0));
113
+ if (front.length === 0) continue;
114
+ bucket.items = [...front, ...bucket.items.filter(item => !order.has(item.id))];
115
+ moved += front.length;
116
+ }
117
+ if (moved > 0) debug.log('llm.interjection', 'prioritized', { requested: ids.length, moved });
118
+ return moved;
119
+ }
120
+
102
121
  /** 지금 이 세션에 대기 중인 수(관측·표시용). 비우지 «않는다». */
103
122
  export function pendingUserInputCount(sessionId: string): number {
104
123
  return buckets.get(sessionId)?.items.length ?? 0;