elanous 0.2.29 → 0.2.31

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 (709) 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 → LSXfY0u9QtfDbejY0Ukf_}/_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-50625904996a8fa8.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/6948.1062d4594652b5bf.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
  93. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
  94. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
  109. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
  121. package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-a5635eba0d73b84e.js → page-2ebb8fd59b9461f9.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0a07363b130182a1.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-521ee23ac8c0abfa.js} +1 -1
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-9f92737b8766009a.js → page-149dc1caba411bb9.js} +1 -1
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
  175. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
  183. package/apps/pwa/out/_next/static/css/{72becfd42807b50d.css → 3f5fc6f96e2cf7b2.css} +1 -1
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +23 -23
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +23 -23
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +23 -23
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +22 -22
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +22 -22
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +23 -23
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +22 -22
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +23 -23
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +23 -23
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +22 -22
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +23 -23
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +23 -23
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +23 -23
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +23 -23
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +22 -22
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +22 -22
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +23 -23
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +23 -23
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +23 -23
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +22 -22
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +22 -22
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +23 -23
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +23 -23
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +22 -22
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +22 -22
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +22 -22
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +23 -23
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +23 -23
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +22 -22
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +23 -23
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +23 -23
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +23 -23
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +23 -23
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +23 -23
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +22 -22
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +23 -23
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +23 -23
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +23 -23
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +23 -23
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +23 -23
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +23 -23
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +23 -23
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +23 -23
  277. package/bin/elanous.mjs +7 -3
  278. package/graphs/context/nightly-condense.yaml +1 -0
  279. package/graphs/intake/intake-daily.yaml +8 -1
  280. package/graphs/intake/recipes.yaml +5 -0
  281. package/graphs/lecture/lecture-note.yaml +2 -2
  282. package/graphs/ops/harness-gc.yaml +1 -0
  283. package/graphs/release/recipes.yaml +3 -0
  284. package/graphs/release/release-loop.yaml +9 -5
  285. package/graphs/units/recipes.yaml +3 -0
  286. package/graphs/units/release-gate-recheck.yaml +15 -0
  287. package/package.json +2 -1
  288. package/scripts/check-native-tool-wiring.ts +3 -2
  289. package/scripts/ci-android-unit-tests.ts +16 -0
  290. package/scripts/ci-typecheck-changed.ts +37 -9
  291. package/scripts/coord-channel-watch.sh +22 -16
  292. package/scripts/coord-role-pack.ts +81 -2
  293. package/scripts/cron-run.ts +96 -3
  294. package/scripts/detect-test-interference.ts +38 -5
  295. package/scripts/gate-pr-cache.ts +65 -0
  296. package/scripts/gh-surface/capture.ts +126 -0
  297. package/scripts/gh-surface/gh +40 -0
  298. package/scripts/import-graph-scc.ts +38 -0
  299. package/scripts/install.ps1 +19 -0
  300. package/scripts/intake-social.ts +181 -0
  301. package/scripts/lecture-note/node.ts +71 -4
  302. package/scripts/lib/android-toolchain.ts +32 -0
  303. package/scripts/lib/deterministic-env.ts +62 -0
  304. package/scripts/lib/gate-test-env.ts +19 -0
  305. package/scripts/measure-goal-grounding-corpus.ts +2 -1
  306. package/scripts/ratchets/test-interference-patterns.allowlist.txt +257 -0
  307. package/scripts/ratchets/test-interference-patterns.ts +367 -0
  308. package/scripts/release-loop/cut-branch.ts +4 -3
  309. package/scripts/release-loop/export-check-node.ts +0 -1
  310. package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
  311. package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
  312. package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
  313. package/scripts/release-loop/gate-closure.ts +12 -8
  314. package/scripts/release-loop/gate-diff.ts +1 -1
  315. package/scripts/release-loop/gate-host-mirror.ts +66 -0
  316. package/scripts/release-loop/gate-node.ts +523 -75
  317. package/scripts/release-loop/gate-partial.ts +106 -9
  318. package/scripts/release-loop/gate-pr-cache.ts +66 -0
  319. package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
  320. package/scripts/release-loop/gate-r2-verdict.ts +189 -0
  321. package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
  322. package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
  323. package/scripts/release-loop/import-graph-scc-run.ts +54 -0
  324. package/scripts/release-loop/import-graph-scc.ts +215 -0
  325. package/scripts/release-loop/node-verdict.ts +2 -0
  326. package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
  327. package/scripts/release-loop/resume-release.ts +33 -4
  328. package/scripts/release-loop/resume.ts +13 -5
  329. package/scripts/release-loop/spawn-lane.ts +2 -19
  330. package/scripts/release-loop/tui-sim-node.ts +3 -2
  331. package/scripts/release-loop/unattended-release.ts +16 -0
  332. package/scripts/test-deterministic.ts +5 -61
  333. package/scripts/train-reach-grouping.ts +48 -0
  334. package/scripts/tsc-incremental-cache.ts +86 -0
  335. package/scripts/tsc-incremental-diagnostics.ts +76 -0
  336. package/scripts/tsc-main-safety-net.ts +2 -2
  337. package/src/acp/client.ts +4 -1
  338. package/src/acp/core-turn-bridge.ts +50 -5
  339. package/src/ad-pipeline/run.ts +4 -2
  340. package/src/agent/runner.ts +169 -3
  341. package/src/agent/subagent-callable.ts +3 -2
  342. package/src/agent-mission/review-loop.ts +6 -3
  343. package/src/agent-substrate/acp-implementer.ts +14 -2
  344. package/src/agent-substrate/pr-reviewer.ts +12 -0
  345. package/src/agent-substrate/self-review-cli.ts +30 -4
  346. package/src/autopilot/pr-manager.ts +62 -7
  347. package/src/briefing/brief-items.ts +24 -22
  348. package/src/capture/tui-self-report.ts +15 -0
  349. package/src/chat/chat-cli.ts +10 -2
  350. package/src/chat/index.ts +77 -11
  351. package/src/chat/input-control-key.ts +5 -3
  352. package/src/chat/tool-interrupt-behavior.ts +38 -0
  353. package/src/chat/tool-render/dispatch.ts +5 -1
  354. package/src/chat/turn-typeahead.ts +75 -20
  355. package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
  356. package/src/cli/agent-cli.ts +41 -13
  357. package/src/cli/config-audit.ts +123 -0
  358. package/src/cli/decisions-cli.ts +80 -6
  359. package/src/cli/log-event-names.ts +7 -0
  360. package/src/cli/mcp-login.ts +21 -5
  361. package/src/cli/msg-cli.ts +88 -0
  362. package/src/cli/pr-cli.ts +214 -57
  363. package/src/cli/pr-land-heavy-remote.ts +2 -2
  364. package/src/cli/pr-land-overlap-evidence.ts +63 -9
  365. package/src/cli/pr-land-pod-shadow-job.ts +83 -0
  366. package/src/cli/pr-land-pod-shadow.ts +16 -3
  367. package/src/cli/pr-land-virtual-rebase.ts +108 -0
  368. package/src/cli/release-cli.ts +80 -14
  369. package/src/cli/seat-cli.ts +138 -3
  370. package/src/cli/self-update.ts +5 -2
  371. package/src/cli/tasks-cli.ts +97 -19
  372. package/src/context-bus/context-first.ts +13 -0
  373. package/src/context-bus/context-now.ts +13 -2
  374. package/src/context-bus/ops-events.ts +75 -0
  375. package/src/control-plane/lease-holder.ts +12 -8
  376. package/src/control-plane/ledger.ts +163 -4
  377. package/src/control-plane/server.ts +91 -11
  378. package/src/core-turn/run-core-turn.ts +1 -0
  379. package/src/core-turn/run-goal-loop.ts +222 -3
  380. package/src/core-turn/seat-turn-cap.ts +79 -0
  381. package/src/core-turn/short-question.ts +38 -6
  382. package/src/core-turn/types.ts +3 -0
  383. package/src/dashboard/acp-boot.ts +3 -0
  384. package/src/dashboard/index.ts +224 -615
  385. package/src/dashboard/input/chat-main-entry-runtime.ts +1 -1
  386. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
  387. package/src/dashboard/input/chat-main-session.ts +8 -1
  388. package/src/dashboard/input/chat-main-turn.ts +12 -3
  389. package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
  390. package/src/dashboard/input/external-input-host.ts +26 -0
  391. package/src/dashboard/input/internal-turn.ts +261 -0
  392. package/src/dashboard/input/seat-autowake.ts +318 -0
  393. package/src/dashboard/input/turn-steer-bridge.ts +70 -0
  394. package/src/dashboard/loop-scheduler.ts +72 -0
  395. package/src/dashboard/seat-boot-preamble.ts +18 -0
  396. package/src/dashboard/skill-runtime.ts +2 -0
  397. package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
  398. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
  399. package/src/dashboard/slash-runtime/index.ts +13 -0
  400. package/src/dashboard/turn-busy-teardown.ts +50 -0
  401. package/src/decisions/decision-ledger.ts +45 -4
  402. package/src/discord-self-message.ts +4 -4
  403. package/src/domains/release-tool.ts +18 -1
  404. package/src/field-note/transcribe.ts +17 -0
  405. package/src/github/remote-call.ts +81 -0
  406. package/src/goals/registry.ts +46 -6
  407. package/src/goals/types.ts +7 -1
  408. package/src/graph-runner/runner.ts +1 -0
  409. package/src/grok/credential.ts +26 -0
  410. package/src/harness/harness-clean.ts +2 -1
  411. package/src/harness/harness-cli-command.ts +52 -5
  412. package/src/harness/harness-gc.ts +2 -1
  413. package/src/harness/harness-incidents.ts +57 -20
  414. package/src/harness/harness-pod-dispatch.ts +87 -10
  415. package/src/harness/harness-queue.ts +53 -4
  416. package/src/harness/harness-stop.ts +4 -3
  417. package/src/harness/harness-substrate-default.ts +78 -7
  418. package/src/harness/harness-worktree-auto.ts +2 -1
  419. package/src/harness/harness-worktrees.ts +3 -2
  420. package/src/hooks/dispatch.ts +2 -1
  421. package/src/index.ts +152 -25
  422. package/src/input/external-input-queue.ts +33 -1
  423. package/src/intake-plane/slash.ts +14 -3
  424. package/src/keybindings.ts +4 -1
  425. package/src/llm/tool-loop-steered-rejection.ts +33 -0
  426. package/src/llm.ts +138 -19
  427. package/src/loops/consensus.ts +348 -0
  428. package/src/loops/msg-wake.ts +206 -4
  429. package/src/loops/observe.ts +19 -3
  430. package/src/loops/orchestrator/tick.ts +64 -10
  431. package/src/loops/orchestrator/traffic.ts +64 -1
  432. package/src/loops/registry.ts +30 -0
  433. package/src/market/signed-index.ts +14 -0
  434. package/src/mcp/mcp-oauth.ts +54 -5
  435. package/src/models/prompts.ts +28 -0
  436. package/src/msg/msg-sse-client.ts +223 -0
  437. package/src/msg/msg-store.ts +86 -2
  438. package/src/mss/logging/log-store.ts +225 -1
  439. package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
  440. package/src/nexus/api/http-server.ts +54 -15
  441. package/src/nexus/api/loop-resources.ts +19 -3
  442. package/src/nexus/api/ops-api.ts +11 -0
  443. package/src/nexus/daemon-thin-inventory.md +37 -0
  444. package/src/nexus/index.ts +70 -0
  445. package/src/nexus/state/state.ts +1 -0
  446. package/src/oauth/store.ts +32 -7
  447. package/src/onboarding/first-run.ts +28 -3
  448. package/src/ops/overview-cache.ts +16 -4
  449. package/src/ops/resources.ts +82 -0
  450. package/src/plugins/maker/connector-maker.ts +41 -0
  451. package/src/plugins/maker/skill-maker.ts +42 -0
  452. package/src/pr-tool/census.ts +288 -0
  453. package/src/prompt-library/chat-conciseness.ts +13 -0
  454. package/src/prompt-library/universal-preamble.ts +10 -5
  455. package/src/release-loop/gate-host-reservation.ts +97 -0
  456. package/src/release-loop/landing-freeze.ts +5 -0
  457. package/src/release-loop/light-rc.ts +5 -2
  458. package/src/release-loop/placement.ts +92 -1
  459. package/src/release-loop/rehearsal-shard-plan.ts +149 -0
  460. package/src/release-loop/rehearsal.ts +73 -17
  461. package/src/repl/index.ts +20 -2
  462. package/src/seat-loop/seat-knowhow.ts +282 -0
  463. package/src/seat-loop/seat-loop.ts +41 -2
  464. package/src/seat-loop/traffic-signal.ts +3 -0
  465. package/src/self-dev/ask-launch-flow.ts +24 -3
  466. package/src/self-dev/decompose-compose-graph.ts +28 -27
  467. package/src/self-dev/decompose-proposal.ts +53 -38
  468. package/src/self-dev/decompose.ts +17 -0
  469. package/src/self-dev/dev-pipeline.ts +31 -2
  470. package/src/self-dev/draft-residue.ts +24 -9
  471. package/src/self-dev/draft-sweep.ts +59 -4
  472. package/src/self-dev/external-call-zero.ts +77 -0
  473. package/src/self-dev/launch-preflight-text.ts +6 -0
  474. package/src/self-dev/launch-preflight.ts +25 -3
  475. package/src/self-dev/local-supervisor-judge.ts +185 -0
  476. package/src/self-dev/run-supervisor.ts +229 -19
  477. package/src/self-dev/run-types.ts +20 -0
  478. package/src/self-dev/shard-aggregate.ts +13 -2
  479. package/src/self-dev/shard-plan.ts +47 -0
  480. package/src/self-dev/shard-run.ts +112 -10
  481. package/src/self-dev/spawn-lane-files.ts +19 -0
  482. package/src/self-implement/app-api-budget.ts +51 -11
  483. package/src/self-implement/config-gate.ts +2 -1
  484. package/src/self-implement/expose-gate.ts +2 -1
  485. package/src/self-implement/gate-artifacts.ts +405 -0
  486. package/src/self-implement/gate-cli.ts +201 -16
  487. package/src/self-implement/gate-remote.ts +110 -25
  488. package/src/self-implement/gate-scenario.ts +85 -0
  489. package/src/self-implement/goal-author.ts +160 -8
  490. package/src/self-implement/graph-authority.ts +38 -6
  491. package/src/self-implement/graph-overlay-condition.ts +92 -1
  492. package/src/self-implement/heal-triage.ts +79 -0
  493. package/src/self-implement/host-regate.ts +61 -3
  494. package/src/self-implement/orchestrator.ts +14 -123
  495. package/src/self-implement/pr-title.ts +123 -0
  496. package/src/self-implement/run-checkpoint.ts +235 -0
  497. package/src/self-implement/run-ledger.ts +155 -10
  498. package/src/self-implement/run-stop.ts +4 -3
  499. package/src/self-implement/run-ttl.ts +28 -4
  500. package/src/self-implement/seams.ts +2 -0
  501. package/src/self-implement/shadow-stage.ts +7 -6
  502. package/src/self-implement/stop-autoheal.ts +2 -1
  503. package/src/self-implement/train-gate-remote.ts +37 -8
  504. package/src/self-implement/train-reach-grouping.ts +157 -0
  505. package/src/self-implement/train-scenario-layers.ts +133 -0
  506. package/src/self-implement/uncommitted-work.ts +2 -0
  507. package/src/session/pending-input.ts +19 -0
  508. package/src/session/session-start.ts +224 -0
  509. package/src/session-runtime/parallel-dispatch.ts +22 -5
  510. package/src/skills/tools/dev-harness.ts +6 -4
  511. package/src/skills/tools/shell.ts +1 -1
  512. package/src/steward/resync-tick.ts +114 -23
  513. package/src/steward/ta-repair-event-collect.ts +158 -0
  514. package/src/task-agent/card-evidence.ts +25 -1
  515. package/src/task-agent/green-sweep.ts +8 -3
  516. package/src/task-agent/judge.ts +76 -0
  517. package/src/task-agent/land-queue.ts +79 -0
  518. package/src/task-agent/live-moves.ts +30 -9
  519. package/src/task-agent/postland-card.ts +5 -0
  520. package/src/task-agent/prelaunch-already-done.ts +98 -0
  521. package/src/task-agent/real-launch-guard.ts +37 -0
  522. package/src/task-agent/rejudge-on-head.ts +89 -12
  523. package/src/task-agent/remote-rejudge-bind.ts +28 -8
  524. package/src/task-agent/repair-cycle.ts +45 -7
  525. package/src/task-agent/repair-worker.ts +7 -0
  526. package/src/task-agent/run-identity.ts +200 -0
  527. package/src/task-agent/shadow.ts +50 -3
  528. package/src/task-agent/task-hand.ts +158 -5
  529. package/src/task-agent/train-landing.ts +77 -0
  530. package/src/task-agent/work-order.ts +104 -0
  531. package/src/task-orchestrator/surfaces/pod-command-job.ts +88 -28
  532. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
  533. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
  534. package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
  535. package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
  536. package/src/task-orchestrator/surfaces/pod-lease.ts +20 -6
  537. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
  538. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
  539. package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
  540. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +63 -0
  541. package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
  542. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
  543. package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
  544. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
  545. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +208 -0
  546. package/src/task-orchestrator/surfaces/self-implement-pod.ts +132 -15
  547. package/src/telegram.ts +2 -4
  548. package/src/tui/input/pickers.ts +732 -0
  549. package/src/tui/slash/mission.ts +492 -0
  550. package/src/tui/slash/term.ts +877 -0
  551. package/src/tui-client/dashboard-session.ts +9 -0
  552. package/src/tui.ts +48 -0
  553. package/src/user-config/gemini-server-tools.ts +9 -0
  554. package/src/user-config.ts +53 -16
  555. package/src/util/spawn-sync-output.ts +7 -0
  556. package/src/ux-sim/fake-bin.ts +154 -0
  557. package/src/ux-sim/fake-clock.ts +36 -0
  558. package/src/ux-sim/headless-tui.ts +72 -0
  559. package/src/ux-sim/in-process-cli.ts +2 -1
  560. package/src/ux-sim/temp-git-remote.ts +82 -0
  561. package/src/version/packed-revision.json +1 -1
  562. package/src/video-pipeline/recipes/vlog.ts +25 -7
  563. package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
  567. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
  569. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
  572. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
  573. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
  576. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
  578. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
  584. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
  588. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
  599. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
  605. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
  608. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
  609. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
  610. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
  613. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
  615. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
  616. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
  617. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
  619. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
  625. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
  632. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
  635. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
  640. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
  642. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
  703. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
  709. /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
