elanous 0.2.36 → 0.2.37

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 (630) 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/{uC-N0emedeNOFuaBQFv-I → 8kITumG9GAZ1LwT9POrAR}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +62 -0
  8. package/apps/pwa/out/_next/static/chunks/{4286.b70c4520306817e8.js → 1262.a89bb27a5b2f844e.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{3410.7f9af5ab77cbe65f.js → 1746.3563617ea64023a3.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{9250-072df22eaadaa6b5.js → 2002-a43a3f380df873ec.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +32 -0
  19. package/apps/pwa/out/_next/static/chunks/{3727.7949ccaacaa71242.js → 2283.edd9627b7bdfb546.js} +2 -2
  20. package/apps/pwa/out/_next/static/chunks/2318-450e75d07605b8fe.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{4615.8525eb0add35eba6.js → 2375.bf364c85dbb6f085.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +148 -0
  25. package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +27 -0
  29. package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{5711.957b095705c12560.js → 3199.6a1a9b0e6cd01dc6.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{2986.45d7652e4f13557e.js → 3578.4e9f9948a9a6f2f4.js} +2 -2
  35. package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +90 -0
  39. package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +226 -0
  40. package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +287 -0
  41. package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{7481.39f7a4654907bf6e.js → 4313.76f232c304a15bde.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4337e36d.f42c3b391b3d8f20.js +122 -0
  45. package/apps/pwa/out/_next/static/chunks/{6943.c6b24124853a47b2.js → 4383.18e5c54db3a22c88.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{3757-180308bc61021b05.js → 4725-34bed25720cc326b.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +24 -0
  52. package/apps/pwa/out/_next/static/chunks/{771.c3cdb6c1f7f47c02.js → 4931.95cc6dbd230774ca.js} +3 -3
  53. package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{552.b7d061ad91eeac51.js → 5046.7fd5cbd859299448.js} +2 -2
  56. package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +104 -0
  57. package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/{9f31e478.fefcbcd3c388ebc5.js → 58edce7d.f1b0c72acf13b123.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +93 -0
  65. package/apps/pwa/out/_next/static/chunks/{3136.30aaaa5fa03662a3.js → 5952.294fc574a8625184.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/{da5ecc5c-b005ad8cac737d57.js → 5f6af561-f90b7a67f4f75d13.js} +1 -1
  67. package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +74 -0
  68. package/apps/pwa/out/_next/static/chunks/{3324.a09703033abcbd2f.js → 6252.240578f10952e091.js} +1 -1
  69. package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{8904.7d51af2dc033965c.js → 6680.6a693c28aae4cd19.js} +2 -2
  71. package/apps/pwa/out/_next/static/chunks/{275-02ea4c2a33980422.js → 6745-5a63492933959dd9.js} +3 -3
  72. package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +149 -0
  74. package/apps/pwa/out/_next/static/chunks/{528.38ce20ef8aa251ff.js → 6819.be5c9c4d67f22922.js} +3 -3
  75. package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{3a3d9966.cc4d4585a2708e7c.js → 709a918c.4fd3b4e2a32cb4e3.js} +1 -1
  78. package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +41 -0
  80. package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +24 -0
  83. package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/{4304.e9b2512834a9e23e.js → 7424.c0fe2a595d4232b5.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{2683.c9773a0c589b031b.js → 7867.e8725745ddd1d940.js} +4 -4
  93. package/apps/pwa/out/_next/static/chunks/{6466-92e65a48490b68a9.js → 7893-e444a1b0809cd1e4.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{ccae1c4b-0cf414f5eff1b10d.js → 7c5ed21f-f286708e57cf88f7.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +8 -0
  98. package/apps/pwa/out/_next/static/chunks/{3840-5825d56d46976a92.js → 8080-40d781e7704d3671.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +77 -0
  100. package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +286 -0
  103. package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +79 -0
  107. package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{873d6c12.09bd499f57171543.js → 8c58d09b.e8724a299658d86f.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/{575.d929793a53f27c4b.js → 9151.a2c51e93f9156dae.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +94 -0
  117. package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{190.285c832bd9626f8c.js → 958.53a8dcf4729e6997.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/{page-e2de2e59111c9aad.js → page-3337c6a1328c2674.js} +1 -1
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/{page-f2b2e4bf6e981450.js → page-89acd5d68c0bc560.js} +1 -1
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-2af16e62c12f22df.js → page-fe986fe79b107546.js} +1 -1
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-1e5da297557d2354.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-88a1edbff62eaf1d.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-ac2c1e6169cfce57.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c1c80e345fa9d6f5.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{053a429e.9a63436527cc751c.js → d9815f84.4918f682a45a8502.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{ceba0382.650712b56b85b582.js → de8446d3.31b73eb239fecd7b.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +1 -0
  184. package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
  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 +23 -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/graphs/drafts/recipes.yaml +27 -7
  279. package/graphs/work/draft-close.yaml +54 -0
  280. package/graphs/work/green-close.yaml +37 -0
  281. package/graphs/work/recipes.yaml +46 -1
  282. package/graphs/work/run-research.yaml +35 -0
  283. package/package.json +1 -1
  284. package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
  285. package/scripts/boundary-proof-mapping-audit.ts +88 -0
  286. package/scripts/codex-fallback-live-probe.ts +17 -15
  287. package/scripts/fleet/node-setup.sh +32 -2
  288. package/scripts/fleet/run-light-worker.sh +9 -0
  289. package/scripts/gate-0226-failure-census.ts +507 -0
  290. package/scripts/goals/authoring-metrics.ts +258 -0
  291. package/scripts/graph-units/draft-close-node.ts +222 -0
  292. package/scripts/hook-order-sweep.ts +7 -4
  293. package/scripts/land-global-checks.ts +69 -1
  294. package/scripts/measure-nl-routing-corpus.ts +207 -2
  295. package/scripts/release-loop/docs-node.ts +140 -0
  296. package/scripts/release-loop/gate-closure.ts +48 -0
  297. package/scripts/release-loop/gate-diff.ts +2 -1
  298. package/scripts/release-loop/known-issues-node.ts +6 -4
  299. package/scripts/release-loop/notes-repair.ts +216 -0
  300. package/scripts/release-loop/prepare-node.ts +61 -5
  301. package/scripts/release-loop/resume-release.ts +114 -4
  302. package/scripts/release-loop/resume-test-traffic.ts +10 -0
  303. package/scripts/release-loop/version-node.ts +81 -12
  304. package/scripts/train/green-leg.ts +176 -0
  305. package/scripts/tui-continue-real-evidence.ts +47 -0
  306. package/scripts/ux-sim.ts +1 -1
  307. package/src/acp/client.ts +31 -5
  308. package/src/acp/core-turn-bridge.ts +6 -0
  309. package/src/acp/stderr-summary.ts +49 -0
  310. package/src/agent/monad-agent-turn.ts +1 -0
  311. package/src/agent/terminal-surface.ts +217 -0
  312. package/src/agent-substrate/pr-reviewer.ts +11 -3
  313. package/src/agent-substrate/self-review-cli.ts +343 -31
  314. package/src/autopilot/lineage/sources.ts +1 -1
  315. package/src/autopilot/pr-manager.ts +64 -13
  316. package/src/boot/daemon-runtime.ts +35 -3
  317. package/src/boot/daemon-tools/pty-shell.ts +2 -1
  318. package/src/budget/run-usage-rollup.ts +12 -7
  319. package/src/budget/unified-usage.ts +20 -0
  320. package/src/capture/tui-self-report.ts +32 -3
  321. package/src/cli/autopilot-cli.ts +24 -9
  322. package/src/cli/decisions-cli.ts +7 -4
  323. package/src/cli/doctor-cli.ts +116 -7
  324. package/src/cli/logs-cli.ts +357 -2
  325. package/src/cli/memory-cli.ts +30 -1
  326. package/src/cli/msg-cli.ts +15 -11
  327. package/src/cli/pr-granularity.ts +5 -3
  328. package/src/cli/release-checklist-read-cli.ts +109 -4
  329. package/src/cli/release-cli.ts +43 -10
  330. package/src/cli/self-update.ts +23 -5
  331. package/src/cli/self-utterances-cli.ts +13 -16
  332. package/src/cli/tasks-cli.ts +309 -11
  333. package/src/cli/usage-cli.ts +12 -10
  334. package/src/context-bus/claude-memory-import.ts +99 -0
  335. package/src/context-bus/long-term-memory.ts +125 -0
  336. package/src/core-turn/run-goal-loop.ts +5 -2
  337. package/src/core-turn/types.ts +2 -0
  338. package/src/dashboard/chat/acp-chat.ts +9 -0
  339. package/src/dashboard/index.ts +97 -13
  340. package/src/dashboard/input/agent-wake.ts +43 -0
  341. package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
  342. package/src/dashboard/replay-preview.ts +25 -0
  343. package/src/dashboard/slash-runtime/dashboard-handlers.ts +17 -8
  344. package/src/dashboard/synchronized-frame-output.ts +74 -0
  345. package/src/display/coordinator.ts +45 -12
  346. package/src/display/resize-listener.ts +41 -20
  347. package/src/display/synchronized-output-region.ts +60 -0
  348. package/src/domains/surface-events.ts +80 -1
  349. package/src/exec-requests/planner.ts +37 -2
  350. package/src/execution-loop/launch-gate.ts +4 -3
  351. package/src/git-fs/cli-stderr.ts +45 -0
  352. package/src/git-fs/gh-cli.ts +6 -3
  353. package/src/git-fs/git-cli.ts +11 -5
  354. package/src/graph-runner/graph-cli.ts +26 -2
  355. package/src/graph-runner/graph-run-api.ts +3 -2
  356. package/src/graph-runner/runner.ts +17 -5
  357. package/src/graph-wizard/generate.ts +29 -6
  358. package/src/harness/harness-cli-command.ts +179 -33
  359. package/src/harness/review-adapter.ts +26 -6
  360. package/src/index.ts +116 -13
  361. package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
  362. package/src/llm/route-decision.ts +13 -0
  363. package/src/llm-tool-name.ts +37 -0
  364. package/src/llm-tool-schema.ts +35 -0
  365. package/src/llm.ts +123 -11
  366. package/src/loops/checker.ts +100 -0
  367. package/src/loops/consensus.ts +26 -2
  368. package/src/loops/loop-cli.ts +9 -4
  369. package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
  370. package/src/loops/orchestrator/tick.ts +49 -4
  371. package/src/model-tier/llm-tier-map.ts +12 -17
  372. package/src/msg/msg-store.ts +17 -0
  373. package/src/native-tool-catalog.ts +1 -1
  374. package/src/nexus/api/graph-wizard-api.ts +27 -2
  375. package/src/nexus/api/grid.ts +24 -4
  376. package/src/nexus/api/http-server.ts +1 -1
  377. package/src/nexus/api/ops-api.ts +14 -6
  378. package/src/nexus/state/state.ts +7 -1
  379. package/src/oauth/codex-account-store.ts +34 -1
  380. package/src/ops/loops-map.ts +46 -0
  381. package/src/ops/overview-cache.ts +22 -4
  382. package/src/ops/overview.ts +41 -5
  383. package/src/policy/llm-policy.ts +3 -1
  384. package/src/prompt-enhance/enhance.ts +4 -4
  385. package/src/pty-shell/availability.ts +7 -0
  386. package/src/pty-shell/herdr-agent-report.ts +40 -31
  387. package/src/pty-shell/herdr-prune-stale.ts +17 -0
  388. package/src/pty-shell/herdr-sequence-lease.ts +60 -0
  389. package/src/pty-shell/pty-control-ipc.ts +187 -18
  390. package/src/pty-shell/registry.ts +25 -15
  391. package/src/pty-shell/tui-run-state.ts +235 -1
  392. package/src/release-loop/checklist.ts +50 -5
  393. package/src/release-loop/feature-store.ts +9 -9
  394. package/src/release-loop/landed-but-yellow.ts +93 -12
  395. package/src/repl/index.ts +8 -0
  396. package/src/seat-loop/seat-report.ts +1 -0
  397. package/src/self-dev/ask-launch-flow.ts +86 -10
  398. package/src/self-dev/decompose-proposal.ts +29 -18
  399. package/src/self-dev/dev-pipeline.ts +29 -7
  400. package/src/self-dev/draft-sweep.ts +241 -16
  401. package/src/self-dev/draft-triage-rules.ts +19 -5
  402. package/src/self-dev/review-provider-fallback.ts +45 -7
  403. package/src/self-dev/shard-plan.ts +48 -0
  404. package/src/self-dev/shard-run.ts +50 -3
  405. package/src/self-implement/doctor-visit.ts +83 -0
  406. package/src/self-implement/gate-artifacts.ts +6 -2
  407. package/src/self-implement/gate-baseline.ts +64 -1
  408. package/src/self-implement/gate-cli.ts +93 -9
  409. package/src/self-implement/gate-remote.ts +28 -4
  410. package/src/self-implement/gate-scope.ts +13 -1
  411. package/src/self-implement/goal-author.ts +333 -18
  412. package/src/self-implement/goal-supervisor-fill.ts +75 -26
  413. package/src/self-implement/importer-test-index.ts +215 -2
  414. package/src/self-implement/knowhow-pack.ts +5 -5
  415. package/src/self-implement/orchestrator.ts +318 -25
  416. package/src/self-implement/review-round-brief.ts +300 -0
  417. package/src/self-implement/rework-policy.ts +14 -0
  418. package/src/self-implement/run-ledger.ts +170 -6
  419. package/src/self-implement/run-stop.ts +1 -1
  420. package/src/self-implement/running-runs.ts +17 -3
  421. package/src/self-implement/seams.ts +12 -6
  422. package/src/self-implement/stop-autoheal.ts +1 -0
  423. package/src/self-implement/test-seams.ts +13 -1
  424. package/src/self-implement/train-reach-grouping.ts +8 -2
  425. package/src/session/chat.ts +7 -1
  426. package/src/session/id-prefix.ts +60 -0
  427. package/src/session/index.ts +4 -0
  428. package/src/session-runtime/index.ts +9 -1
  429. package/src/skills/tools/pty.ts +5 -0
  430. package/src/status/metrics.ts +12 -1
  431. package/src/steward/rejudge-tick.ts +12 -5
  432. package/src/steward/resync-tick.ts +31 -4
  433. package/src/task-agent/actions.ts +199 -4
  434. package/src/task-agent/boundary-proof-mapping.ts +12 -0
  435. package/src/task-agent/boundary-proof-producer.ts +147 -0
  436. package/src/task-agent/completion-evidence.ts +2 -1
  437. package/src/task-agent/green-close-recipe.ts +239 -0
  438. package/src/task-agent/green-sweep.ts +64 -10
  439. package/src/task-agent/live-moves.ts +48 -3
  440. package/src/task-agent/map-host-adapter.ts +134 -0
  441. package/src/task-agent/map-reduce.ts +158 -0
  442. package/src/task-agent/map-run-ledger.ts +226 -0
  443. package/src/task-agent/parent-host.ts +21 -11
  444. package/src/task-agent/rejudge-on-head.ts +72 -5
  445. package/src/task-agent/repair-cycle.ts +41 -0
  446. package/src/task-agent/repair-next-move.ts +12 -2
  447. package/src/task-agent/review-prior-fix.ts +12 -2
  448. package/src/task-agent/shadow.ts +188 -5
  449. package/src/task-agent/task-hand.ts +158 -13
  450. package/src/task-agent/task-parent-role-llm.ts +9 -0
  451. package/src/task-agent/tier-split.ts +4 -3
  452. package/src/task-agent/work-order.ts +53 -2
  453. package/src/task-orchestrator/dispatcher.ts +46 -1
  454. package/src/task-orchestrator/generator-prompt.ts +6 -0
  455. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
  456. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
  457. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
  458. package/src/task-orchestrator/surfaces/pod-pool.ts +50 -4
  459. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +15 -9
  460. package/src/task-orchestrator/surfaces/self-implement-pod.ts +217 -36
  461. package/src/task-orchestrator/surfaces/self-implement.ts +4 -0
  462. package/src/testing/linux-env.ts +177 -0
  463. package/src/tui/chat/goal-interim.ts +5 -1
  464. package/src/tui/entry.ts +258 -4
  465. package/src/tui/input/at-picker.ts +55 -0
  466. package/src/tui/slash/resume.ts +35 -12
  467. package/src/tui/slash/signals.ts +114 -0
  468. package/src/tui/slash/term-next.ts +71 -0
  469. package/src/tui-client/local-chat-turn.ts +4 -3
  470. package/src/user-config.ts +19 -1
  471. package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
  472. package/src/ux-sim/classic-tui-seat-scenarios.ts +158 -4
  473. package/src/ux-sim/fake-gh.ts +174 -0
  474. package/src/ux-sim/fake-kubectl.ts +142 -0
  475. package/src/ux-sim/fake-llm.ts +6 -1
  476. package/src/ux-sim/next-tui-seat-scenarios.ts +124 -6
  477. package/src/ux-sim/resume-picker-device.ts +173 -0
  478. package/src/ux-sim/session-id-seed.ts +60 -0
  479. package/src/ux-sim/skills-tools-shell-device.ts +156 -0
  480. package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
  481. package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
  482. package/src/version/packed-revision.json +1 -1
  483. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +0 -287
  484. package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +0 -36
  490. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +0 -149
  493. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +0 -24
  498. package/apps/pwa/out/_next/static/chunks/2812ca6a.3b9f4a7a08885744.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +0 -24
  502. package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/3148-98efd4869d660a87.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +0 -226
  505. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +0 -8
  509. package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +0 -32
  510. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +0 -286
  512. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +0 -74
  515. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +0 -104
  519. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +0 -148
  522. package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +0 -93
  524. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +0 -122
  526. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/599.c39c571b6733f2a2.js +0 -41
  531. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +0 -79
  532. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +0 -27
  544. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/6925.562d532110879886.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7891.03f910124a737985.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +0 -62
  557. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +0 -90
  559. package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +0 -94
  560. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +0 -77
  565. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/9514.131c52cc75fe6439.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +0 -1
  630. /package/apps/pwa/out/_next/static/{uC-N0emedeNOFuaBQFv-I → 8kITumG9GAZ1LwT9POrAR}/_ssgManifest.js +0 -0
@@ -51,6 +51,16 @@ export interface ShardRunMode {
51
51
  fixedDistribution?: boolean;
52
52
  /** Measured on the executing host; override only for deterministic planning tests. */
53
53
  hostResources?: { cores: number; freeMemoryGiB: number; freeTmpGiB: number };
54
+ /** Observation after each bundle's first current+baseline attempt; never controls retries or verdict. */
55
+ onShardComplete?: (progress: ShardRunProgress) => void;
56
+ }
57
+
58
+ export interface ShardRunProgress {
59
+ shardId: string;
60
+ completedShards: number;
61
+ totalShards: number;
62
+ completedFiles: number;
63
+ totalFiles: number;
54
64
  }
55
65
 
56
66
  function hostResources(): ShardRunMode['hostResources'] | undefined {
@@ -162,7 +172,7 @@ export function runShardedGateTests(
162
172
  try { fixed = planFixedGateTestShards(files, count); }
163
173
  catch (error) { return { aggregate: { status: 'unmeasured', retryShardIds: [] }, shards: [], attempts: [], reason: String(error), distribution: 'fixed' }; }
164
174
  debug.log('self-dev.shard', 'fixed-distribution', { shards: fixed.length, files: fixed.reduce((sum, shard) => sum + shard.files.length, 0) });
165
- return { ...runPlannedShards(cwd, fixed, baseRef, run, baselineWorktree), distribution: 'fixed' };
175
+ return { ...runPlannedShards(cwd, fixed, baseRef, run, baselineWorktree, mode.onShardComplete), distribution: 'fixed' };
166
176
  }
167
177
  const rss = new Map<string, number>();
168
178
  const seconds = new Map<string, number>();
@@ -199,7 +209,7 @@ export function runShardedGateTests(
199
209
  const fixed = planFixedGateTestShards(files, maxCount);
200
210
  debug.log('self-dev.shard', 'host-cap-fixed-fallback', { requested: count, cap: maxCount,
201
211
  files: new Set(files).size, reason, measurementFailures: measurementFailures ?? 0 });
202
- return { ...runPlannedShards(cwd, fixed, baseRef, run, baselineWorktree), distribution: 'fixed-cap-fallback',
212
+ return { ...runPlannedShards(cwd, fixed, baseRef, run, baselineWorktree, mode.onShardComplete), distribution: 'fixed-cap-fallback',
203
213
  fallbackReason: reason, ...(measurementFailures ? { measurementFailures } : {}) };
204
214
  } catch (error) {
205
215
  return { aggregate: { status: 'unmeasured', retryShardIds: [] }, shards: [], attempts: [],
@@ -232,7 +242,7 @@ export function runShardedGateTests(
232
242
  requested: count, planned: shards.length, files: new Set(files).size, budgetGiB,
233
243
  measurementFailures: measurementFailures ?? 0,
234
244
  });
235
- return { ...runPlannedShards(cwd, shards, baseRef, run, baselineWorktree), ...(plannedCount > count ? { expandedFrom: count } : {}), ...(measurementFailures ? { measurementFailures } : {}) };
245
+ return { ...runPlannedShards(cwd, shards, baseRef, run, baselineWorktree, mode.onShardComplete), ...(plannedCount > count ? { expandedFrom: count } : {}), ...(measurementFailures ? { measurementFailures } : {}) };
236
246
  }
237
247
 
238
248
  /** Shared by the measured and the fixed planner: current + baseline per shard, one retry round, one aggregate. */
@@ -242,6 +252,7 @@ function runPlannedShards(
242
252
  baseRef: string,
243
253
  run: ShardProcess,
244
254
  baselineWorktree: typeof withBaselineWorktree,
255
+ onShardComplete?: ShardRunMode['onShardComplete'],
245
256
  ): ShardRunResult {
246
257
  const attempts: GateShardAttempt[] = [];
247
258
  const failureEvidence: ShardFailureEvidence[] = [];
@@ -256,6 +267,8 @@ function runPlannedShards(
256
267
  const treeReadable = (() => { try { return statSync(dir).isDirectory(); } catch { return false; } })();
257
268
  const atBase = (shard: GateTestShard) => treeReadable ? shard.files.filter((file) => !absentAtBaseline(join(dir, file))) : [...shard.files];
258
269
  let pending = shards;
270
+ let completedFiles = 0;
271
+ const totalFiles = new Set(shards.flatMap((shard) => shard.files)).size;
259
272
  for (let round = 1; round <= 2 && pending.length; round++) {
260
273
  for (const shard of pending) {
261
274
  const runSafely = (location: string, selected: readonly string[]): ReturnType<ShardProcess> => {
@@ -279,6 +292,13 @@ function runPlannedShards(
279
292
  baselineFiles,
280
293
  currentRoot: cwd, baselineRoot: dir,
281
294
  });
295
+ if (round === 1 && onShardComplete) {
296
+ completedFiles += shard.files.length;
297
+ try {
298
+ onShardComplete({ shardId: shard.id, completedShards: attempts.length,
299
+ totalShards: shards.length, completedFiles, totalFiles });
300
+ } catch { /* progress is observation only */ }
301
+ }
282
302
  }
283
303
  const retry = new Set(aggregateGateTestShards(shards, attempts).retryShardIds);
284
304
  pending = shards.filter((shard) => retry.has(shard.id));
@@ -360,3 +380,30 @@ export function runBunShardWithSpawn(cwd: string, files: readonly string[], spaw
360
380
  rmSync(dir, { recursive: true, force: true });
361
381
  }
362
382
  }
383
+
384
+ /** GATE-REMOTE-SHARD-PLAN — identity of one remote shard. files/introducedFiles are optional: a caller that only relays
385
+ * identity (CLI wiring) passes none, while a planner-produced shard carries its file-level attribution. */
386
+ export interface RemoteShardSpec {
387
+ orchestrationId: string;
388
+ shardId: string;
389
+ totalShards: number;
390
+ position: number;
391
+ files?: readonly string[];
392
+ introducedFiles?: readonly string[];
393
+ }
394
+
395
+ /** The identity slice that rides a remote gate command line — validated so a dropped flag fails loudly, not silently. */
396
+ export function remoteShardArgArgs(shard: RemoteShardSpec, options?: { planFile?: string }): string[] {
397
+ if (!shard.orchestrationId.trim()) throw new Error('orchestration id must be non-empty');
398
+ if (!shard.shardId.trim()) throw new Error('shard id must be non-empty');
399
+ if (!Number.isSafeInteger(shard.totalShards) || shard.totalShards < 1) throw new Error('shard total must be a positive integer');
400
+ if (!Number.isSafeInteger(shard.position) || shard.position < 1) throw new Error('shard position must be a positive integer');
401
+ const args = ['--orchestration-id', shard.orchestrationId, '--shard-id', shard.shardId, '--shard-position', String(shard.position)];
402
+ if (options?.planFile !== undefined && options.planFile !== '') args.push('--shard-plan', options.planFile);
403
+ return args;
404
+ }
405
+
406
+ /** Full remote command for one shard — the exact argv a remote host (e.g. an node-b pod shard) would run. */
407
+ export function remoteShardArgv(shard: RemoteShardSpec, options?: { planFile?: string }): string[] {
408
+ return ['bun', 'bin/elanous.mjs', '--test', 'self', 'gate', '--changed', '--shards', String(shard.totalShards), ...remoteShardArgArgs(shard, options)];
409
+ }
@@ -1,4 +1,7 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { SPAWN_SYNC_MAX_BUFFER } from '../util/spawn-sync-output.js';
1
3
  import { debug } from '../debug/log.js';
4
+ import { loadReviewRoundBrief, type ReviewRoundBrief } from './review-round-brief.js';
2
5
  import { findIncidentPrecedents, type IncidentPrecedent } from '../harness/harness-incidents.js';
3
6
  import { elanousStateRoot } from '../autopilot/state-paths.js';
4
7
  import {
@@ -16,6 +19,42 @@ export function doctorVisitIncidentRoot(): string {
16
19
  return elanousStateRoot();
17
20
  }
18
21
 
22
+ export interface DoctorReviewPrMetadata { headRefOid: string; body: string; files: string[]; comments?: Array<{ body: string; author: string }> }
23
+
24
+ /** Fetch only the metadata needed to anchor a saved review to the current PR head. */
25
+ export function readDoctorReviewPr(pr: number): DoctorReviewPrMetadata {
26
+ const result = spawnSync('gh', ['pr', 'view', String(pr), '--json', 'headRefOid,body,files,author,comments'], {
27
+ encoding: 'utf8', timeout: 30_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER, stdio: ['ignore', 'pipe', 'pipe'],
28
+ });
29
+ if (result.error || result.status !== 0) throw new Error(`PR #${pr} unavailable: ${result.error?.message ?? result.stderr?.trim() ?? 'gh failed'}`);
30
+ const data = JSON.parse(result.stdout) as { headRefOid?: unknown; body?: unknown; files?: unknown; author?: { login?: unknown }; comments?: unknown };
31
+ if (typeof data.headRefOid !== 'string' || !/^[a-f0-9]{40}$/i.test(data.headRefOid)) throw new Error('PR headRefOid is missing or invalid');
32
+ return {
33
+ headRefOid: data.headRefOid,
34
+ body: typeof data.body === 'string' ? data.body : '',
35
+ files: Array.isArray(data.files) ? data.files.flatMap((file: unknown) => {
36
+ if (typeof file === 'string') return [file];
37
+ if (file && typeof file === 'object' && typeof (file as { path?: unknown }).path === 'string') return [(file as { path: string }).path];
38
+ return [];
39
+ }) : [],
40
+ comments: typeof data.author?.login === 'string' && Array.isArray(data.comments) ? data.comments.flatMap((comment: unknown) => {
41
+ if (!comment || typeof comment !== 'object') return [];
42
+ const item = comment as { body?: unknown; author?: { login?: unknown } };
43
+ const login = item.author?.login;
44
+ return typeof item.body === 'string' && typeof login === 'string' && login === data.author?.login
45
+ ? [{ body: item.body, author: login }] : [];
46
+ }) : [],
47
+ };
48
+ }
49
+
50
+ /** Doctor's saved-review view; never records a run-ledger visit for a PR. */
51
+ export function readDoctorReviewBrief(pr: number, read: (pr: number) => DoctorReviewPrMetadata = readDoctorReviewPr, reviewResultsDir?: string): ReviewRoundBrief {
52
+ if (!Number.isSafeInteger(pr) || pr <= 0) throw new Error('PR number must be a positive integer');
53
+ const metadata = read(pr);
54
+ return loadReviewRoundBrief({ pr, head: metadata.headRefOid, body: metadata.body, changedFiles: metadata.files, comments: metadata.comments?.map((comment) => comment.body),
55
+ ...(reviewResultsDir ? { reviewResultsDir } : {}) });
56
+ }
57
+
19
58
  /** DOCTOR-VISIT 증상 닫힌 목록 — 이 밖의 값은 기록·조회 모두 거부한다. */
20
59
  export const DOCTOR_SYMPTOMS = [
21
60
  'admit-starved',
@@ -180,8 +219,52 @@ export function recordTaskAgentNeedsOwnerVisit(input: {
180
219
  return { status: outcome.result ?? 'missing-ledger' };
181
220
  }
182
221
 
222
+ /** A parent stop that needs an owner records one shadow visit per stop, without running a prescription. */
223
+ export function recordParentNeedsOwnerVisit(input: {
224
+ runId: string;
225
+ stopKey: string;
226
+ evidence: string;
227
+ dir?: string;
228
+ }): { status: 'missing-ledger' | 'recorded' | 'already-recorded' } {
229
+ const outcome = appendRunLedgerEntryChecked(input.runId, (entries) => {
230
+ if (entries === null) return { append: false, result: 'missing-ledger' as const };
231
+ if (entries.some((entry) => entry.event === 'doctor-visit' && entry.data.from === 'parent'
232
+ && entry.data.symptom === 'needs-owner' && entry.data.stopKey === input.stopKey)) {
233
+ return { append: false, result: 'already-recorded' as const };
234
+ }
235
+ return { append: true, entry: {
236
+ runId: input.runId,
237
+ timestamp: new Date().toISOString(),
238
+ event: 'doctor-visit',
239
+ data: { from: 'parent', symptom: 'needs-owner', stopKey: input.stopKey, evidence: input.evidence },
240
+ } };
241
+ }, input.dir);
242
+ if (outcome.appended) {
243
+ debug.log('run-doctor', 'visit', { runId: input.runId, from: 'parent', symptom: 'needs-owner', stopKey: input.stopKey });
244
+ return { status: 'recorded' };
245
+ }
246
+ if (outcome.result === null) throw new Error(`run-ledger-write-refused: ${input.runId}`);
247
+ return { status: outcome.result };
248
+ }
249
+
183
250
  export type ReadDoctorVisitsOptions = RunLedgerLookupOptions;
184
251
 
252
+ /** Project logged review briefs into status without changing the run-ledger schema. Keep the latest observation per PR. */
253
+ export function doctorReviewVisits(events: readonly { timestamp?: string; sequence?: number; runId?: string; key?: string; evidence?: string }[]): (Omit<DoctorVisit, 'runId'> & { runId?: string })[] {
254
+ const seenPrs = new Set<string>();
255
+ return [...events].sort((left, right) => {
256
+ const leftAt = left.timestamp ? Date.parse(left.timestamp) : 0;
257
+ const rightAt = right.timestamp ? Date.parse(right.timestamp) : 0;
258
+ return rightAt - leftAt || (right.sequence ?? 0) - (left.sequence ?? 0) || String(right.key ?? '').localeCompare(String(left.key ?? ''));
259
+ }).flatMap((event) => {
260
+ const pr = /^(\d+)(?::|$)/.exec(event.key ?? '')?.[1];
261
+ if (pr && seenPrs.has(pr)) return [];
262
+ if (pr) seenPrs.add(pr);
263
+ return [{ ...(event.runId ? { runId: event.runId } : {}), from: 'seat' as const, symptom: 'review-loop' as const,
264
+ ...(event.evidence ? { evidence: event.evidence } : {}), ...(event.timestamp ? { timestamp: event.timestamp } : {}) }];
265
+ });
266
+ }
267
+
185
268
  /** `runId` 원장이 조회 범위 안에 있는가 — `doctor status --run` 이 없는 런을 «0건»으로 삼키지 않게 한다. */
186
269
  export function doctorVisitRunExists(runId: string, options: ReadDoctorVisitsOptions = {}): boolean {
187
270
  return lookupRunLedger(runId, options).matches.length > 0;
@@ -85,6 +85,7 @@ export interface GateArtifactSummary extends GateArtifactCounts {
85
85
  verdict: string | null;
86
86
  /** 판정 줄(`tests: …` / `[gate-baseline] …` / `shards: unmeasured (…)`) 그대로. */
87
87
  verdictLine?: string;
88
+ timeoutRechecks?: readonly { name: string; file: string; result: 'pass' | 'timeout' | 'failure' | 'unknown'; elapsedMs: number; rawResultLine: string }[];
88
89
  exitCode: number;
89
90
  /** 정수 칸 중 하나라도 null 일 때만 — 왜 못 셌나(한 줄). */
90
91
  countsUnavailableReason?: string;
@@ -129,6 +130,7 @@ export interface GateArtifactInput {
129
130
  testFiles: readonly string[];
130
131
  verdict: string | null;
131
132
  verdictLine?: string;
133
+ timeoutRechecks?: readonly { name: string; file: string; result: 'pass' | 'timeout' | 'failure' | 'unknown'; elapsedMs: number; rawResultLine: string }[];
132
134
  exitCode: number;
133
135
  /** 판정 정수(못 센 칸은 null ⊕ countsUnavailableReason). 안 주면 다섯 다 null · 이유 'not recorded' — 칸은 «늘» 쓴다. */
134
136
  counts?: GateArtifactCounts;
@@ -219,6 +221,7 @@ export function writeGateArtifacts(input: GateArtifactInput): { summaryPath: str
219
221
  shardsDetail,
220
222
  verdict: input.verdict,
221
223
  ...(input.verdictLine !== undefined ? { verdictLine: input.verdictLine } : {}),
224
+ ...(input.timeoutRechecks ? { timeoutRechecks: input.timeoutRechecks } : {}),
222
225
  exitCode: input.exitCode,
223
226
  introduced: counts.introduced,
224
227
  preexisting: counts.preexisting,
@@ -388,8 +391,9 @@ export function importRemoteGateArtifacts(dir: string, files: Map<string, Buffer
388
391
  writeFileSync(run.resultPath, `${JSON.stringify(result, null, 2)}\n`);
389
392
  };
390
393
  for (const shard of summary.shardsDetail) { relocate(shard?.current); relocate(shard?.baseline); }
391
- // OP FU (MK #8178) — 원격 조각의 실패 증거(`<shardId>.failure.json`)도 그대로 가져온다(관측만 · summary 는 안 고친다).
392
- for (const [name, bytes] of files) if (name.endsWith('.failure.json') && artifactNamePattern.test(name)) writeFileSync(join(dir, name), bytes);
394
+ // Optional observations stay optional for older remote commits. Neither changes the gate verdict.
395
+ for (const [name, bytes] of files) if ((name === 'progress.json' || name.endsWith('.failure.json'))
396
+ && artifactNamePattern.test(name)) writeFileSync(join(dir, name), bytes);
393
397
  summary.remoteHost = host;
394
398
  writeFileSync(summaryPath, `${JSON.stringify(summary, null, 2)}\n`);
395
399
  return { summaryPath, junitFiles };
@@ -9,7 +9,7 @@ import type { GitRunResult } from '../git-fs/retry.js';
9
9
  import { linkWorktreeDependencies, worktreeAddTimeoutForRepo } from '../git-fs/worktree.js';
10
10
  import { reapStaleGateWorktrees } from './gate-baseline-reap.js';
11
11
 
12
- export type GateFailureAttribution = 'introduced' | 'preexisting' | 'unknown' | 'precondition-unmet' | 'flaky-timeout' | 'flaky-rerun';
12
+ export type GateFailureAttribution = 'introduced' | 'preexisting' | 'unknown' | 'precondition-unmet' | 'flaky-timeout' | 'flaky-rerun' | 'timeout-recheck-passed';
13
13
  export type GateBaselinePresence = 'present' | 'missing' | 'unknown';
14
14
  export type TimeoutVariability = 'may-vary' | 'same' | 'unknown';
15
15
 
@@ -72,6 +72,16 @@ export interface GateBaselineReport extends GateBaselineSummary {
72
72
  files: string[];
73
73
  baselineStatus: BaselineProcessStatus;
74
74
  log: string;
75
+ timeoutRechecks?: TimeoutRecheckRecord[];
76
+ timeoutRecheckPassed?: number;
77
+ }
78
+
79
+ export interface TimeoutRecheckRecord {
80
+ name: string;
81
+ file: string;
82
+ result: 'pass' | 'timeout' | 'failure' | 'unknown';
83
+ elapsedMs: number;
84
+ rawResultLine: string;
75
85
  }
76
86
 
77
87
  interface GateTestCountChange {
@@ -697,6 +707,9 @@ function summarizeGateBaseline(failures: readonly GateTestFailure[]): GateBaseli
697
707
  if (failure.attribution === 'flaky-rerun') {
698
708
  return { ...withPresence, flakyRerun: withPresence.flakyRerun + 1 };
699
709
  }
710
+ if (failure.attribution === 'timeout-recheck-passed') {
711
+ return withPresence;
712
+ }
700
713
  const withTimeoutRegression = failure.timeoutRegression === 'passed-at-base'
701
714
  ? { ...withPresence, timeoutPassedAtBase: withPresence.timeoutPassedAtBase + 1 }
702
715
  : withPresence;
@@ -722,6 +735,51 @@ export function rerunBunSingleTest(cwd: string, file: string, testName: string,
722
735
  return classifyBunSingleTestRerun(result);
723
736
  }
724
737
 
738
+ /** A standalone timeout-only retry is allowed only when every introduced failure is explicitly a Bun timeout. */
739
+ export function recheckTimeoutOnlyIntroducedFailures(
740
+ cwd: string,
741
+ report: GateBaselineReport,
742
+ run: (cwd: string, file: string, name: string, timeoutMs: number) => { observation?: TimeoutRerunObservation; elapsedMs: number; output: string } = runTimeoutRecheck,
743
+ ): GateBaselineReport {
744
+ const eligible = report.failures.length > 0
745
+ && report.introduced === report.failures.length
746
+ && report.failures.every((failure) => failure.attribution === 'introduced' && !!failure.file
747
+ && /\bthis test timed out after \d+ms\b/i.test(failure.diagnostic ?? ''));
748
+ if (!eligible) return report;
749
+ const records: TimeoutRecheckRecord[] = [];
750
+ const failures = report.failures.map((failure) => {
751
+ if (!failure.file) return failure;
752
+ const prefix = `${failure.file} > `;
753
+ const name = failure.name.startsWith(prefix) ? failure.name.slice(prefix.length) : failure.name;
754
+ const { observation, elapsedMs, output } = run(cwd, failure.file, name, 60_000);
755
+ const result = observation ?? 'unknown';
756
+ const record: TimeoutRecheckRecord = {
757
+ name: failure.name, file: failure.file, result, elapsedMs,
758
+ rawResultLine: flattenControlChars(redactSecretText(output)).slice(-500),
759
+ };
760
+ records.push(record);
761
+ debug.log('gate.baseline', 'timeout-recheck', record);
762
+ return result === 'pass' ? { ...failure, attribution: 'timeout-recheck-passed' as const } : failure;
763
+ });
764
+ return {
765
+ ...report,
766
+ ...summarizeGateBaseline(failures),
767
+ failures,
768
+ timeoutRechecks: records,
769
+ timeoutRecheckPassed: failures.filter((failure) => failure.attribution === 'timeout-recheck-passed').length,
770
+ };
771
+ }
772
+
773
+ function runTimeoutRecheck(cwd: string, file: string, name: string, timeoutMs: number): { observation?: TimeoutRerunObservation; elapsedMs: number; output: string } {
774
+ const started = Date.now();
775
+ const result = runIsolatedBunTest(cwd, ['--timeout', String(timeoutMs), '--test-name-pattern', buildBunSingleTestPattern(name), file], timeoutMs + 10_000);
776
+ return {
777
+ observation: classifyBunSingleTestRerun(result),
778
+ elapsedMs: Date.now() - started,
779
+ output: `${String(result.stdout ?? '')}\n${String(result.stderr ?? '')}`,
780
+ };
781
+ }
782
+
725
783
  /** `introduced` 재실행 상한. 초과분은 돌리지 않고 보고서에 남긴다. 부하로 건너뛰지 않는다. */
726
784
  export const INTRODUCED_RERUN_CAP = 8;
727
785
 
@@ -1512,6 +1570,7 @@ export function formatGateBaselineNote(report: GateBaselineReport, unrunImporter
1512
1570
  + `, unknown=${report.unknown}, precondition-unmet=${report.preconditionUnmet}`
1513
1571
  + (report.timedOut > 0 ? `, timed-out=${report.timedOut}` : '')
1514
1572
  + (report.flakyRerun > 0 ? `, flaky-rerun=${report.flakyRerun}` : '')
1573
+ + ((report.timeoutRecheckPassed ?? 0) > 0 ? `, timeout-recheck-passed=${report.timeoutRecheckPassed}` : '')
1515
1574
  + (runId ? `, run=${runId}` : '')
1516
1575
  + (report.missingAtBase > 0 ? `, missing-at-base=${report.missingAtBase}` : '');
1517
1576
  const lines = report.failures.map((failure) => `- ${failure.attribution}: ${failure.name}`
@@ -1532,10 +1591,14 @@ export function formatGateBaselineNote(report: GateBaselineReport, unrunImporter
1532
1591
  : report.rerunNotRun > 0
1533
1592
  ? `\n[gate-baseline] rerun not-run=${report.rerunNotRun}`
1534
1593
  : '';
1594
+ const timeoutRecheckLines = report.timeoutRechecks?.length
1595
+ ? `\n[gate.baseline.timeout-recheck] ${report.timeoutRechecks.map((item) => `${item.name}: ${item.result} elapsed=${item.elapsedMs}ms · ${item.rawResultLine}`).join('\n')}`
1596
+ : '';
1535
1597
  return `${head}\n${lines.join('\n')}\n${report.log}`
1536
1598
  + timedOutLine
1537
1599
  + mayVaryNonTimeoutLine
1538
1600
  + rerunLine
1601
+ + timeoutRecheckLines
1539
1602
  + (report.preexisting > 0 ? '\n⚠️ preexisting 실패는 base에서도 재현됨 — 이 PR의 책임이 아니다.' : '');
1540
1603
  }
1541
1604
 
@@ -1,4 +1,5 @@
1
- import { existsSync, lstatSync, mkdtempSync, readFileSync, realpathSync } from 'node:fs';
1
+ import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { randomUUID } from 'node:crypto';
2
3
  import { tmpdir } from 'node:os';
3
4
  import { spawnSync } from 'node:child_process';
4
5
  import { join } from 'node:path/posix';
@@ -12,7 +13,7 @@ import { runIosUnitTestGate } from '../../scripts/ci-ios-unit-tests.js';
12
13
  import { runPwaBuildGate } from '../../scripts/ci-pwa-build-gate.js';
13
14
  import { runMockModuleRestoreGate } from '../../scripts/ci-mock-module-restore-gate.js';
14
15
  import { parseReviewDepthFromFilesJson } from '../agent-mission/review-depth.js';
15
- import { buildGateBaselineReport, calculateGateTestCountChange, formatGateBaselineNote, formatGateTestCountNote, isGateTestFile, runGateBaseline, type BaselineProcessResult, type BaselineProcessStatus, type GateTestFailure } from './gate-baseline.js';
16
+ import { buildGateBaselineReport, calculateGateTestCountChange, formatGateBaselineNote, formatGateTestCountNote, isGateTestFile, recheckTimeoutOnlyIntroducedFailures, runGateBaseline, type BaselineProcessResult, type BaselineProcessStatus, type GateTestFailure, type TimeoutRecheckRecord, type TimeoutRerunObservation } from './gate-baseline.js';
16
17
  import { resolveGateScope } from './gate-scope.js';
17
18
  import { publicExposureFiles, runExposeGate } from './expose-gate.js';
18
19
  import { getUserConfig } from '../user-config.js';
@@ -26,7 +27,8 @@ import {
26
27
  overlapWithCurrentChanges,
27
28
  } from '../cli/pr-granularity.js';
28
29
  import { listWorktrees } from '../git-fs/worktree.js';
29
- import { runShardedGateTests, writeShardFailureEvidence } from '../self-dev/shard-run.js';
30
+ import { runShardedGateTests, writeShardFailureEvidence, remoteShardArgv, type ShardRunProgress } from '../self-dev/shard-run.js';
31
+ import { planGateRemoteShards, shardPlanOrchestrationId, type GateRemoteShard } from '../self-dev/shard-plan.js';
30
32
  import { parseGateScenario, readGateScenarioFile } from './gate-scenario.js';
31
33
  import { isGateSpawnLaneFile } from '../self-dev/spawn-lane-files.js';
32
34
  import { defaultGateEnvKey, defaultRevResolver, resolveArtifactDir, writeGateArtifacts, type GateArtifactCounts, type GateArtifactsUnavailable, type RevResolver } from './gate-artifacts.js';
@@ -99,7 +101,11 @@ interface SelfGateCliDeps {
99
101
  readFile?: (path: string) => string | undefined;
100
102
  runTests?: (cwd: string, files: readonly string[]) => ProcessResult;
101
103
  runBaseline?: (cwd: string, files: readonly string[], baseRef: string) => BaselineProcessResult;
104
+ runTimeoutRecheck?: (cwd: string, file: string, name: string, timeoutMs: number) => { observation?: TimeoutRerunObservation; elapsedMs: number; output: string };
102
105
  runShards?: typeof runShardedGateTests;
106
+ /** Test seam for the live progress line. */
107
+ writeProgressStderr?: (line: string) => void;
108
+ now?: () => number;
103
109
  runIsolationGate?: (out: GateOutput) => number;
104
110
  runMockModuleRestoreGate?: (out: GateOutput) => number;
105
111
  /** 모델 이름 하드코딩 래칫(🅕 #20521) — `pr land` 만 물고 하니스 무인 병합은 안 물면 위반이 main 에 들어가 남의 착지를 막는다(🅣 2026-09-25). */
@@ -131,6 +137,7 @@ interface GateArtifactCapture {
131
137
  /** `unrun importer tests: N` 의 N — 색인 조회 실패면 null(그 이유가 importerLookupFailed). */
132
138
  unrunImporters?: number | null;
133
139
  importerLookupFailed?: string;
140
+ timeoutRechecks?: readonly TimeoutRecheckRecord[];
134
141
  }
135
142
 
136
143
  /** SIDE-VERIFY ③ — summary 정수 칸: 게이트가 이미 낸 `result.baseline` ⊕ `unrunImporterTotal` 을 «옮기기만» 한다.
@@ -388,7 +395,9 @@ export function observePrFileOverlap(
388
395
  return { ok: false as const, out: '', err: error instanceof Error ? error.message : String(error) };
389
396
  }
390
397
  };
391
- const commits = collectBaseLandingCommits(run, cwd, { since: '0', baseRef: `${baseOid}..${baseRefName}` });
398
+ // The resolved base range is the complete scope; a time cutoff can hide a
399
+ // just-created commit when a gate shard is slow.
400
+ const commits = collectBaseLandingCommits(run, cwd, { since: null, baseRef: `${baseOid}..${baseRefName}` });
392
401
  if (commits === null) return { status: 'unavailable', reason: 'git log failed' };
393
402
  const overlaps = overlapWithCurrentChanges(commits, files);
394
403
  return overlaps.length > 0
@@ -588,6 +597,24 @@ export function formatUnrunImporterTests(importerTestsNotRun: NonNullable<Return
588
597
  return `unrun importer tests: ${importerTestsNotRun.total}${files}; unresolved relative specifiers: ${importerTestsNotRun.unresolvedRelativeSpecifiers}`;
589
598
  }
590
599
 
600
+ /** gate 출력 한 줄에 실리는 미등재 spawn-lane 시험의 최대 표시 수 — 실측 드리프트(57건)를 전부 나열하면
601
+ * «읽히지 않는 소음»이 된다(`formatUnrunImporterTests` 의 잘림 정책과 같은 취지). */
602
+ const UNLISTED_SPAWN_LANE_DISPLAY_LIMIT = 10;
603
+
604
+ /** ⛔⭐ 소비자 배선(무인 리뷰 must-fix) — `resolveGateScope` 이 채우는 `runtimeEdgeImpact` 를 읽는 곳이
605
+ * 없으면 그 측정은 어디에도 드러나지 않는다. 정책은 형제들과 같다 — ***「보고한다. 막지 않는다.」***
606
+ * 손으로 관리하는 `GATE_SPAWN_LANE_FILES` 가 실측에서 빠뜨린 spawn-lane 시험을 알린다. */
607
+ export function formatUnlistedSpawnLaneTests(impact: ReturnType<typeof resolveGateScope>['runtimeEdgeImpact']): string {
608
+ if (!impact) return 'unlisted spawn-lane tests: (not measured — no importer index)';
609
+ if (!impact.measured) return 'unlisted spawn-lane tests: (not measured)';
610
+ const total = impact.unlistedSpawnLaneTests.length;
611
+ if (total === 0) return 'unlisted spawn-lane tests: 0';
612
+ const shown = impact.unlistedSpawnLaneTests.slice(0, UNLISTED_SPAWN_LANE_DISPLAY_LIMIT);
613
+ const truncated = total > shown.length ? `, showing ${shown.length}/${total}` : '';
614
+ return `unlisted spawn-lane tests: ${total} (${shown.join(', ')}${truncated})`
615
+ + ' ⚠️ GATE_SPAWN_LANE_FILES 가 빠뜨린 실측 spawn-lane 시험 — 「보고만 한다. 막지 않는다.」';
616
+ }
617
+
591
618
  export function formatPartialObservationNote(unrunImporterTotal: number, note: string): string {
592
619
  if (unrunImporterTotal <= 0) return note;
593
620
  return `partial observation: ${unrunImporterTotal} unrun importer tests; ${note}`;
@@ -756,6 +783,7 @@ function emitGateArtifacts(cwd: string, artifactDir: string, result: SelfGateCli
756
783
  testFiles: capture.testFiles ?? result.testFiles,
757
784
  verdict: capture.verdict ?? null,
758
785
  ...(capture.verdictLine !== undefined ? { verdictLine: capture.verdictLine } : {}),
786
+ ...(capture.timeoutRechecks ? { timeoutRechecks: capture.timeoutRechecks } : {}),
759
787
  exitCode: result.exitCode,
760
788
  counts: counts.counts,
761
789
  ...(counts.reason !== undefined ? { countsUnavailableReason: counts.reason } : {}),
@@ -770,6 +798,31 @@ function emitGateArtifacts(cwd: string, artifactDir: string, result: SelfGateCli
770
798
  }
771
799
  }
772
800
 
801
+ /** A completed bundle is observed immediately, before the synchronous runner returns. Each sink is best effort. */
802
+ function shardProgressObserver(cwd: string, options: SelfGateCliOptions, deps: SelfGateCliDeps): (progress: ShardRunProgress) => void {
803
+ const now = deps.now ?? Date.now;
804
+ const startedAt = now();
805
+ return (progress) => {
806
+ const elapsedMs = Math.max(0, now() - startedAt);
807
+ const estimatedRemainingMs = progress.completedShards > 0
808
+ ? Math.round(elapsedMs * (progress.totalShards - progress.completedShards) / progress.completedShards) : null;
809
+ const snapshot = { ...progress, elapsedMs, estimatedRemainingMs };
810
+ const line = `gate shard progress: bundles ${progress.completedShards}/${progress.totalShards} · files ${progress.completedFiles}/${progress.totalFiles} · elapsed ${Math.round(elapsedMs / 1000)}s · remaining ~${estimatedRemainingMs === null ? '?' : Math.round(estimatedRemainingMs / 1000) + 's'}\n`;
811
+ try { (deps.writeProgressStderr ?? ((value) => { process.stderr.write(value); }))(line); } catch { /* observation only */ }
812
+ try { debug.log('gate.cli', 'shard-progress', snapshot); } catch { /* observation only */ }
813
+ if (!options.artifactDir?.trim()) return;
814
+ let temporary: string | undefined;
815
+ try {
816
+ const dir = resolveArtifactDir(options.artifactDir, cwd);
817
+ mkdirSync(dir, { recursive: true });
818
+ temporary = join(dir, `.progress.${process.pid}.${randomUUID()}.tmp`);
819
+ writeFileSync(temporary, `${JSON.stringify(snapshot, null, 2)}\n`);
820
+ renameSync(temporary, join(dir, 'progress.json'));
821
+ } catch { /* artifact failure must not affect the gate verdict */ }
822
+ finally { if (temporary) { try { rmSync(temporary, { force: true }); } catch { /* observation only */ } } }
823
+ };
824
+ }
825
+
773
826
  function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: SelfGateCliDeps, capture: GateArtifactCapture): SelfGateCliResult {
774
827
  if (options.base && options.pr) throw new Error('use either --base <ref> or --pr <number>, not both');
775
828
  if (options.shards !== undefined && (!Number.isSafeInteger(options.shards) || options.shards < 1)) throw new Error('invalid --shards count');
@@ -803,6 +856,9 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
803
856
  // 🚨 러너 우주 «밖» — 형제들과 같은 정책으로 «말만» 한다(`OBS-T418`).
804
857
  formatUnrunnableChangeKinds(selection.files),
805
858
  formatUnrunImporterTests(importerTestsNotRun, lookupFailed),
859
+ // ⛔⭐ 무인 리뷰 must-fix — 죽은 필드 배선: `resolveGateScope` 이 채운 `runtimeEdgeImpact` 을
860
+ // 실제로 읽어 출력하는 소비자(이 줄이 없으면 그 측정은 어디에도 드러나지 않는다).
861
+ formatUnlistedSpawnLaneTests(scope.runtimeEdgeImpact),
806
862
  `caller tests: ${lookupFailed ? `lookup failed (${lookupFailed})` : scope.callerTests.map(({ file, reasons }) => `${file} (${reasons.join('+')})`).join(', ') || (routeIndex?.lookupFailures.length ? 'route lookup incomplete' : '(none)')}`,
807
863
  ...(routeIndex?.lookupFailures.length ? [`⚠️ caller route base lookup failed — unmeasured: ${routeIndex.lookupFailures.map(({ source, reason }) => `${source} (${reason})`).join(', ')}`] : []),
808
864
  ...(callerTestsOverflow.length ? [`⚠️ caller test cap exceeded — not run: ${callerTestsOverflow.map(({ file, reasons }) => `${file} (${reasons.join('+')})`).join(', ')}`] : []),
@@ -854,9 +910,10 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
854
910
  const spawnFileCount = testFiles.filter(isGateSpawnLaneFile).length;
855
911
  const shardCount = options.shards ?? (Math.min(3, spawnFileCount) + Number(testFiles.length > spawnFileCount));
856
912
  const runShards = deps.runShards ?? runShardedGateTests;
913
+ const onShardComplete = shardProgressObserver(cwd, options, deps);
857
914
  const sharded = options.fixedShardDistribution
858
- ? runShards(cwd, testFiles, selection.baseRef, shardCount, undefined, undefined, undefined, { fixedDistribution: true })
859
- : runShards(cwd, testFiles, selection.baseRef, shardCount);
915
+ ? runShards(cwd, testFiles, selection.baseRef, shardCount, undefined, undefined, undefined, { fixedDistribution: true, onShardComplete })
916
+ : runShards(cwd, testFiles, selection.baseRef, shardCount, undefined, undefined, undefined, { onShardComplete });
860
917
  capture.sharded = sharded;
861
918
  capture.verdict = sharded.aggregate.status;
862
919
  lines.push(`shards: ${sharded.shards.length} (${sharded.shards.map((shard) => `${shard.id}=${shard.files.join(',')}`).join('; ')})${sharded.expandedFrom !== undefined ? ` · RSS 예산상 ${sharded.expandedFrom}→${sharded.shards.length} 자동 확장` : ''}${sharded.measurementFailures ? ` · 측정 실패 ${sharded.measurementFailures}` : ''}${options.fixedShardDistribution ? ' · 고정 분배(사전 측정 없음)' : ''}${sharded.distribution === 'fixed-cap-fallback' ? ` · 호스트 상한 자동 고정 분배(${sharded.fallbackReason})` : ''}`);
@@ -897,7 +954,15 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
897
954
  capture.unmeasuredReason = unmeasuredReason;
898
955
  }
899
956
  else if (aggregate.report) {
900
- const report = aggregate.report;
957
+ const report = recheckTimeoutOnlyIntroducedFailures(cwd, aggregate.report, deps.runTimeoutRecheck);
958
+ capture.timeoutRechecks = report.timeoutRechecks;
959
+ const timeoutRecheckResolvedFailure = aggregate.status === 'failed'
960
+ && (report.timeoutRecheckPassed ?? 0) > 0
961
+ && report.introduced === 0 && report.unknown === 0 && report.preconditionUnmet === 0
962
+ && report.timedOut === 0 && report.flakyRerun === 0 && report.worktreeFailuresParsed
963
+ && report.baselineStatus !== 'unknown';
964
+ const effectiveStatus = timeoutRecheckResolvedFailure ? 'passed' : aggregate.status;
965
+ capture.verdict = effectiveStatus;
901
966
  logGateCliBaseline(cwd, {
902
967
  introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown,
903
968
  preconditionUnmet: report.preconditionUnmet, timedOut: report.timedOut,
@@ -914,7 +979,7 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
914
979
  capture.verdictLine = lines[lines.length - 1];
915
980
  const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
916
981
  return {
917
- exitCode: aggregate.status !== 'passed' || !policyPassed || !androidPassed || !iosPassed || !pwaPassed || !expose.passed ? 1 : 0,
982
+ exitCode: capture.verdict !== 'passed' || !policyPassed || !androidPassed || !iosPassed || !pwaPassed || !expose.passed ? 1 : 0,
918
983
  lines, changedFiles: selection.files, testFiles, unverified: scope.unverified,
919
984
  documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests,
920
985
  alwaysIncludeMissing, importerTestsAdded, ...(shardBaseline ? { baseline: shardBaseline } : {}),
@@ -935,7 +1000,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
935
1000
 
936
1001
  if (worktreeLog.includes('deterministic environment setup failed')) lines.push(worktreeLog);
937
1002
  const baseline = (deps.runBaseline ?? runGateBaseline)(cwd, testFiles, selection.baseRef);
938
- const report = buildGateBaselineReport(worktreeLog, baseline);
1003
+ const report = recheckTimeoutOnlyIntroducedFailures(cwd, buildGateBaselineReport(worktreeLog, baseline), deps.runTimeoutRecheck);
1004
+ capture.timeoutRechecks = report.timeoutRechecks;
939
1005
  logGateCliBaseline(cwd, {
940
1006
  introduced: report.introduced,
941
1007
  preexisting: report.preexisting,
@@ -958,3 +1024,21 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
958
1024
  const exitCode = !androidPassed || !iosPassed || !pwaPassed || !policyPassed || !expose.passed || report.introduced > 0 || report.unknown > 0 || report.preconditionUnmet > 0 ? 1 : 0;
959
1025
  return { exitCode, lines, changedFiles: selection.files, testFiles, unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, importerTestsAdded, baseline: { introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown, preconditionUnmet: report.preconditionUnmet } };
960
1026
  }
1027
+
1028
+ /** GATE-REMOTE-SHARD-PLAN — a shard plan plus the ready-to-run remote command for each shard. */
1029
+ export interface RemoteGateShardPlan {
1030
+ orchestrationId: string;
1031
+ shards: GateRemoteShard[];
1032
+ commands: string[][];
1033
+ }
1034
+
1035
+ /** Turn a changed-file list into identity-carrying shards and their remote gate commands (shard-plan → shard-run wiring). */
1036
+ export function planRemoteGateShardCommands(
1037
+ files: readonly string[],
1038
+ shardCount: number,
1039
+ options?: { planFile?: string; orchestrationId?: string },
1040
+ ): RemoteGateShardPlan {
1041
+ const orchestrationId = options?.orchestrationId ?? shardPlanOrchestrationId(files);
1042
+ const shards = planGateRemoteShards(files, shardCount, orchestrationId);
1043
+ return { orchestrationId, shards, commands: shards.map((shard) => remoteShardArgv(shard, options)) };
1044
+ }
@@ -142,8 +142,9 @@ function hostSlotScriptWithSlot(cap: number, dir: string, tools: readonly SlotLo
142
142
  return [
143
143
  `GS=${quote(dir)}; mkdir -p "$GS" || infra slots`,
144
144
  `${pick}else infra lock-tool; fi`,
145
+ 'load1() { if [ -r /proc/loadavg ]; then awk \'NR==1 {print $1}\' /proc/loadavg; elif command -v sysctl >/dev/null 2>&1; then sysctl -n vm.loadavg 2>/dev/null | awk \'{gsub(/[{}]/, ""); print $1}\'; else echo unknown; fi; }',
145
146
  `n=1; while [ $n -le ${n} ]; do $GL "$GS/slot$n" ${passSlot ? 'env GATE_REMOTE_SLOT="$n" ' : ''}sh "$W/run.sh"; s=$?; [ -f "$W/started" ] && exit $s; n=$((n+1)); done`,
146
- `echo "${BUSY}=$((n-1))" >&2; exit 98`,
147
+ `echo "${BUSY}=$((n-1));load1=$(load1)" >&2; exit 98`,
147
148
  ];
148
149
  }
149
150
 
@@ -184,7 +185,7 @@ export const PUSH_TIMEOUT_MS = 10 * 60_000;
184
185
 
185
186
  export type RemoteRunOutcome =
186
187
  | { kind: 'ran'; rc: number; stdout: Buffer; stderr: Buffer; commit: string; host: string; ms: number }
187
- | { kind: 'busy'; occupied?: number; rc?: number }
188
+ | { kind: 'busy'; occupied?: number; load1?: number | null; rc?: number }
188
189
  | { kind: 'infra'; reason: string; stage?: string; rc?: number | null; stderr?: string };
189
190
 
190
191
  export interface RemoteRunOptions {
@@ -349,8 +350,10 @@ export function runOnRemote(opts: RemoteRunOptions, runner: GateRemoteRunner = r
349
350
  if (!(run.rc === 0 && marker >= 0)) {
350
351
  const last = stderrText.trimEnd().split('\n').at(-1) ?? '';
351
352
  if (run.rc === 98) {
352
- const busy = /^__GATE_REMOTE_BUSY(?:=(\d+))?$/.exec(last);
353
- if (busy) return { kind: 'busy', rc: run.rc, ...(busy[1] !== undefined ? { occupied: Number(busy[1]) } : {}) };
353
+ const busy = /^__GATE_REMOTE_BUSY(?:=(\d+))?(?:;load1=(unknown|\d+(?:\.\d+)?|))?$/.exec(last);
354
+ if (busy) return { kind: 'busy', rc: run.rc,
355
+ ...(busy[1] !== undefined ? { occupied: Number(busy[1]) } : {}),
356
+ ...(busy[2] !== undefined ? { load1: busy[2] === '' || busy[2] === 'unknown' ? null : Number(busy[2]) } : {}) };
354
357
  }
355
358
  if (run.rc === 97 && last.startsWith(INFRA)) return { kind: 'infra', stage: last.slice(INFRA.length).trim(), rc: run.rc, stderr: stderrText, reason: `remote-${last.slice(INFRA.length).trim()}` };
356
359
  }
@@ -459,6 +462,8 @@ export interface DispatchDeps {
459
462
  env?: NodeJS.ProcessEnv;
460
463
  sleep?: (ms: number) => Promise<void>;
461
464
  now?: () => number;
465
+ /** Test seam for gate.remote events; production defaults to the structured debug log. */
466
+ log?: (event: string, data: Record<string, unknown>) => void;
462
467
  write?: { out: (data: string | Uint8Array) => void; err: (data: string | Uint8Array) => void };
463
468
  }
464
469
 
@@ -531,6 +536,9 @@ export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDe
531
536
  const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
532
537
  const now = deps.now ?? Date.now;
533
538
  const deadline = now() + settings.slotWaitSeconds * 1000;
539
+ let waitStartedAt: number | undefined;
540
+ const logWait = deps.log ?? ((event: string, data: Record<string, unknown>) => debug.log('gate.remote', event, data));
541
+ let waitedForSlot = false;
534
542
  debug.log('gate.remote', 'dispatch', { tool: opts.tool, host, reason: decision.reason });
535
543
  let outcome: RemoteRunOutcome;
536
544
  for (;;) {
@@ -540,6 +548,14 @@ export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDe
540
548
  outcome = { kind: 'infra', reason: `exception: ${error instanceof Error ? error.message : String(error)}` };
541
549
  }
542
550
  if (outcome.kind !== 'busy') break;
551
+ waitedForSlot = true;
552
+ waitStartedAt ??= now();
553
+ const waitData = {
554
+ tool: opts.tool, host, reason: 'host-busy', load1: outcome.load1 ?? null, loadThreshold: settings.loadThreshold,
555
+ occupied: outcome.occupied ?? null, cap: hostCap, elapsedMs: Math.max(0, now() - waitStartedAt),
556
+ };
557
+ logWait('wait-reason', waitData);
558
+ write.err(`[gate.remote] waiting on ${host} — reason=host-busy load=${outcome.load1 ?? 'unknown'}/${settings.loadThreshold} slots=${outcome.occupied ?? 'unknown'}/${hostCap} elapsed=${Math.floor(waitData.elapsedMs / 1000)}s\n`);
543
559
  debug.log('gate.remote', 'host-busy', { tool: opts.tool, host, cap: hostCap, occupied: outcome.occupied ?? null });
544
560
  // Never start an attempt past the deadline: an expired self gate wait remains unmeasured.
545
561
  const left = deadline - now();
@@ -547,6 +563,14 @@ export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDe
547
563
  await sleep(Math.min(15_000, left));
548
564
  if (now() >= deadline) break;
549
565
  }
566
+ if (waitedForSlot) {
567
+ const resolution = outcome.kind === 'ran' ? 'slot-open' : outcome.kind === 'busy' ? 'deadline-slot-still-busy'
568
+ : `remote-infra: ${outcome.reason}`;
569
+ const waitData = { tool: opts.tool, host, reason: resolution, elapsedMs: Math.max(0, now() - waitStartedAt!),
570
+ ...(outcome.kind === 'busy' ? { occupied: outcome.occupied ?? null, cap: hostCap } : {}) };
571
+ logWait('wait-ended', waitData);
572
+ write.err(`[gate.remote] wait ended on ${host} — reason=${resolution} elapsed=${Math.floor(waitData.elapsedMs / 1000)}s${outcome.kind === 'busy' ? ` slots=${outcome.occupied ?? 'unknown'}/${hostCap}` : ''}\n`);
573
+ }
550
574
  if (opts.onRemoteOutcome) {
551
575
  try { opts.onRemoteOutcome(outcome, host, deps.runner ?? realGateRemoteRunner); }
552
576
  catch (error) { debug.log('gate.remote', 'outcome-hook-failed', { tool: opts.tool, host, error: error instanceof Error ? error.message : String(error) }); }