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,12 +5,15 @@
5
5
  // GATE-REUSE-BY-DIFF (0.2.25): a code change no longer forces the full sweep — with the tip's import closure
6
6
  // (gate-closure.ts) the plan adds every test that can reach a changed file, and every test whose closure is opaque.
7
7
  // `release resume --from gate` now plans this by default when the tip moved (`--no-partial` = full gate).
8
- import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
8
+ import { existsSync, linkSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
9
+ import { randomUUID } from 'node:crypto';
9
10
  import { spawnSync } from 'node:child_process';
10
11
  import { dirname, join } from 'node:path';
11
12
  import { CODE_FILE, type ClosureVerdict } from './gate-closure';
12
13
 
13
14
  export interface PartialPlan {
15
+ /** A verified docs-only append carries the completed, clean cut without starting a test Pod. */
16
+ kind?: 'carry' | 'recheck';
14
17
  version: string;
15
18
  /** Commit the previous (full) gate measured — its recorded failures are carried for every file not re-run. */
16
19
  priorCommit: string;
@@ -22,6 +25,80 @@ export interface PartialPlan {
22
25
  priorErrors: string[];
23
26
  }
24
27
 
28
+ /** G1: a second measurement of only the failed files on the very same release commit.
29
+ * This is deliberately separate from PartialPlan, which compares two different commits. */
30
+ export interface RecheckPlan extends PartialPlan { kind: 'recheck' }
31
+
32
+ const FULL_SHA = /^[0-9a-f]{40}$/i;
33
+ const RELEASE_VERSION = /^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/;
34
+ export const recheckPlanPath = (root: string, version: string) => partialPlanPath(root, version);
35
+
36
+ /** A recheck never broadens its scope to passing or changed tests. Any uncertain input fails closed. */
37
+ export function planSameCommitRecheck(input: { version: string; measuredCommit: string; forCommit: string;
38
+ failures: readonly string[]; errors: readonly string[]; existsAtCommit: (file: string) => boolean }):
39
+ { ok: true; plan: RecheckPlan } | { ok: false; reason: string } {
40
+ if (!RELEASE_VERSION.test(input.version)) return { ok: false, reason: 'invalid release version' };
41
+ if (!FULL_SHA.test(input.measuredCommit) || !FULL_SHA.test(input.forCommit)) return { ok: false, reason: 'commit is not a full sha' };
42
+ if (input.measuredCommit !== input.forCommit) return { ok: false, reason: 'recheck requires the same commit' };
43
+ let files: string[];
44
+ try { files = [...new Set([...input.failures, ...input.errors].map(testFileOfId))].sort(); }
45
+ catch (error) { return { ok: false, reason: String(error instanceof Error ? error.message : error) }; }
46
+ if (!files.length) return { ok: false, reason: 'no failed test files to recheck' };
47
+ try {
48
+ const missing = files.find((file) => !input.existsAtCommit(file));
49
+ if (missing) return { ok: false, reason: `failed test file missing at commit: ${missing}` };
50
+ } catch (error) { return { ok: false, reason: `test file existence unreadable: ${String(error)}` }; }
51
+ return { ok: true, plan: { kind: 'recheck', version: input.version, priorCommit: input.measuredCommit,
52
+ forCommit: input.forCommit, files, priorFailures: [...input.failures], priorErrors: [...input.errors] } };
53
+ }
54
+
55
+ export function writeRecheckPlan(root: string, plan: RecheckPlan): string {
56
+ validateRecheckPlan(plan, plan.version, recheckPlanPath(root, plan.version));
57
+ const path = recheckPlanPath(root, plan.version);
58
+ const inspectExisting = (): void => {
59
+ const existing = JSON.parse(readFileSync(path, 'utf8')) as Partial<RecheckPlan>;
60
+ if (existing.kind !== 'recheck') throw new Error(`gate partial plan already exists: ${path}`);
61
+ validateRecheckPlan(existing, plan.version, path);
62
+ if (existing.forCommit !== plan.forCommit)
63
+ throw new Error(`gate recheck plan already exists for another commit: ${path}`);
64
+ if (JSON.stringify(existing) !== JSON.stringify(plan))
65
+ throw new Error(`different gate recheck plan already exists: ${path}`);
66
+ };
67
+ return publishPlanIfVacant(path, plan, inspectExisting);
68
+ }
69
+
70
+ /** Both writers of gate-partial.json must use the same no-clobber publication rule. */
71
+ function publishPlanIfVacant(path: string, plan: PartialPlan, inspectExisting: () => void): string {
72
+ if (existsSync(path)) { inspectExisting(); return path; }
73
+ mkdirSync(dirname(path), { recursive: true });
74
+ const temp = `${path}.${process.pid}.${randomUUID()}.tmp`;
75
+ try {
76
+ writeFileSync(temp, `${JSON.stringify(plan, null, 2)}\n`, { mode: 0o600, flag: 'wx' });
77
+ // Same-directory hard link publishes a complete file only if the slot is still empty.
78
+ // renameSync would overwrite a different writer's commit between inspection and publication.
79
+ try { linkSync(temp, path); }
80
+ catch (error) {
81
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
82
+ inspectExisting();
83
+ }
84
+ } finally { rmSync(temp, { force: true }); }
85
+ return path;
86
+ }
87
+
88
+ function validateRecheckPlan(raw: Partial<RecheckPlan>, version: string, path: string): asserts raw is RecheckPlan {
89
+ const invalid = () => { throw new Error(`invalid gate recheck plan: ${path}`); };
90
+ if (!RELEASE_VERSION.test(version) || raw.kind !== 'recheck' || raw.version !== version ||
91
+ typeof raw.priorCommit !== 'string' || !FULL_SHA.test(raw.priorCommit) ||
92
+ typeof raw.forCommit !== 'string' || !FULL_SHA.test(raw.forCommit) || raw.priorCommit !== raw.forCommit ||
93
+ !Array.isArray(raw.priorFailures) || !raw.priorFailures.every((id) => typeof id === 'string') ||
94
+ !Array.isArray(raw.priorErrors) || !raw.priorErrors.every((id) => typeof id === 'string') ||
95
+ !Array.isArray(raw.files) || !raw.files.length || !raw.files.every((file) => typeof file === 'string')) invalid();
96
+ let expected: string[] = [];
97
+ try { expected = [...new Set([...raw.priorFailures!, ...raw.priorErrors!].map(testFileOfId))].sort(); }
98
+ catch { invalid(); }
99
+ if (JSON.stringify(raw.files) !== JSON.stringify(expected)) invalid();
100
+ }
101
+
25
102
  export const partialPlanPath = (root: string, version: string) => join(root, 'release', version, 'gate-partial.json');
26
103
  /** The same test-file set the gate sweep runs (`git ls-files` filtered by this suffix). */
27
104
  const TEST_FILE = /^(?:[\w.-]+\/)*[\w.-]+\.test\.(?:tsx?|jsx?|mts|cts)$/;
@@ -31,6 +108,12 @@ const INERT_MD = /\.md$/;
31
108
  const TEST_INPUT = /(?:^|\/)(?:test|tests|fixtures|__fixtures__|__snapshots__|__mocks__)\//;
32
109
  const isInert = (file: string) => INERT_MD.test(file) && !TEST_INPUT.test(file);
33
110
 
111
+ /** Recheck the immutable Git diff at the consumer; a mutable plan file alone cannot authorize a zero-file gate. */
112
+ export function verifyDocsOnlyCarry(repo: string, priorCommit: string, forCommit: string): boolean {
113
+ const files = changedFilesBetween(repo, priorCommit, forCommit);
114
+ return files.length > 0 && files.every(isInert);
115
+ }
116
+
34
117
  /** The test file of a failure id (`<file> > <case>`). One rule for the gate and the partial plan: ids come only from the
35
118
  * gate's output parsers, which accept `dir/….test.ts(x)` — anything else (a root file, `..`, no case) is unsafe. */
36
119
  export function testFileOfId(id: string): string {
@@ -75,18 +158,22 @@ export function planPartialRegate(input: { version: string; priorCommit: string;
75
158
  const gone = failureFiles.filter((file) => !exists(file));
76
159
  if (gone.length) return { ok: false, reason: `prior failure file deleted at the tip → full gate: ${list(gone)}` };
77
160
  const files = [...new Set([...input.changedFiles.filter((file) => TEST_FILE.test(file) && exists(file)), ...failureFiles, ...reaching])].sort();
78
- if (!files.length) return { ok: false, reason: 'nothing to re-run' };
79
- return { ok: true, plan: { version: input.version, priorCommit: input.priorCommit, forCommit: input.forCommit, files,
161
+ // An empty selection is safe only for a genuinely docs-only diff. A deleted test also selects zero files,
162
+ // but it changes the measured suite and must not masquerade as a carry.
163
+ if (!files.length && (!input.changedFiles.length || input.changedFiles.some((file) => !isInert(file))))
164
+ return { ok: false, reason: 'nothing to re-run (not a docs-only append)' };
165
+ return { ok: true, plan: { ...(!files.length ? { kind: 'carry' as const } : {}), version: input.version, priorCommit: input.priorCommit, forCommit: input.forCommit, files,
80
166
  priorFailures: [...input.priorFailures], priorErrors: [...input.priorErrors] }, ...(closure ? { closure } : {}) };
81
167
  }
82
168
 
83
169
  export function writePartialPlan(root: string, plan: PartialPlan): string {
84
170
  const path = partialPlanPath(root, plan.version);
85
- mkdirSync(dirname(path), { recursive: true });
86
- const temp = `${path}.${process.pid}.tmp`;
87
- writeFileSync(temp, `${JSON.stringify(plan, null, 2)}\n`, { mode: 0o600 });
88
- renameSync(temp, path);
89
- return path;
171
+ return publishPlanIfVacant(path, plan, () => {
172
+ const existing = JSON.parse(readFileSync(path, 'utf8')) as PartialPlan & { kind?: unknown };
173
+ if (existing.kind === 'recheck') throw new Error(`gate recheck plan already exists: ${path}`);
174
+ if (JSON.stringify(existing) !== JSON.stringify(plan))
175
+ throw new Error(`different gate partial plan already exists: ${path}`);
176
+ });
90
177
  }
91
178
 
92
179
  export function clearPartialPlan(root: string, version: string): void {
@@ -100,10 +187,20 @@ export function readPartialPlan(roots: readonly string[], version: string, commi
100
187
  const path = partialPlanPath(root, version);
101
188
  if (!existsSync(path)) continue;
102
189
  const raw = JSON.parse(readFileSync(path, 'utf8')) as Partial<PartialPlan>;
190
+ if ((raw as Partial<RecheckPlan>).kind !== undefined && (raw as Partial<RecheckPlan>).kind !== 'recheck' && raw.kind !== 'carry')
191
+ throw new Error(`invalid gate partial plan: ${path}`);
192
+ // Until the gate consumer connects G1, the opt-in recheck plan is a shadow record.
193
+ // A legacy full gate may run, but it must never interpret a same-commit recheck as a changed-tip partial gate.
194
+ if ((raw as Partial<RecheckPlan>).kind === 'recheck') {
195
+ validateRecheckPlan(raw as Partial<RecheckPlan>, version, path);
196
+ continue;
197
+ }
103
198
  if (raw.version !== version || typeof raw.priorCommit !== 'string' || !/^[0-9a-f]{40}$/i.test(raw.priorCommit)
104
199
  || typeof raw.forCommit !== 'string' || !/^[0-9a-f]{40}$/i.test(raw.forCommit) || raw.priorCommit === raw.forCommit
105
- || !Array.isArray(raw.files) || raw.files.length === 0 || !raw.files.every((file) => typeof file === 'string' && TEST_FILE.test(file) && !file.split('/').includes('..'))
200
+ || !Array.isArray(raw.files) || (raw.files.length === 0) !== (raw.kind === 'carry')
201
+ || !raw.files.every((file) => typeof file === 'string' && TEST_FILE.test(file) && !file.split('/').includes('..'))
106
202
  || !Array.isArray(raw.priorFailures) || !Array.isArray(raw.priorErrors)) throw new Error(`invalid gate partial plan: ${path}`);
203
+ if (raw.kind === 'carry' && (raw.priorFailures.length || raw.priorErrors.length)) throw new Error(`invalid gate partial plan: ${path}`);
107
204
  // Every prior failure's file is re-run (planPartialRegate guarantees it) — a plan that would carry a failure it did
108
205
  // not re-run is malformed, not «partial».
109
206
  const rerun = new Set(raw.files);
@@ -0,0 +1,66 @@
1
+ /** Decide whether a standalone train may consume an author's exact-head remote gate. No I/O. */
2
+ export type PrGateCacheDecision = {
3
+ decision: 'reuse' | 'partial' | 'full'; reason: string; files: string[];
4
+ head: string; base: string; main: string;
5
+ };
6
+
7
+ export interface PrGateCacheInput {
8
+ summary: unknown;
9
+ head: string;
10
+ main: string;
11
+ singlePr: boolean;
12
+ baseAncestorOfHead: boolean;
13
+ baseAncestorOfMain: boolean;
14
+ /** git diff --name-only --no-renames author base..current main; null means unmeasured. */
15
+ mainChangedFiles: readonly string[] | null;
16
+ /** True only when every changed inert document was added on main, not modified or deleted. */
17
+ inertDocsAddedOnly: boolean | null;
18
+ /** Import-closure result among the author's measured cohort; null means unmeasured. */
19
+ affectedTests: readonly string[] | null;
20
+ /** Whether changed main code is in the changed PR source's forward dependency closure. */
21
+ sourceDependencyOverlap: boolean | null;
22
+ }
23
+
24
+ const SHA = /^[0-9a-f]{40}$/i;
25
+ const TEST = /\.test\.[cm]?[jt]sx?$/;
26
+ const CODE = /\.[cm]?[jt]sx?$/;
27
+ const INERT_DOC = /\.md$/;
28
+ const TEST_INPUT = /(?:^|\/)(?:test|tests|__tests__|fixtures|__fixtures__|__snapshots__|__mocks__)\//;
29
+ const safePath = (path: unknown): path is string => typeof path === 'string' && !!path
30
+ && !path.startsWith('/') && !path.split('/').some((part) => !part || part === '.' || part === '..');
31
+
32
+ export function decidePrGateCache(input: PrGateCacheInput): PrGateCacheDecision {
33
+ const raw = input.summary && typeof input.summary === 'object' && !Array.isArray(input.summary)
34
+ ? input.summary as Record<string, unknown> : {};
35
+ const base = typeof raw.base40 === 'string' ? raw.base40.toLowerCase() : '';
36
+ const head = input.head.toLowerCase();
37
+ const main = input.main.toLowerCase();
38
+ const result = (decision: PrGateCacheDecision['decision'], reason: string, files: string[] = []): PrGateCacheDecision =>
39
+ ({ decision, reason, files, head, base, main });
40
+ if (!input.singlePr) return result('full', 'bundle-train');
41
+ if (![head, base, main].every((sha) => SHA.test(sha))) return result('full', 'identity-unmeasured');
42
+ if (typeof raw.head40 !== 'string' || raw.head40.toLowerCase() !== head || raw.verdict !== 'passed' || raw.exitCode !== 0
43
+ || raw.introduced !== 0 || raw.unknown !== 0 || raw.preconditionUnmet !== 0 || raw.unrunImporters !== 0
44
+ || (raw.remoteHost !== 'node-b' && raw.remoteHost !== 'node-c'))
45
+ return result('full', 'author-gate-unmeasured-or-incomplete');
46
+ if (!Array.isArray(raw.cohort) || !raw.cohort.length || !raw.cohort.every((file) => safePath(file) && TEST.test(file)))
47
+ return result('full', 'author-cohort-unmeasured');
48
+ const cohort = [...new Set(raw.cohort as string[])];
49
+ if (!input.baseAncestorOfHead || !input.baseAncestorOfMain) return result('full', 'base-not-ancestor');
50
+ if (!input.mainChangedFiles || !input.mainChangedFiles.every(safePath)) return result('full', 'main-diff-unmeasured');
51
+ const changed = [...new Set(input.mainChangedFiles)].sort();
52
+ if (changed.some((file) => !CODE.test(file) && !(INERT_DOC.test(file) && !TEST_INPUT.test(file))))
53
+ return result('full', 'main-noncode-change');
54
+ if (changed.some((file) => INERT_DOC.test(file)) && input.inertDocsAddedOnly !== true)
55
+ return result('full', 'main-document-change-not-addition');
56
+ const codeChanged = changed.filter((file) => CODE.test(file));
57
+ if (!codeChanged.length) return result('reuse', changed.length ? 'main-doc-only-outside-radius' : 'same-content-base');
58
+ if (input.sourceDependencyOverlap === null) return result('full', 'pr-source-radius-unmeasured');
59
+ if (!input.affectedTests || !input.affectedTests.every((file) => safePath(file) && cohort.includes(file)))
60
+ return result('full', 'radius-unmeasured');
61
+ const affected = [...new Set([...input.affectedTests, ...codeChanged.filter((file) => cohort.includes(file))])].sort();
62
+ if (input.sourceDependencyOverlap && !affected.length) return result('full', 'pr-source-dependency-without-recheck-test');
63
+ if (!affected.length) return result('reuse', 'main-change-outside-pr-radius');
64
+ if (affected.length === cohort.length) return result('full', 'whole-author-cohort-affected');
65
+ return result('partial', 'main-change-inside-pr-radius', affected);
66
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Decide whether the release gate may prepare a warm worker before the cut.
3
+ * This module makes no Pod or Git calls; the caller must recheck the same inputs
4
+ * immediately before starting anything, because pool occupancy can change.
5
+ */
6
+
7
+ export const GATE_PREWARM_WINDOW_MS = 30 * 60_000;
8
+ export const GATE_PREWARM_OBSERVATION_MAX_AGE_MS = 30_000;
9
+
10
+ export interface GatePrewarmInput {
11
+ nowMs: number;
12
+ cutAtMs: number;
13
+ cutSha: string;
14
+ lockHash: string;
15
+ /** Observed current source; it must still be the candidate the cut planner named. */
16
+ sourceSha: string | null;
17
+ sourceLockHash: string | null;
18
+ /** null means absent in a measured mirror; undefined means mirror status could not be measured. */
19
+ mirrorCommitSha: string | null | undefined;
20
+ /** One snapshot time for source, mirror, occupancy and demand. */
21
+ observedAtMs: number | null;
22
+ /** Current Pod count includes any existing warm workers. */
23
+ occupiedPods: number | null;
24
+ capacity: number;
25
+ /** Pending higher-priority requests, including ones not yet represented by a Pod. */
26
+ gateDemand: number | null;
27
+ taskDemand: number | null;
28
+ }
29
+
30
+ export type GatePrewarmPlan =
31
+ | { action: 'defer'; reason: 'invalid-input' | 'outside-window' | 'unmeasured' | 'stale-observation' | 'identity' | 'higher-priority' | 'no-slot' }
32
+ | { action: 'prepare-mirror'; cutSha: string; lockHash: string }
33
+ | { action: 'start-worker'; cutSha: string; lockHash: string; slotAfter: number };
34
+
35
+ const count = (value: number | null): value is number =>
36
+ value !== null && Number.isSafeInteger(value) && value >= 0;
37
+
38
+ /** Gate > task > prewarm. Missing capacity or demand evidence never grants a worker slot. */
39
+ export function planGatePrewarm(input: GatePrewarmInput): GatePrewarmPlan {
40
+ const { nowMs, cutAtMs, cutSha, lockHash, sourceSha, sourceLockHash, mirrorCommitSha,
41
+ observedAtMs, occupiedPods, capacity, gateDemand, taskDemand } = input;
42
+ if (!Number.isSafeInteger(nowMs) || !Number.isSafeInteger(cutAtMs) || !/^[a-f0-9]{40}$/.test(cutSha)
43
+ || !/^[a-f0-9]{64}$/.test(lockHash) || !Number.isSafeInteger(capacity) || capacity < 1) {
44
+ return { action: 'defer', reason: 'invalid-input' };
45
+ }
46
+ const untilCut = cutAtMs - nowMs;
47
+ if (untilCut <= 0 || untilCut > GATE_PREWARM_WINDOW_MS) return { action: 'defer', reason: 'outside-window' };
48
+ if (mirrorCommitSha === undefined || typeof sourceSha !== 'string' || typeof sourceLockHash !== 'string'
49
+ || typeof observedAtMs !== 'number' || !count(occupiedPods) || !count(gateDemand) || !count(taskDemand)) {
50
+ return { action: 'defer', reason: 'unmeasured' };
51
+ }
52
+ if (mirrorCommitSha !== null && (typeof mirrorCommitSha !== 'string' || !/^[a-f0-9]{40}$/.test(mirrorCommitSha))) {
53
+ return { action: 'defer', reason: 'invalid-input' };
54
+ }
55
+ if (!Number.isSafeInteger(observedAtMs) || observedAtMs > nowMs
56
+ || nowMs - observedAtMs > GATE_PREWARM_OBSERVATION_MAX_AGE_MS) {
57
+ return { action: 'defer', reason: 'stale-observation' };
58
+ }
59
+ if (sourceSha !== cutSha || sourceLockHash !== lockHash) return { action: 'defer', reason: 'identity' };
60
+ // A mirror request uses no Pod slot but must not run during higher-priority traffic.
61
+ if (gateDemand > 0 || taskDemand > 0) return { action: 'defer', reason: 'higher-priority' };
62
+ // A measured mirror can be absent or hold an older commit; both require the same targeted fetch.
63
+ if (mirrorCommitSha !== cutSha) return { action: 'prepare-mirror', cutSha, lockHash };
64
+ if (occupiedPods >= capacity) return { action: 'defer', reason: 'no-slot' };
65
+ return { action: 'start-worker', cutSha, lockHash, slotAfter: capacity - occupiedPods - 1 };
66
+ }
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env bun
2
+ import { readFileSync, realpathSync, statSync } from 'node:fs';
3
+ import { parseXml, type XmlElement } from '../../src/self-dev/shard-aggregate.js';
4
+
5
+ export type GateR2Verdict = 'introduced' | 'preexisting' | 'interference-candidate' | 'environment-failure' | 'unmeasured';
6
+ export type GateR2Identity = 'exact' | 'renamed-existing-candidate' | 'identity-unmeasured';
7
+
8
+ export interface GateR2Run {
9
+ runId: string;
10
+ head40: string;
11
+ envKey: string;
12
+ cohort: string[];
13
+ rc: number;
14
+ junitPath: string;
15
+ resultPath: string;
16
+ }
17
+ export interface GateR2Input {
18
+ stableTestId: string;
19
+ head40: string;
20
+ base40: string;
21
+ envKey: string;
22
+ shards: number;
23
+ cohort: string[];
24
+ batch: GateR2Run;
25
+ solo: GateR2Run;
26
+ baseline: GateR2Run;
27
+ /** Evidence only: an equal source digest proposes a rename; it never auto-waives a failure. */
28
+ renameCandidate?: { oldTestId: string; oldDigest: string; newDigest: string; unique: boolean };
29
+ /** Two independent Pod status artifacts; an arbitrary matching log line is not infrastructure proof. */
30
+ environmentProof?: { signature: string; batchStatusPath: string; baselineStatusPath: string };
31
+ }
32
+ export interface GateR2Result {
33
+ verdict: GateR2Verdict;
34
+ identityStatus: GateR2Identity;
35
+ stableTestId: string;
36
+ evidence: { head40: string; base40: string; envKey: string; shards: number; cohort: string[];
37
+ batchResultPath: string; soloResultPath: string; baselineResultPath: string; reason: string };
38
+ }
39
+
40
+ type Cases = Map<string, 'pass' | 'fail' | 'error' | 'skipped'>;
41
+ const sha40 = /^[a-f0-9]{40}$/i;
42
+ const testFile = (id: string) => id.split(' > ')[0]?.replace(/^\.\//, '') ?? '';
43
+ /** Read complete Bun JUnit identities; malformed structure or duplicate IDs are unmeasured. */
44
+ export function gateR2JunitCases(xml: string): Cases | null {
45
+ const root = parseXml(xml);
46
+ if (root?.name !== 'testsuites' || !root.children.length) return null;
47
+ const cases: Cases = new Map();
48
+ let invalid = false;
49
+ const countMatches = (declared: string | undefined, actual: number) => declared === undefined
50
+ || (/^(0|[1-9]\d*)$/.test(declared) && Number(declared) === actual);
51
+ const walkSuite = (suite: XmlElement, parentFile: string | undefined, names: string[]): number => {
52
+ if (suite.name !== 'testsuite') { invalid = true; return 0; }
53
+ const file = suite.attrs.file ?? parentFile ?? suite.attrs.name;
54
+ const nextNames = parentFile ? [...names, suite.attrs.name ?? ''] : names;
55
+ let count = 0;
56
+ for (const child of suite.children) {
57
+ if (child.name === 'testsuite') { count += walkSuite(child, file, nextNames); continue; }
58
+ if (child.name !== 'testcase') { invalid = true; continue; }
59
+ count++;
60
+ const path = child.attrs.file ?? file;
61
+ const name = [...nextNames, child.attrs.name ?? ''].filter(Boolean).join(' > ');
62
+ if (!path || !child.attrs.name || !name || child.children.some((marker) => !['failure', 'error', 'skipped', 'system-out', 'system-err'].includes(marker.name))) {
63
+ invalid = true; continue;
64
+ }
65
+ const id = `${path.replace(/^\.\//, '')} > ${name}`;
66
+ if (cases.has(id)) { invalid = true; continue; }
67
+ const markers = child.children.filter((marker) => ['failure', 'error', 'skipped'].includes(marker.name));
68
+ if (markers.length > 1) { invalid = true; continue; }
69
+ cases.set(id, markers[0]?.name === 'failure' ? 'fail' : markers[0]?.name === 'error' ? 'error'
70
+ : markers[0]?.name === 'skipped' ? 'skipped' : 'pass');
71
+ }
72
+ if (!countMatches(suite.attrs.tests, count)) invalid = true;
73
+ return count;
74
+ };
75
+ const count = root.children.reduce((total, child) => total + walkSuite(child, undefined, []), 0);
76
+ if (!countMatches(root.attrs.tests, count)) invalid = true;
77
+ return invalid || cases.size === 0 ? null : cases;
78
+ }
79
+
80
+ function readSmall(path: string): string {
81
+ if (!path || statSync(path).size > 16 * 1024 * 1024) throw new Error('artifact missing or too large');
82
+ return readFileSync(path, 'utf8');
83
+ }
84
+
85
+ export function classifyGateR2Verdict(input: GateR2Input, read: (path: string) => string = readSmall): GateR2Result {
86
+ const source = (input && typeof input === 'object' ? input : {}) as Partial<GateR2Input>;
87
+ const { batch, solo, baseline } = source;
88
+ const evidence = { head40: source.head40 ?? '', base40: source.base40 ?? '', envKey: source.envKey ?? '', shards: source.shards ?? 0,
89
+ cohort: Array.isArray(source.cohort) ? [...source.cohort] : [], batchResultPath: batch?.resultPath ?? '', soloResultPath: solo?.resultPath ?? '',
90
+ baselineResultPath: baseline?.resultPath ?? '', reason: '' };
91
+ const answer = (verdict: GateR2Verdict, reason: string, identityStatus: GateR2Identity = 'exact'): GateR2Result =>
92
+ ({ verdict, identityStatus, stableTestId: source.stableTestId ?? '', evidence: { ...evidence, reason } });
93
+ const unique = (paths: string[]) => paths.length === new Set(paths).size && paths.every((path) =>
94
+ path.split('/').every((part) => part !== '.' && part !== '..' && /^[\w.-]+$/.test(part))
95
+ && /\.(test|spec)\.[cm]?[tj]sx?$/.test(path));
96
+ if (typeof input?.stableTestId !== 'string' || typeof input.head40 !== 'string' || typeof input.base40 !== 'string'
97
+ || typeof input.envKey !== 'string' || !Array.isArray(input.cohort) || !Array.isArray(batch?.cohort)
98
+ || !Array.isArray(solo?.cohort) || !Array.isArray(baseline?.cohort)
99
+ || !sha40.test(input.head40) || !sha40.test(input.base40) || !input.envKey || !Number.isSafeInteger(input.shards) || input.shards < 1
100
+ || !input.stableTestId.includes(' > ') || !unique(input.cohort) || input.cohort.length < 2
101
+ || JSON.stringify(input.cohort) !== JSON.stringify([...input.cohort].sort())
102
+ || !input.cohort.includes(testFile(input.stableTestId)) || !batch || !solo || !baseline)
103
+ return answer('unmeasured', 'identity or cohort input invalid', 'identity-unmeasured');
104
+ if (batch.head40 !== input.head40 || solo.head40 !== input.head40 || baseline.head40 !== input.base40
105
+ || [batch, solo, baseline].some((run) => run.envKey !== input.envKey || !Number.isSafeInteger(run.rc) || run.rc < 0
106
+ || typeof run.runId !== 'string' || run.runId.length < 8 || !run.resultPath || !run.junitPath)
107
+ || new Set([batch.runId, solo.runId, baseline.runId]).size !== 3
108
+ || new Set([batch.junitPath, batch.resultPath, solo.junitPath, solo.resultPath, baseline.junitPath, baseline.resultPath]).size !== 6
109
+ || JSON.stringify(batch.cohort) !== JSON.stringify(input.cohort)
110
+ || JSON.stringify(solo.cohort) !== JSON.stringify([testFile(input.stableTestId)])
111
+ || JSON.stringify(baseline.cohort) !== JSON.stringify([testFile(input.stableTestId)]))
112
+ return answer('unmeasured', 'head/env/cohort/artifact mismatch', 'identity-unmeasured');
113
+ let batchCases: Cases, soloCases: Cases, baseCases: Cases;
114
+ try {
115
+ const artifactPaths = [batch.junitPath, batch.resultPath, solo.junitPath, solo.resultPath, baseline.junitPath, baseline.resultPath];
116
+ if (new Set(artifactPaths.map((path) => realpathSync(path))).size !== artifactPaths.length
117
+ || new Set(artifactPaths.map((path) => { const stat = statSync(path); return `${stat.dev}:${stat.ino}`; })).size !== artifactPaths.length)
118
+ return answer('unmeasured', 'run artifacts resolve to the same file', 'identity-unmeasured');
119
+ for (const run of [batch, solo, baseline]) {
120
+ const result = JSON.parse(read(run.resultPath)) as Partial<GateR2Run>;
121
+ if (result.head40 !== run.head40 || result.envKey !== run.envKey || result.rc !== run.rc || result.runId !== run.runId
122
+ || result.resultPath !== run.resultPath
123
+ || result.junitPath !== run.junitPath || JSON.stringify(result.cohort) !== JSON.stringify(run.cohort))
124
+ return answer('unmeasured', 'result artifact disagrees with run identity', 'identity-unmeasured');
125
+ }
126
+ const parsed = [batch, solo, baseline].map((run) => gateR2JunitCases(read(run.junitPath)));
127
+ if (parsed.some((cases) => cases === null)) return answer('unmeasured', 'JUnit incomplete or duplicate IDs', 'identity-unmeasured');
128
+ if ([batch, solo, baseline].some((run, index) => [...parsed[index]!.keys()].some((id) => !run.cohort.includes(testFile(id)))))
129
+ return answer('unmeasured', 'JUnit testcase outside declared cohort', 'identity-unmeasured');
130
+ [batchCases, soloCases, baseCases] = parsed as Cases[];
131
+ if ([batch, solo, baseline].some((run, index) => {
132
+ const hasFailure = [...parsed[index]!.values()].some((status) => status === 'fail' || status === 'error');
133
+ return (run.rc === 0) === hasFailure;
134
+ })) return answer('unmeasured', 'JUnit failures contradict process exit code', 'identity-unmeasured');
135
+ } catch { return answer('unmeasured', 'JUnit unreadable', 'identity-unmeasured'); }
136
+ const issue = (value: string | undefined) => value === 'fail' || value === 'error';
137
+ if (!issue(batchCases.get(input.stableTestId)) || batch.rc === 0)
138
+ return answer('unmeasured', 'batch failure identity not proved', 'identity-unmeasured');
139
+ const soloStatus = soloCases.get(input.stableTestId);
140
+ const baseStatus = baseCases.get(input.stableTestId);
141
+ const rename = input.renameCandidate;
142
+ const renameStatus: GateR2Identity = rename?.unique && typeof rename.oldDigest === 'string'
143
+ && typeof rename.newDigest === 'string' && rename.oldDigest.length >= 8 && rename.oldDigest === rename.newDigest
144
+ && issue(baseCases.get(rename.oldTestId)) ? 'renamed-existing-candidate' : 'identity-unmeasured';
145
+ if (!baseStatus) return answer('unmeasured', 'baseline testcase identity absent or ambiguous', renameStatus);
146
+ if (baseStatus === 'skipped') return answer('unmeasured', 'baseline testcase skipped', 'identity-unmeasured');
147
+ if (issue(baseStatus) && baseline.rc === 0)
148
+ return answer('unmeasured', 'baseline JUnit failure contradicts exit code', 'identity-unmeasured');
149
+ if (!soloStatus || soloStatus === 'skipped') return answer('unmeasured', 'solo testcase identity absent or skipped', 'identity-unmeasured');
150
+ if (input.environmentProof !== undefined) {
151
+ try {
152
+ const { signature, batchStatusPath, baselineStatusPath } = input.environmentProof;
153
+ if (typeof signature !== 'string' || signature.length < 8 || !batchStatusPath || !baselineStatusPath || baseline.rc === 0)
154
+ return answer('unmeasured', 'Pod infrastructure proof incomplete', 'identity-unmeasured');
155
+ const proofPaths = [batchStatusPath, baselineStatusPath];
156
+ const artifactPaths = [batch.junitPath, batch.resultPath, solo.junitPath, solo.resultPath, baseline.junitPath, baseline.resultPath];
157
+ const allPaths = [...artifactPaths, ...proofPaths];
158
+ if (new Set(allPaths.map((path) => realpathSync(path))).size !== allPaths.length
159
+ || new Set(allPaths.map((path) => { const stat = statSync(path); return `${stat.dev}:${stat.ino}`; })).size !== allPaths.length)
160
+ return answer('unmeasured', 'Pod status artifacts are not independent', 'identity-unmeasured');
161
+ const batchStatus = JSON.parse(read(batchStatusPath)) as Record<string, unknown>;
162
+ const baseStatusProof = JSON.parse(read(baselineStatusPath)) as Record<string, unknown>;
163
+ const valid = (proof: Record<string, unknown>, head: string, runId: string) => proof.kind === 'pod-infrastructure'
164
+ && proof.head40 === head && proof.envKey === input.envKey && proof.signature === signature && proof.runId === runId;
165
+ if (!valid(batchStatus, input.head40, batch.runId) || !valid(baseStatusProof, input.base40, baseline.runId))
166
+ return answer('unmeasured', 'Pod infrastructure proof conflicts with result run IDs', 'identity-unmeasured');
167
+ if (!issue(baseStatus)) return answer('unmeasured', 'Pod infrastructure proof does not explain baseline target', 'identity-unmeasured');
168
+ return answer('environment-failure', 'independent Pod infrastructure status at base and head');
169
+ } catch { return answer('unmeasured', 'Pod infrastructure proof unreadable', 'identity-unmeasured'); }
170
+ }
171
+ if (soloStatus === 'pass' && solo.rc === 0) return answer('interference-candidate', 'batch failed, same-head/env solo passed');
172
+ if (!issue(soloStatus) || solo.rc === 0) return answer('unmeasured', 'solo result missing or inconsistent', 'identity-unmeasured');
173
+ if (issue(baseStatus) && baseline.rc !== 0) return answer('preexisting', 'same stable ID failed at base and head');
174
+ if (baseStatus === 'pass') return answer('introduced', 'same stable ID passed at base and failed in solo head');
175
+ return answer('unmeasured', 'baseline testcase identity absent or ambiguous', renameStatus);
176
+ }
177
+
178
+ export async function gateR2Main(args: string[] = process.argv.slice(2), write: (value: string) => void = console.log): Promise<number> {
179
+ const path = args[0] === '--input' ? args[1] : undefined;
180
+ if (!path || (args.length !== 2 && !(args.length === 3 && args[2] === '--json'))) { write('usage: gate-r2-verdict --input <json-file> --json'); return 2; }
181
+ try {
182
+ const result = classifyGateR2Verdict(JSON.parse(readSmall(path)) as GateR2Input);
183
+ write(JSON.stringify(result));
184
+ return result.verdict === 'unmeasured' ? 3 : 0;
185
+ } catch (error) { write(JSON.stringify({ verdict: 'unmeasured', identityStatus: 'identity-unmeasured', stableTestId: '',
186
+ evidence: { head40: '', base40: '', envKey: '', shards: 0, cohort: [], batchResultPath: '', soloResultPath: '', baselineResultPath: '', reason: String(error) } })); return 3; }
187
+ }
188
+
189
+ if (import.meta.main) process.exitCode = await gateR2Main();
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env bun
2
+ // Shadow node: prepare a same-commit, failed-files-only plan. The gate consumer is a separate TC change.
3
+ import { readFileSync } from 'node:fs';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { planSameCommitRecheck, writeRecheckPlan } from './gate-partial';
8
+
9
+ export interface RecheckInput {
10
+ version: string;
11
+ commit: string;
12
+ measuredCommit: string;
13
+ failures: string[];
14
+ errors: string[];
15
+ ledgerRoot: string;
16
+ }
17
+
18
+ /** Only a Git blob is a runnable test file; `cat-file -e` also accepts trees. */
19
+ export function existsTestFileAtCommit(repo: string, commit: string, file: string): boolean {
20
+ // git-spawn-allow: read-only object type check at the exact measured release commit.
21
+ const found = spawnSync('git', ['cat-file', '-t', `${commit}:${file}`], { cwd: repo, encoding: 'utf8' });
22
+ if (found.error) throw found.error;
23
+ return found.status === 0 && found.stdout.trim() === 'blob';
24
+ }
25
+
26
+ export function prepareGateRecheck(input: RecheckInput, existsAtCommit: (file: string) => boolean):
27
+ { outcome: 'ok'; planPath: string; files: string[]; summary: string } |
28
+ { outcome: 'fail'; planPath: null; files: string[]; summary: string } {
29
+ const fail = (summary: string) => ({ outcome: 'fail' as const, planPath: null, files: [], summary });
30
+ if (!input || typeof input !== 'object' || typeof input.ledgerRoot !== 'string' || !input.ledgerRoot.trim() ||
31
+ !Array.isArray(input.failures) || !input.failures.every((id) => typeof id === 'string') ||
32
+ !Array.isArray(input.errors) || !input.errors.every((id) => typeof id === 'string')) return fail('invalid recheck input');
33
+ const planned = planSameCommitRecheck({ version: input.version, measuredCommit: input.measuredCommit,
34
+ forCommit: input.commit, failures: input.failures, errors: input.errors, existsAtCommit });
35
+ if (!planned.ok) return fail(planned.reason);
36
+ try {
37
+ const planPath = writeRecheckPlan(input.ledgerRoot, planned.plan);
38
+ return { outcome: 'ok', planPath, files: planned.plan.files, summary: `${planned.plan.files.length} failed test files planned on same commit` };
39
+ } catch (error) { return fail(String(error instanceof Error ? error.message : error)); }
40
+ }
41
+
42
+ function main(): void {
43
+ const contextPath = process.env.ELANOUS_GRAPH_CONTEXT;
44
+ if (!contextPath) throw new Error('ELANOUS_GRAPH_CONTEXT required');
45
+ const context = JSON.parse(readFileSync(contextPath, 'utf8')) as { input?: RecheckInput };
46
+ const repo = resolve(import.meta.dir, '../..');
47
+ const input = context.input as RecheckInput;
48
+ const result = prepareGateRecheck(input, (file) => existsTestFileAtCommit(repo, input.commit, file));
49
+ console.log(JSON.stringify(result));
50
+ }
51
+
52
+ if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) main();