@@ -193,7 +193,7 @@ function rejectedCdResult(): RunShellDispatchResult {
193
193
  // always serve THIS process's instance.
194
194
  const LEDGER_CLI_BIN = /(?:^|[/\\])(?:elanous|elanous\.mjs|elanous\.cjs|eln)$/;
195
195
  const LEDGER_ENV_BIN = /(?:^|[/\\])env$/;
196
- const LEDGER_CLI_NATIVE_TOOL: Readonly<Record<string, string>> = {
196
+ export const LEDGER_CLI_NATIVE_TOOL: Readonly<Record<string, string>> = {
197
197
  'msg list': 'MsgList',
198
198
  'msg post': 'MsgPost',
199
199
  'msg ack': 'MsgAck',
@@ -1,11 +1,12 @@
1
1
  /** Resync labeled PRs before the steward's TA rejudge node sees their heads. */
2
2
  import { debug } from '../debug/log.js';
3
3
  import { spawnSync } from 'node:child_process';
4
- import { mkdirSync, writeFileSync } from 'node:fs';
4
+ import { closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, writeFileSync } from 'node:fs';
5
5
  import { dirname, join } from 'node:path';
6
+ import { dlopen, FFIType } from 'bun:ffi';
6
7
  import { getElanousConfigDir } from '../elanous-config-dir.js';
7
8
  import { resolveHqLaunchSeat } from '../hq/seats.js';
8
- import { effectiveInstanceRoot } from '../instance/resolve.js';
9
+ import { effectiveInstanceRoot, normRoot, releaseLedgerRoot } from '../instance/resolve.js';
9
10
  import { runResyncShadow, type ResyncShadowSummary } from '../loops/orchestrator/resync-shadow.js';
10
11
  import { listSchedules, type ReleaseSchedule } from '../release-loop/release-schedule.js';
11
12
 
@@ -71,6 +72,90 @@ export function defaultResyncRun(
71
72
  execute: typeof runResyncShadow = runResyncShadow,
72
73
  ): Promise<ResyncShadowSummary> { return execute(3, { repoRoot }, 'live'); }
73
74
 
75
+ const LOCK_EX = 2;
76
+ const LOCK_NB = 4;
77
+ const LOCK_UN = 8;
78
+ type FlockFn = (fd: number, op: number) => number;
79
+ let flockFn: FlockFn | undefined;
80
+
81
+ function osFlock(): FlockFn {
82
+ if (flockFn) return flockFn;
83
+ const names = process.platform === 'darwin'
84
+ ? ['/usr/lib/libSystem.B.dylib', 'libc.dylib']
85
+ : ['libc.so.6', `libc.musl-${process.arch === 'arm64' ? 'aarch64' : 'x86_64'}.so.1`];
86
+ let lastError: unknown;
87
+ for (const name of names) {
88
+ try {
89
+ const lib = dlopen(name, { flock: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 } });
90
+ flockFn = (fd, op) => lib.symbols.flock(fd, op) as number;
91
+ return flockFn;
92
+ } catch (error) { lastError = error; }
93
+ }
94
+ throw new Error(`OP seat flock unavailable (${names.join(', ')}): ${String(lastError)}`);
95
+ }
96
+
97
+ /**
98
+ * The one root every OP-seat locker resolves to (steward resync · manual resume · unattended release). It is the
99
+ * release ledger root — an explicit `--config-dir` universe, otherwise machine-wide prod — because the OP seat is
100
+ * machine-wide: a resync from a tree-derived test universe and a release run must still meet on the same lock file.
101
+ * An injected root (tests, a caller that already decided) is used as is. Normalized so `x` and `x/` share one inode.
102
+ */
103
+ export function opSeatLockRoot(explicit?: string): string {
104
+ return normRoot(explicit ?? releaseLedgerRoot());
105
+ }
106
+
107
+ /** Persistent inode for the shared OP-seat kernel flock. Never unlink: a replacement inode would split lockers. */
108
+ export function opSeatFlockPath(root?: string): string {
109
+ return join(opSeatLockRoot(root), 'steward', 'op-seat.flock');
110
+ }
111
+
112
+ export interface OpSeatFlock {
113
+ path: string;
114
+ release(): void;
115
+ }
116
+
117
+ /** Exclusive kernel flock covering OP-seat HEAD, index, and workfile mutation. Released on every exit, including throw. */
118
+ export async function acquireOpSeatFlock(root?: string, waitMs = 120_000): Promise<OpSeatFlock> {
119
+ const path = opSeatFlockPath(root);
120
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
121
+ const flock = osFlock();
122
+ const fd = openSync(path, constants.O_CREAT | constants.O_RDWR | constants.O_NOFOLLOW, 0o600);
123
+ let acquired = false;
124
+ try {
125
+ const stat = fstatSync(fd);
126
+ const current = lstatSync(path);
127
+ if (!stat.isFile() || (stat.mode & 0o077) !== 0 || stat.ino !== current.ino || stat.dev !== current.dev) {
128
+ throw new Error('OP seat flock must be a private regular file (0600)');
129
+ }
130
+ const deadline = Date.now() + waitMs;
131
+ while (flock(fd, LOCK_EX | LOCK_NB) !== 0) {
132
+ if (Date.now() >= deadline) throw new Error(`OP seat flock timed out: ${path}`);
133
+ await Bun.sleep(25);
134
+ }
135
+ acquired = true;
136
+ const locked = lstatSync(path);
137
+ if (stat.ino !== locked.ino || stat.dev !== locked.dev) throw new Error('OP seat flock changed');
138
+ } catch (error) {
139
+ try { if (acquired) flock(fd, LOCK_UN); } finally { closeSync(fd); }
140
+ throw error;
141
+ }
142
+ let released = false;
143
+ return {
144
+ path,
145
+ release() {
146
+ if (released) return;
147
+ released = true;
148
+ try { flock(fd, LOCK_UN); } finally { closeSync(fd); }
149
+ },
150
+ };
151
+ }
152
+
153
+ export async function withOpSeatFlock<T>(action: () => Promise<T> | T, root?: string): Promise<T> {
154
+ const held = await acquireOpSeatFlock(root);
155
+ try { return await action(); }
156
+ finally { held.release(); }
157
+ }
158
+
74
159
  export async function resyncTick(
75
160
  run: () => Promise<ResyncShadowSummary> = () => defaultResyncRun(),
76
161
  log: (event: string, data: Record<string, unknown>) => void = (event, data) => debug.log('loop.steward', event, data),
@@ -84,32 +169,38 @@ export async function resyncTickWithReleaseProbe(
84
169
  releaseProbe: () => ReleaseRunState,
85
170
  windowProbe: () => ReleaseWindowState = releaseWindowState,
86
171
  ): Promise<ResyncTickResult> {
87
- let result: ResyncTickResult;
172
+ // Acquisition failure (unreadable lock file, 120s timeout) is a tick failure: it takes the same
173
+ // `{ decision: 'failed' }` + log path as any other resync error instead of escaping to the caller.
174
+ let held: OpSeatFlock | undefined;
88
175
  try {
89
- const release = releaseProbe();
90
- if (release !== 'idle') {
91
- result = { decision: 'skipped-release', reason: release === 'active' ? 'release run active' : 'release process probe unavailable' };
92
- } else {
93
- const window = windowProbe();
94
- if (window !== 'outside') {
95
- result = { decision: 'skipped-release-window', reason: window === 'inside' ? 'scheduled release window' : 'release schedule unavailable' };
176
+ let result: ResyncTickResult;
177
+ try {
178
+ held = await acquireOpSeatFlock();
179
+ const release = releaseProbe();
180
+ if (release !== 'idle') {
181
+ result = { decision: 'skipped-release', reason: release === 'active' ? 'release run active' : 'release process probe unavailable' };
96
182
  } else {
97
- const summary = await run();
98
- if (summary.saved > 0) {
99
- mkdirSync(dirname(pendingPath), { recursive: true });
100
- writeFileSync(pendingPath, JSON.stringify({ savedAt: new Date().toISOString() }));
183
+ const window = windowProbe();
184
+ if (window !== 'outside') {
185
+ result = { decision: 'skipped-release-window', reason: window === 'inside' ? 'scheduled release window' : 'release schedule unavailable' };
186
+ } else {
187
+ const summary = await run();
188
+ if (summary.saved > 0) {
189
+ mkdirSync(dirname(pendingPath), { recursive: true });
190
+ writeFileSync(pendingPath, JSON.stringify({ savedAt: new Date().toISOString() }));
191
+ }
192
+ result = { decision: 'ran', summary };
101
193
  }
102
- result = { decision: 'ran', summary };
103
194
  }
104
195
  }
105
- }
106
- catch (error) { result = { decision: 'failed', reason: (error instanceof Error ? error.message : String(error)).slice(-300) }; }
107
- try { log('resync-tick', { ...result }); }
108
- catch (error) {
109
- result = { decision: 'failed', reason: `log failed: ${error instanceof Error ? error.message : String(error)}`.slice(-300) };
110
- console.error(`steward resync: ${result.reason}`);
111
- }
112
- return result;
196
+ catch (error) { result = { decision: 'failed', reason: (error instanceof Error ? error.message : String(error)).slice(-300) }; }
197
+ try { log('resync-tick', { ...result }); }
198
+ catch (error) {
199
+ result = { decision: 'failed', reason: `log failed: ${error instanceof Error ? error.message : String(error)}`.slice(-300) };
200
+ console.error(`steward resync: ${result.reason}`);
201
+ }
202
+ return result;
203
+ } finally { held?.release(); }
113
204
  }
114
205
 
115
206
  if (import.meta.main) {
@@ -0,0 +1,158 @@
1
+ /** Immediate TA repair collection. The card and atomic worker result remain authoritative. */
2
+ import { mkdirSync, readFileSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { debug } from '../debug/log.js';
5
+ import { spawnElanous } from '../instance/spawn-elanous.js';
6
+ import { acquireLockSync } from '../storage/file-lock.js';
7
+ import { subscribeInsideEvent, type InsideLiveEvent } from '../nexus/api/inside-events.js';
8
+ import type { NexusEventBus } from '../nexus/api/event-bus.js';
9
+ import { parseRepairWorkerResult } from '../task-agent/repair-worker.js';
10
+ import { readTaskCard, taskAgentStatePath } from '../task-agent/task-hand.js';
11
+
12
+ const SHA40 = /^[0-9a-f]{40}$/i;
13
+ const CARD = /^ta-[a-z0-9-]{1,80}$/;
14
+ const TIMEOUT_MS = 10 * 60_000;
15
+ const OUTPUT_LIMIT = 1024 * 1024;
16
+
17
+ export interface TaRepairCompleted {
18
+ kind: 'ta.repair.completed'; schema: 1; card: string; pr: number; head: string;
19
+ runId: string; resultPath: string; completedAt: string;
20
+ }
21
+
22
+ export function parseTaRepairCompleted(value: unknown): TaRepairCompleted | null {
23
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
24
+ const v = value as Record<string, unknown>;
25
+ if (v.kind !== 'ta.repair.completed' || v.schema !== 1 || typeof v.card !== 'string' || !CARD.test(v.card)
26
+ || !Number.isSafeInteger(v.pr) || Number(v.pr) < 1 || typeof v.head !== 'string' || !SHA40.test(v.head)
27
+ || typeof v.runId !== 'string' || !/^run-[a-z0-9-]{1,100}$/i.test(v.runId)
28
+ || typeof v.resultPath !== 'string' || !v.resultPath.startsWith('/')
29
+ || typeof v.completedAt !== 'string' || !Number.isFinite(Date.parse(v.completedAt))) return null;
30
+ return v as unknown as TaRepairCompleted;
31
+ }
32
+
33
+ export interface TaRepairCollectDeps {
34
+ statePath?: string;
35
+ /** Test entry for a child that runs the real tasks CLI with isolated dependencies. */
36
+ cliBin?: string;
37
+ read?: (path: string) => string;
38
+ run?: (card: string) => Promise<{ code: number | null; output: string; truncated?: boolean }>;
39
+ now?: () => Date;
40
+ log?: (data: Record<string, unknown>) => void;
41
+ }
42
+
43
+ function defaultRun(card: string, statePath: string, cliBin?: string): Promise<{ code: number | null; output: string; truncated?: boolean }> {
44
+ return new Promise(done => {
45
+ const child = spawnElanous(['tasks', 'rejudge', card, '--json'], { stateDir: dirname(statePath),
46
+ ...(cliBin ? { bin: cliBin } : {}), stdio: ['ignore', 'pipe', 'pipe'] });
47
+ let output = '';
48
+ let truncated = false;
49
+ let settled = false;
50
+ let force: ReturnType<typeof setTimeout> | undefined;
51
+ const finish = (code: number | null) => {
52
+ if (settled) return;
53
+ settled = true;
54
+ clearTimeout(timer);
55
+ if (force) clearTimeout(force);
56
+ done({ code, output, truncated });
57
+ };
58
+ const timer = setTimeout(() => {
59
+ child.kill('SIGTERM');
60
+ // Keep the card lock until close confirms the child has stopped writing the card.
61
+ force = setTimeout(() => { child.kill('SIGKILL'); }, 5000);
62
+ }, TIMEOUT_MS);
63
+ const append = (chunk: unknown) => {
64
+ const next = output + String(chunk);
65
+ if (next.length > OUTPUT_LIMIT) { truncated = true; output = next.slice(-OUTPUT_LIMIT); }
66
+ else output = next;
67
+ };
68
+ child.stdout?.on('data', append);
69
+ child.stderr?.on('data', append);
70
+ // Node emits close after error, including spawn failure. An error can also
71
+ // describe a failed kill while the child is still alive: keep the lock.
72
+ child.once('error', (error) => { append(`\nchild error: ${String(error)}`); });
73
+ child.once('close', finish);
74
+ });
75
+ }
76
+
77
+ function childConsumedRepair(output: string, event: TaRepairCompleted): boolean {
78
+ for (const line of output.split(/\r?\n/).reverse()) {
79
+ if (!line.trimStart().startsWith('[')) continue;
80
+ try {
81
+ const rows: unknown = JSON.parse(line);
82
+ if (Array.isArray(rows) && rows.some(row => row && typeof row === 'object' && row.card === event.card
83
+ && row.pr === event.pr && row.repairRunId === event.runId && row.repairHead === event.head
84
+ && row.step === 'repair' && (row.decision === 'repair-applied' || row.decision === 'repair-failed'))) return true;
85
+ } catch { /* not a JSON result line */ }
86
+ }
87
+ return false;
88
+ }
89
+
90
+ /** One event may start one card rejudge. A periodic rejudge can race; its existing card CAS still owns side effects. */
91
+ export async function collectTaRepairCompleted(input: unknown, deps: TaRepairCollectDeps = {}): Promise<'invalid' | 'duplicate' | 'deferred' | 'collected'> {
92
+ const event = parseTaRepairCompleted(input);
93
+ if (!event) return 'invalid';
94
+ const statePath = deps.statePath ?? taskAgentStatePath();
95
+ const emit = (outcome: string, extra: Record<string, unknown> = {}) => {
96
+ const collectedAt = (deps.now?.() ?? new Date()).toISOString();
97
+ const data = { card: event.card, pr: event.pr, runId: event.runId, completedAt: event.completedAt,
98
+ collectedAt, ...(outcome === 'collected' ? { latencyMs: Date.parse(collectedAt) - Date.parse(event.completedAt) } : {}),
99
+ delivery: 'event', outcome, ...extra };
100
+ try { (deps.log ?? ((d) => debug.log('task-agent', 'ta.repair.collected', d)))(data); } catch { /* observability cannot change the result */ }
101
+ };
102
+ let card;
103
+ try { card = readTaskCard(event.card, statePath); } catch { emit('deferred', { reason: 'card unreadable' }); return 'deferred'; }
104
+ const repair = Array.isArray(card?.repairs) ? card.repairs.find(entry => entry && typeof entry === 'object' && entry.runId === event.runId) : undefined;
105
+ if (!repair || repair.pr !== event.pr || typeof repair.head !== 'string' || repair.head.toLowerCase() !== event.head.toLowerCase()
106
+ || typeof repair.resultPath !== 'string' || !repair.resultPath.startsWith('/')
107
+ || resolve(repair.resultPath) !== resolve(event.resultPath)) { emit('invalid', { reason: 'event differs from card binding' }); return 'invalid'; }
108
+ if (repair.status !== 'requested') { emit('duplicate', { reason: `repair ${repair.status}` }); return 'duplicate'; }
109
+ let result;
110
+ try { result = parseRepairWorkerResult((deps.read ?? ((path) => readFileSync(path, 'utf8')))(repair.resultPath), event.pr, event.head, event.runId); }
111
+ catch { /* periodic tick can recover a missing result */ }
112
+ if (!result) { emit('deferred', { reason: 'worker result missing or invalid' }); return 'deferred'; }
113
+
114
+ // Existing PID-aware lock recovers a dead daemon without making later events wait forever.
115
+ // A live holder keeps the lock through the child process; the card CAS covers periodic-tick races.
116
+ const lock = join(dirname(statePath), 'steward', 'ta-repair-collect', `${event.card}.lock`);
117
+ let release: () => void;
118
+ try {
119
+ mkdirSync(dirname(lock), { recursive: true });
120
+ release = acquireLockSync(lock, { breakDeadHolder: true, staleMs: TIMEOUT_MS + 60_000, maxTries: 2 });
121
+ }
122
+ catch { emit('deferred', { reason: 'collector busy; periodic fallback remains' }); return 'deferred'; }
123
+ try {
124
+ // Recheck after claiming: another collector or the periodic tick may have consumed the file.
125
+ const current = readTaskCard(event.card, statePath);
126
+ const latest = Array.isArray(current?.repairs) ? current.repairs.find(entry => entry && typeof entry === 'object' && entry.runId === event.runId) : undefined;
127
+ if (!latest || latest.status !== 'requested' || latest.pr !== event.pr || typeof latest.head !== 'string'
128
+ || latest.head.toLowerCase() !== event.head.toLowerCase() || typeof latest.resultPath !== 'string'
129
+ || !latest.resultPath.startsWith('/') || resolve(latest.resultPath) !== resolve(event.resultPath)) { emit('duplicate'); return 'duplicate'; }
130
+ const child = await (deps.run ?? ((card) => defaultRun(card, statePath, deps.cliBin)))(event.card);
131
+ const after = readTaskCard(event.card, statePath)?.repairs?.find(entry => entry.runId === event.runId);
132
+ const consumed = child.code === 0 && !child.truncated && after?.status !== 'requested' && after !== undefined
133
+ && childConsumedRepair(child.output, event);
134
+ const outcome = consumed ? 'collected' : child.truncated ? 'deferred' : after && after.status !== 'requested' ? 'duplicate' : 'deferred';
135
+ emit(outcome, { rc: child.code, repairStatus: after?.status,
136
+ ...(child.truncated ? { reason: 'rejudge output exceeded 1 MiB; event attribution unmeasured' } : {}),
137
+ detail: child.output.slice(-300) });
138
+ return consumed ? 'collected' : outcome === 'duplicate' ? 'duplicate' : 'deferred';
139
+ } catch (error) {
140
+ emit('deferred', { reason: String(error).slice(-300) });
141
+ return 'deferred';
142
+ } finally { release(); }
143
+ }
144
+
145
+ /** Bridge child-process inside events to Nexus pub/sub; keep the handler nonblocking. */
146
+ export function startTaRepairEventCollector(bus: NexusEventBus, deps: TaRepairCollectDeps = {}): () => void {
147
+ const unsubscribeBus = bus.subscribe(event => {
148
+ void collectTaRepairCompleted(event.detail, deps).catch(error => {
149
+ try { debug.log('task-agent', 'ta.repair.collect-error', { reason: String(error).slice(-300) }, { level: 'warn' }); }
150
+ catch { /* observer failure cannot reject the Nexus callback */ }
151
+ });
152
+ }, ['ta.repair.completed']);
153
+ const unsubscribeInside = subscribeInsideEvent((event: InsideLiveEvent) => {
154
+ if (event.kind !== 'ta.repair.completed') return;
155
+ bus.publish({ kind: 'ta.repair.completed', ts: Date.now(), detail: event as unknown as Record<string, unknown> });
156
+ });
157
+ return () => { unsubscribeInside(); unsubscribeBus(); };
158
+ }
@@ -76,7 +76,27 @@ export function podChildRunIds(host: readonly RunLedgerEntry[] | null, runId?: s
76
76
  && RUN_ID.test(entry.data.childRunId) && entry.data.childRunId !== runId).map((entry) => entry.data.childRunId as string))];
77
77
  }
78
78
 
79
- /** 순수 — 카드 런의 골 id · PR. PR 은 호스트 → 자식(나중 자식 먼저) → job-finished 순으로 처음 찾은 것. */
79
+ /**
80
+ * TA-BIND-PR-TERMINAL — 부모(호스트) 원장의 `pr-terminal{childRunId, prNumber, prUrl}`(draft-residue `applyPodTerminal`).
81
+ * gate-failed draft 자식은 `pr-opened` 없이 `rework-blocked-draft-pr`·`pr.comment.mode` 만 남겨서, PR 근거는 부모의 이 줄뿐이다.
82
+ * 자식은 부모의 `pod-child-run` 자식이어야 하고, url 은 같은 번호의 PR 주소여야 한다. 나중 줄이 먼저다.
83
+ */
84
+ export function podTerminalPr(host: readonly RunLedgerEntry[] | null, childRunIds: readonly string[]): { number: number; url: string; childRunId: string } | undefined {
85
+ const children = new Set(childRunIds);
86
+ for (let at = (host?.length ?? 0) - 1; at >= 0; at--) {
87
+ const entry = host![at]!;
88
+ if (entry.event !== 'pr-terminal') continue;
89
+ const childRunId = entry.data?.childRunId;
90
+ const number = entry.data?.prNumber;
91
+ const url = entry.data?.prUrl;
92
+ if (typeof childRunId !== 'string' || !children.has(childRunId) || !Number.isSafeInteger(number) || (number as number) <= 0
93
+ || typeof url !== 'string' || PR_URL.exec(url)?.[1] !== String(number)) continue;
94
+ return { number: number as number, url, childRunId };
95
+ }
96
+ return undefined;
97
+ }
98
+
99
+ /** 순수 — 카드 런의 골 id · PR. PR 은 호스트 → 자식(나중 자식 먼저) → 호스트 `pr-terminal` → job-finished 순으로 처음 찾은 것. */
80
100
  export function bindCardEvidence(card: Pick<TaskCard, 'runId'>, snapshot: CardRunSnapshot): CardRunEvidence {
81
101
  if (!card.runId || !snapshot.host) return { ledgerFound: false };
82
102
  const children = podChildRunIds(snapshot.host, card.runId).reverse();
@@ -88,6 +108,10 @@ export function bindCardEvidence(card: Pick<TaskCard, 'runId'>, snapshot: CardRu
88
108
  const found = entries ? lastPr(entries) : undefined;
89
109
  if (found) { pr = found; childRunId = id; }
90
110
  }
111
+ if (!pr) {
112
+ const terminal = podTerminalPr(snapshot.host, children);
113
+ if (terminal) { pr = { number: terminal.number, url: terminal.url }; childRunId = terminal.childRunId; }
114
+ }
91
115
  for (const id of children) {
92
116
  if (pr) break;
93
117
  const finish = [...(snapshot.podFinishes ?? [])].reverse().find((row) => row.childRunId === id && PR_URL.test(row.prUrl));
@@ -19,6 +19,7 @@ export interface GreenSweepPr {
19
19
  state: string;
20
20
  mergeSha?: string;
21
21
  url?: string;
22
+ viaTrain?: { integrationPr: number };
22
23
  }
23
24
  export interface GreenSweepDecision {
24
25
  cell: string;
@@ -112,7 +113,8 @@ export function decideGreenSweep(input: {
112
113
  const { item, candidate, pr } = input;
113
114
  const mergeSha = pr?.mergeSha && /^[a-f0-9]{40}$/i.test(pr.mergeSha) ? pr.mergeSha : null;
114
115
  const result = (verdict: GreenSweepVerdict, reason: string): GreenSweepDecision => {
115
- const evidence = `GREEN-FROM-LEDGER: PR #${candidate.pr}${mergeSha ? ` merged ${mergeSha}` : ''} · ${verdict} · ${reason}`;
116
+ const landing = pr?.viaTrain ? ` via train #${pr.viaTrain.integrationPr}` : '';
117
+ const evidence = `GREEN-FROM-LEDGER: PR #${candidate.pr}${landing}${mergeSha ? ` merged ${mergeSha}` : ''} · ${verdict} · ${reason}`;
116
118
  return { cell: item.id, pr: candidate.pr, mergeSha, source: candidate.source, verdict, reason,
117
119
  evidence, existingEvidence: item.evidence ?? '', plannedEvidence: appendGreenSweepEvidence(item.evidence, evidence) };
118
120
  };
@@ -122,6 +124,9 @@ export function decideGreenSweep(input: {
122
124
  if (input.repositoryMatches === false) return result('skip', 'repository-mismatch');
123
125
  if (input.repositoryMatches !== true) return result('record-only', 'repository-unreadable');
124
126
  if (pr.state !== 'MERGED') return result('skip', `pr-${pr.state.toLowerCase()}`);
127
+ if (pr.viaTrain && (candidate.card?.trainLanding?.componentPr !== candidate.pr
128
+ || candidate.card.trainLanding.integrationPr !== pr.viaTrain.integrationPr
129
+ || candidate.card.trainLanding.mergeSha !== pr.mergeSha)) return result('skip', 'train-binding-mismatch');
125
130
  if (!mergeSha) return result('skip', 'merge-sha-unreadable');
126
131
  if (input.ancestor === null) return result('record-only', 'origin-main-ref-unverified');
127
132
  if (!input.ancestor) return result('skip', 'merge-sha-not-on-origin-main');
@@ -159,8 +164,8 @@ export function decideGreenSweep(input: {
159
164
  if (typeof card.pr === 'object' && pr.url && card.pr.url
160
165
  && card.pr.url.replace(/\/+$/, '') !== pr.url.replace(/\/+$/, ''))
161
166
  return result('record-only', 'card-pr-url-mismatch');
162
- if (card.prTerminal?.state === 'CLOSED') return result('record-only', 'card-terminal-conflict');
163
- return result('green', card.postLand?.outcome === 'complete' ? 'bound-card-complete' : 'bound-card-merged');
167
+ if (card.prTerminal?.state === 'CLOSED' && !pr.viaTrain) return result('record-only', 'card-terminal-conflict');
168
+ return result('green', card.postLand?.outcome === 'complete' ? 'bound-card-complete' : pr.viaTrain ? 'bound-card-train-merged' : 'bound-card-merged');
164
169
  }
165
170
 
166
171
  /** Every candidate emits one structured decision, including refusals. */
@@ -24,6 +24,8 @@ export interface TaskJudgeInput {
24
24
  stopReason?: SupervisorStopReason;
25
25
  prState?: 'OPEN' | 'MERGED' | 'CLOSED';
26
26
  pr?: string | number;
27
+ /** Complete PR target paths when measured. Unknown is omitted, never treated as zero code diff. */
28
+ prTargetPaths?: readonly string[];
27
29
  /** `self review --json` 판정. 관측 못 했으면 비운다(«통과»로 읽지 않는다). */
28
30
  review?: 'pass' | 'fail';
29
31
  mustFix?: readonly string[];
@@ -36,6 +38,42 @@ export interface TaskJudgeInput {
36
38
  evidence?: { ok: boolean; ref: string };
37
39
  /** Only classified terminal evidence; an absent input preserves the existing stop-reason table. */
38
40
  terminalRun?: { kind: typeof STOP_CLASS_POD_FAILURE | typeof STOP_CLASS_NO_LAUNCH; reason: string; hasPr: boolean; hasHarvestBranch: boolean };
41
+ /**
42
+ * 같은 칸(checklistId)의 앞 런들 — 재발사 계열 수를 고르기 «전»에 받는 «선례»(RFC adaptive-graph-ops §9.10).
43
+ * 없으면 지금 표 그대로(입력이 비어도 동작한다 — RUN-TAG-REWORK 가 원장에 서명을 달면 여기 입력이 된다).
44
+ */
45
+ precedents?: readonly TaskPrecedent[];
46
+ /** 판정 관측 훅 — `task-agent.judge` 이벤트에 precedent {matched, priorRunId, signature} 를 싣는다. 없으면 관측 없이 종전 동작. */
47
+ observe?: (event: 'task-agent.judge', data: { precedent: { matched: boolean; priorRunId?: string; signature?: string } }) => void;
48
+ }
49
+
50
+ /** 같은 칸의 앞 런 한 건 — 결말(outcome)과 must-fix 서명. `outcome: 'alternative-failed'` 는 «대안도 같은 서명으로 실패했다»는 예약 결말이다. */
51
+ export interface TaskPrecedent {
52
+ runId: string;
53
+ outcome: string;
54
+ signature: string;
55
+ }
56
+
57
+ /** must-fix 서명의 분류 축(남은 must-fix 의 성격) — 해시에 함께 박는다. */
58
+ export const MUST_FIX_CLASSIFICATION = 'implementation-deficit';
59
+
60
+ /**
61
+ * 남은 must-fix 원문을 정규화(공백 접기·trim·정렬)한 해시 ⊕ 분류 — 같은 칸의 앞 런과 비교하는 «서명».
62
+ * must-fix 가 비면 서명도 없다(선례 비교 없음).
63
+ */
64
+ export function mustFixSignature(mustFix?: readonly string[]): string | undefined {
65
+ const normalized = [...(mustFix ?? [])]
66
+ .map(fix => (typeof fix === 'string' ? fix.trim().replace(/\s+/gu, ' ') : ''))
67
+ .filter(Boolean)
68
+ .sort();
69
+ if (!normalized.length) return undefined;
70
+ let hash = 0x811c9dc5;
71
+ const text = `${MUST_FIX_CLASSIFICATION}:${JSON.stringify(normalized)}`;
72
+ for (let i = 0; i < text.length; i++) {
73
+ hash ^= text.charCodeAt(i);
74
+ hash = Math.imul(hash, 0x01000193) >>> 0;
75
+ }
76
+ return `fnv1a-${hash.toString(16).padStart(8, '0')}`;
39
77
  }
40
78
 
41
79
  export interface TaskJudgement {
@@ -83,12 +121,22 @@ const RETRY_MOVE_OF_VARIANT: Record<RetryVariant, LiveRetryMove> = {
83
121
  alternative: 'alternative',
84
122
  };
85
123
 
124
+ /** Only a measured complete file list can establish zero implementation target diff. */
125
+ export function isGoalOnlyPr(paths: readonly string[] | undefined): boolean {
126
+ return paths !== undefined && paths.every((path) => /^docs\/goals\/[^/]+(?:\/.*)?$/.test(path));
127
+ }
128
+
86
129
  /** 실행부 `retry` 가 어느 수인가 — 갈래 없는 재발사(리뷰 fail 의 must-fix 재발사)는 «좁혀 재발사»다. */
87
130
  export function retryMoveOf(variant?: RetryVariant): LiveRetryMove {
88
131
  return RETRY_MOVE_OF_VARIANT[variant ?? 'narrow'];
89
132
  }
90
133
 
91
134
  function base(input: TaskJudgeInput): Omit<TaskJudgement, 'executorKind'> {
135
+ // A goal document is a launch artifact. Its PR cannot prove implementation progress,
136
+ // even when the PR has merged. Waiting also prevents the same goal's live retry.
137
+ if (input.pr && isGoalOnlyPr(input.prTargetPaths)) {
138
+ return { move: 'wait', stage: 'escalated', reason: `goal-only-pr — PR ${input.pr} target diff 0; 같은 골 재큐 중지·구현 근거 필요` };
139
+ }
92
140
  if (input.deliveryEvidence) return input.deliveryEvidence.ok
93
141
  ? { move: 'propose-green', stage: 'closing', reason: `전달 근거 확인: ${input.deliveryEvidence.files.join(', ')}` }
94
142
  : { move: 'wait', stage: 'waiting', reason: input.deliveryEvidence.reason };
@@ -139,16 +187,34 @@ function base(input: TaskJudgeInput): Omit<TaskJudgement, 'executorKind'> {
139
187
  /** 재발사 계열 — 대안(alternative)이 실패한 «같은 실패 흐름»에 속하는 수. */
140
188
  const RETRY_FAMILY: ReadonlySet<TaskMove> = new Set<TaskMove>(['narrow-relaunch', 'wait-retry', 'salvage-relaunch']);
141
189
 
190
+ /**
191
+ * 선례가 «같은 수로 재발사»를 막는 수 — narrow·salvage·그 자신(alternative).
192
+ * 대기 후 재시도(wait-retry)는 «같은 수로 재발사»가 아니므로 선례 승격에서는 제외.
193
+ */
194
+ const PRECEDENT_RELAUNCH_FAMILY: ReadonlySet<TaskMove> = new Set<TaskMove>(['narrow-relaunch', 'salvage-relaunch']);
195
+
142
196
  /**
143
197
  * 종료 어휘·관측에서 다음 한 수를 고른다. 같은 수 2회 실패 → 다른 수 → 그것도 실패 → 결정 카드.
144
198
  *
145
199
  * ⭐ 새 관측이 이긴다(사후 리뷰 must-fix · #24453): 병합된 PR(propose-green)·종료 미관측(wait)·표 밖 어휘(decision-card)는
146
200
  * 실패 셈과 무관하게 그대로 간다. 「대안도 실패 → 결정 카드」 승격은 지금 수가 같은 실패 흐름일 때만 —
147
201
  * 재발사 계열이거나, 그 수 자신이 이미 같은 수 한도만큼 실패했을 때다.
202
+ *
203
+ * ⭐ 선례(RFC adaptive-graph-ops §9.10): 이번 런의 must-fix 서명이 앞 런 서명과 같으면 같은 수로 재발사하지 않는다 —
204
+ * narrow/salvage → alternative, alternative 자신(또는 선례 결말이 `alternative-failed`)이면 결정 카드.
205
+ * 선례가 없으면 지금 표 그대로.
148
206
  */
149
207
  export function judgeNextMove(input: TaskJudgeInput): TaskJudgement {
150
208
  const failures = input.failures ?? {};
151
209
  let judged = base(input);
210
+ const signature = mustFixSignature(input.mustFix);
211
+ // 같은 서명 일치 «전체»를 스캔한다 — `alternative-failed` 유무는 목록 어느 위치에 있든 먼저 판정한다(anyMatch 우선, 순서 무관).
212
+ const sameSignature = signature !== undefined
213
+ ? (input.precedents ?? []).filter(prec => typeof prec?.signature === 'string' && prec.signature === signature
214
+ && typeof prec?.runId === 'string' && prec.runId !== '')
215
+ : [];
216
+ const matched = sameSignature[0];
217
+ input.observe?.('task-agent.judge', { precedent: { matched: matched !== undefined, priorRunId: matched?.runId, signature } });
152
218
  const escalatable = judged.move !== 'wait' && judged.move !== 'decision-card' && judged.move !== 'propose-green';
153
219
  const exhausted = escalatable && (failures[judged.move] ?? 0) >= SAME_MOVE_FAILURE_LIMIT;
154
220
  const inFailingFlow = RETRY_FAMILY.has(judged.move) || exhausted;
@@ -157,6 +223,16 @@ export function judgeNextMove(input: TaskJudgeInput): TaskJudgement {
157
223
  } else if (exhausted) {
158
224
  judged = { move: 'alternative', stage: 'repairing', reason: `같은 수 ${SAME_MOVE_FAILURE_LIMIT}회 실패 — 다른 수 선택 (${judged.move})` };
159
225
  }
226
+ // 선례 승격 — 실패 승격 다음: 이번 수가 같은 서명 앞 런의 수와 겹치지 않게 한다(같은 수로 재발사 차단).
227
+ if (matched !== undefined && (PRECEDENT_RELAUNCH_FAMILY.has(judged.move) || judged.move === 'alternative')) {
228
+ if (judged.move === 'alternative' || sameSignature.some(prec => prec.outcome === 'alternative-failed')) {
229
+ judged = { move: 'decision-card', stage: 'escalated',
230
+ reason: `같은 must-fix 서명 선례 ${matched.runId} — 대안도 같은 서명으로 실패 — 사람 결정 (서명 ${signature})` };
231
+ } else {
232
+ judged = { move: 'alternative', stage: 'repairing',
233
+ reason: `같은 must-fix 서명 선례 ${matched.runId} — 같은 수로 재발사하지 않고 다른 수 선택 (서명 ${signature})` };
234
+ }
235
+ }
160
236
  const executorKind = EXECUTOR_KIND[judged.move];
161
237
  const executorVariant = EXECUTOR_VARIANT[judged.move];
162
238
  if (!executorKind) return judged;
@@ -0,0 +1,79 @@
1
+ /** TA-LAND-AFTER-REVIEW: a configured queue adapter after exact-head review and remote changed gate. */
2
+ import { spawn } from 'node:child_process';
3
+ import { mkdirSync, readFileSync } from 'node:fs';
4
+ import { dirname, isAbsolute, join } from 'node:path';
5
+ import { randomUUID } from 'node:crypto';
6
+ import { parseReviewResultOutput } from './review-result-capture.js';
7
+
8
+ type CommandResult = { status: number; stdout: string; stderr: string };
9
+ export interface QueueLandingInput {
10
+ card: string; pr: number; head: string; cwd: string; statePath: string; reviewResult: string;
11
+ command: string; remote: string; entry: string; configDir: string;
12
+ }
13
+ export interface QueueLandingDeps {
14
+ run?: (command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv) => Promise<CommandResult>;
15
+ read?: (path: string) => string;
16
+ }
17
+
18
+ async function run(command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): Promise<CommandResult> {
19
+ return new Promise((resolve, reject) => {
20
+ const child = spawn(command, args, { cwd, env: env ?? process.env, stdio: ['ignore', 'pipe', 'pipe'] });
21
+ let stdout = ''; let stderr = '';
22
+ child.stdout.on('data', (chunk: Buffer) => { stdout = (stdout + chunk.toString()).slice(-4000); });
23
+ child.stderr.on('data', (chunk: Buffer) => { stderr = (stderr + chunk.toString()).slice(-4000); });
24
+ child.once('error', reject);
25
+ child.once('close', (code) => resolve({ status: code ?? 1, stdout, stderr }));
26
+ });
27
+ }
28
+
29
+ /** The adapter owns no merge authority. Its only successful result is a confirmed queue row. */
30
+ export async function runQueuedLanding(input: QueueLandingInput, deps: QueueLandingDeps = {}): Promise<CommandResult> {
31
+ const invoke = deps.run ?? run;
32
+ const read = deps.read ?? ((path: string) => readFileSync(path, 'utf8'));
33
+ const fail = (stage: string, reason: string): CommandResult => ({ status: 1, stdout: '', stderr: `${stage}: ${reason.slice(-500)}` });
34
+ if (!/^[a-f0-9]{40}$/i.test(input.head) || !Number.isSafeInteger(input.pr) || input.pr < 1) return fail('input', 'invalid PR/head');
35
+ if (!isAbsolute(input.command) || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(input.remote)) return fail('config', 'land queue command/remote invalid');
36
+ let review: ReturnType<typeof parseReviewResultOutput>;
37
+ try { review = parseReviewResultOutput(read(input.reviewResult)); }
38
+ catch (error) { return fail('review', String(error)); }
39
+ if (!review || review.pr !== input.pr || review.head?.toLowerCase() !== input.head.toLowerCase()
40
+ || review.reviewed !== true || !['pass', 'warn'].includes(review.verdict ?? '') || review.mustFix !== 0 || review.error) {
41
+ return fail('review', `exact head #${input.pr} ${input.head.slice(0, 12)} PASS/WARN mf0 not proven`);
42
+ }
43
+ const git = async (args: string[]) => invoke(process.execPath, [input.entry, '--config-dir', input.configDir, 'git', ...args], input.cwd);
44
+ const fetched = await git(['fetch', '--quiet', 'origin', 'main']);
45
+ if (fetched.status !== 0) return fail('base-fetch', fetched.stderr || fetched.stdout || `exit ${fetched.status}`);
46
+ const base = await git(['rev-parse', '--verify', 'origin/main']);
47
+ const baseHead = base.stdout.trim().split(/\s+/)[0];
48
+ if (base.status !== 0 || !/^[a-f0-9]{40}$/i.test(baseHead ?? '')) return fail('base', 'origin/main commit unmeasured');
49
+ const local = await git(['rev-parse', '--verify', 'HEAD']);
50
+ if (local.status !== 0 || local.stdout.trim().split(/\s+/)[0]?.toLowerCase() !== input.head.toLowerCase()) return fail('head', 'queue worktree HEAD differs from PR head');
51
+ const safeCard = input.card.replace(/[^A-Za-z0-9._-]/g, '_');
52
+ const artifact = join(dirname(input.statePath), 'land-queue-gates', `${safeCard}-${input.pr}-${input.head.slice(0, 12)}-${randomUUID()}`);
53
+ mkdirSync(artifact, { recursive: true });
54
+ const gate = await invoke(process.execPath, [input.entry, '--config-dir', input.configDir,
55
+ 'self', 'gate', '--changed', '--base', baseHead!, '--remote', input.remote, '--shards', '4', '--artifact-dir', artifact], input.cwd);
56
+ if (gate.status !== 0) return fail('remote-changed-gate', gate.stderr || gate.stdout || `exit ${gate.status}`);
57
+ let summary: Record<string, unknown>;
58
+ try { summary = JSON.parse(read(join(artifact, 'summary.json'))) as Record<string, unknown>; }
59
+ catch (error) { return fail('remote-changed-gate', `summary unreadable: ${String(error)}`); }
60
+ if (summary.head40 !== input.head || summary.base40 !== baseHead || summary.remoteHost !== input.remote
61
+ || summary.verdict !== 'passed' || summary.exitCode !== 0 || summary.introduced !== 0
62
+ || summary.unknown !== 0 || summary.preconditionUnmet !== 0) {
63
+ return fail('remote-changed-gate', 'summary does not prove this head/base/remote passed with zero unknown');
64
+ }
65
+ const fresh = await invoke('gh', ['pr', 'view', String(input.pr), '--json', 'headRefOid,state,isDraft'], input.cwd);
66
+ let latest: { headRefOid?: unknown; state?: unknown; isDraft?: unknown };
67
+ try { latest = JSON.parse(fresh.stdout) as typeof latest; }
68
+ catch { return fail('pr-head', `current PR state unreadable: ${fresh.stderr || fresh.stdout || fresh.status}`); }
69
+ if (fresh.status !== 0 || latest.state !== 'OPEN' || latest.isDraft !== false
70
+ || typeof latest.headRefOid !== 'string' || latest.headRefOid.toLowerCase() !== input.head.toLowerCase()) {
71
+ return fail('pr-head', `PR #${input.pr} changed after gate or is not ready`);
72
+ }
73
+ const enrolled = await invoke(input.command, [String(input.pr), input.cwd, '--review', input.reviewResult, '--expected-head', input.head], input.cwd,
74
+ { ...process.env, LAND_RR_DIR: dirname(input.reviewResult) });
75
+ if (enrolled.status !== 0 || !new RegExp(`^OK #${input.pr} head=${input.head.slice(0, 12)}(?:\\s|$)`, 'm').test(enrolled.stdout)) {
76
+ return fail('land-enqueue-refused', enrolled.stdout || enrolled.stderr || `exit ${enrolled.status}`);
77
+ }
78
+ return { status: 0, stdout: `queued #${input.pr} head ${input.head.slice(0, 12)} gate ${artifact} · ${enrolled.stdout.slice(-250)}`, stderr: '' };
79
+ }