elanous 0.2.37 → 0.2.40

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 (727) 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/{8kITumG9GAZ1LwT9POrAR → HjeK7zONHfR7op1hKXp4k}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{1746.3563617ea64023a3.js → 1060.014f1f01a17aec26.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{9151.a2c51e93f9156dae.js → 1281.d81877e35b9068f4.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/1350.59f40e39e02d91b1.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1415.79821ec7ae99acdb.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1452.162bb2d9d699e82a.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/147.f92f63bbc5e85fa5.js +286 -0
  10. package/apps/pwa/out/_next/static/chunks/1537-6bb97b5214928ea9.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1661.fb425a1d8a065b72.js +149 -0
  12. package/apps/pwa/out/_next/static/chunks/1671-1c22b40b50b208f2.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1758.0204d3f48783c49d.js +90 -0
  14. package/apps/pwa/out/_next/static/chunks/1806.027bf78b6a94d340.js +104 -0
  15. package/apps/pwa/out/_next/static/chunks/{3578.4e9f9948a9a6f2f4.js → 2047.8f23e210995d4548.js} +2 -2
  16. package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{7424.c0fe2a595d4232b5.js → 2066.a77257c8c350770a.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/2096-a938496bc996dcbd.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{4931.95cc6dbd230774ca.js → 2177.df8547f9d7215c4e.js} +16 -16
  20. package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{6680.6a693c28aae4cd19.js → 2226.2cf61ec781827219.js} +2 -2
  22. package/apps/pwa/out/_next/static/chunks/2281-b8cede695c6c650e.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2499.02fbfd18126c10c0.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{6252.240578f10952e091.js → 2522.f2766b76d22c8bdf.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/{1262.a89bb27a5b2f844e.js → 2566.beaffc3a5e1fcd2e.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/261.0d471e8aded799f3.js +226 -0
  27. package/apps/pwa/out/_next/static/chunks/2615.3c9738153de3ef3f.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2727.e703d99ac414916d.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2752.7904b8df0254d0ae.js +27 -0
  30. package/apps/pwa/out/_next/static/chunks/2762-5051a862dfa40e99.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/2767-31784bfedf8e245d.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{2318-450e75d07605b8fe.js → 2774-719820e3f5b2a3eb.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{4725-34bed25720cc326b.js → 2829-734fe8bf2eee7347.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/311-32dcac79970985e8.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3175-f93f7495cd28253c.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3184.8da993f5502d2140.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3231-d7c981db0ff8bdcc.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3250.151309c5176d6b4b.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3330.7443183b7e6fdbdf.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3517.a5aa1797a9dbf2ee.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3567-45f676877ed9e8a5.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3746-f80a78f220bf37b5.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3819.8a1de79b2e8c7298.js +24 -0
  45. package/apps/pwa/out/_next/static/chunks/39.9b37b0be4c128a83.js +77 -0
  46. package/apps/pwa/out/_next/static/chunks/{4337e36d.f42c3b391b3d8f20.js → 3b355b3d.6f73c98bf6f9c749.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/4023.a19045970a9ce16a.js +36 -0
  48. package/apps/pwa/out/_next/static/chunks/{58edce7d.f1b0c72acf13b123.js → 409c787b.e48c5bec8ec10456.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/413-24c8284bda08241d.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4135.e45d6ebc29e20647.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4283.65502f5d0e6ff6c0.js +287 -0
  52. package/apps/pwa/out/_next/static/chunks/4305-4e28fa92a7b34a5b.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4335-50efa61fd7613142.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4351.0f37a6db2b34d50b.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{5046.7fd5cbd859299448.js → 470.51a72a2348306455.js} +2 -2
  56. package/apps/pwa/out/_next/static/chunks/4720.ecbd1693fa151068.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/{2375.bf364c85dbb6f085.js → 4769.9fd582071301f382.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/483.725e4a61be922788.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{de8446d3.31b73eb239fecd7b.js → 4864a2ca.1c1c280a7772c5e5.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/4969-4b209d7307410c00.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5068-c7f53862f83c0917.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5315.bc96711c24dfefe2.js +74 -0
  63. package/apps/pwa/out/_next/static/chunks/{4383.18e5c54db3a22c88.js → 5383.bdfa5d886e39a826.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/5436.fdf6fa8ae3e9588d.js +64 -0
  65. package/apps/pwa/out/_next/static/chunks/5542.efbf14f16baed4dd.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5622.94893f5aea7185d0.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5644.8f401a25601d05fc.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5658.35f70eb9871a54bf.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5721.7bdc0e904c76ab51.js +8 -0
  70. package/apps/pwa/out/_next/static/chunks/5790-eef0ca20884a6bdf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5802.ef0d8598ca68fe84.js +62 -0
  72. package/apps/pwa/out/_next/static/chunks/5890.fb974729788dcb71.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/5924.5ef25cddd36d5dbf.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/5979-e59c099ebf8d1f35.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/6020.714cfeada2315e2e.js +94 -0
  76. package/apps/pwa/out/_next/static/chunks/6027-dfe0349d8c50f698.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{6745-5a63492933959dd9.js → 6051-0ae955eedb10adb9.js} +3 -3
  78. package/apps/pwa/out/_next/static/chunks/6178.bc4730c86cf74536.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/{2283.edd9627b7bdfb546.js → 6257.c0037b8949239f5e.js} +2 -2
  80. package/apps/pwa/out/_next/static/chunks/6273.d808b0dcb3c2b155.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6292.6ef1df64fa6a4c8a.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/647-af8dd920ba46533c.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6541-170dc5c59e135c0c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6624.981ef7caeb680560.js +32 -0
  85. package/apps/pwa/out/_next/static/chunks/6742-a1ad4a94ba7bc37a.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/{6819.be5c9c4d67f22922.js → 6749.0744ce6eb08d40e9.js} +16 -16
  87. package/apps/pwa/out/_next/static/chunks/6836-493dc55c39187949.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/6856-53ac421c06039a18.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/6908.06008c67f6380ea9.js +148 -0
  90. package/apps/pwa/out/_next/static/chunks/6915.096931864206f522.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/6925.5e181fb7dcf90193.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/6cc1d1d6.9a98dd4622f1afc6.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7203-800e11037adc41eb.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7219-15bdd9a80661af8e.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7279.6170f591105936bb.js +93 -0
  96. package/apps/pwa/out/_next/static/chunks/7349-373165c7fbdcc3df.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7514-a533ba0ca1cae4f4.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7515.1ad6efe157fa4448.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/7521.d919cc1fab80c1d9.js +24 -0
  100. package/apps/pwa/out/_next/static/chunks/7538.90e97bbdf9178cff.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/7611.85f045bf232053ac.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/7825-39203196a12579b2.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/7869.5e1a9a12fd70d6c7.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8086.1ab9103c41be884f.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8099.1cccf31c1baa7e1c.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8179-e61fffbdb70f1152.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8265.bdeb991b34db6a06.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{2002-a43a3f380df873ec.js → 8272-025653884f9645d2.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/{7867.e8725745ddd1d940.js → 8357.1aaa713b052a78b1.js} +4 -4
  110. package/apps/pwa/out/_next/static/chunks/8638-e42615f2166165b5.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/8639-92c11d069792429e.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/8691.54e22831d5e8ccf8.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/8d173e38.18a2f7b4e1848bdb.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9069.657590a84afb8fac.js +41 -0
  115. package/apps/pwa/out/_next/static/chunks/9125-ae588d88a0293b93.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{4313.76f232c304a15bde.js → 9175.2de5209a5ce6f68a.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9184.45afbf44fec87574.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{8c58d09b.e8724a299658d86f.js → 9189505a.980427ac048c8c60.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9311.f9f641a46a508611.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9371-a6fee8378ebfa3ee.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9421-3aa9ff4fa7f63d8a.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9992.07ce73c10bd5e6a1.js +79 -0
  123. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76394dc618d322c8.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/approvals/page-1b948637c37b3abd.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-c63400f1bcf3e47c.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/board/page-95d0957267819586.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ba957ff875a026a0.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/bots/page-bb6fd0714879cb87.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8f9038520d2acbef.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/chat/page-d4b48397e05fce2c.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/consult/page-72d5744245dc0c27.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/control/page-37625dc8300fa43a.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/decisions/page-fbef9d160272dbc1.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/design-check/page-58424168df84928e.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/editor/page-72c12ba430ac57c0.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/exec/page-d53f3e9ed806d7e0.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/field/page-4d2fbd45feee0829.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76394dc618d322c8.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/inside/page-8783dc0ed7590a2c.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/intake/page-3706cb390606e930.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/layout-9b0a86598e0111fd.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live/{page-3337c6a1328c2674.js → page-4edb8df90f4537ce.js} +1 -1
  143. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83d27757e2b8060a.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/loops/page-47398b9ba1cc5e1b.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/market/page-fb86f55cfe2e681d.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e22345fc8fd47b1b.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/morning/{page-1e5da297557d2354.js → page-fca2e59a81744d9e.js} +1 -1
  148. package/apps/pwa/out/_next/static/chunks/app/not-found-6e96bda63100b31e.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/observatory/page-4d17ad8e0db8cea4.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-121f92766c33beaa.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-43f14212c545f92d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ccec2023e7a974ec.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/outputs/page-b04f33f548b89a94.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/page-c8792823c0917021.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/reflection/page-8c0e32782ceef4cb.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-94bd3922eb230ce8.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bca565887bafa03c.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ac1dffafe649fc6c.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/page-52374edb5e23e455.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ad4ebca120d43ca7.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76394dc618d322c8.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/page-718b89ce4b4ae4e4.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/share/page-204eca33eeeaddec.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/showroom/page-e58ba9bcdb9ac0f9.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/tasks/page-98f6dd50bafd7734.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/term/{page-ac2c1e6169cfce57.js → page-139d722de1dcd6c1.js} +1 -1
  167. package/apps/pwa/out/_next/static/chunks/app/today/page-5a4bdd72bff27057.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/trace/page-6f6ab17d44f984ce.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/vault/page-aabb7bd15fb72da9.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e4322319164a4436.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/page-e9efc0c8f32e2371.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-c1c80e345fa9d6f5.js → page-ccde99f07aaf71f7.js} +1 -1
  173. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{d9815f84.4918f682a45a8502.js → b84cad00.594027ebe0531fe2.js} +3 -3
  175. package/apps/pwa/out/_next/static/chunks/c696986b.5dc8bb1143af16d1.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/{709a918c.4fd3b4e2a32cb4e3.js → ca3702f8.2913182e73889fa2.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/d5d3cefc-373c4eb722ed848b.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/{5f6af561-f90b7a67f4f75d13.js → d8de0de2-dd0f4ac8e5ab1832.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/framework-002b472a66935d31.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-49b88d47292c0476.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/main-app-fff2549cb10a133f.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_app-32abbbba3f3b76b7.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/pages/_error-9d9cfef60c60dd7a.js +1 -0
  184. package/apps/pwa/out/_next/static/chunks/webpack-cc7f483fa294034a.js +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +22 -22
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +22 -22
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +22 -22
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +21 -21
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +21 -21
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +22 -22
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +21 -21
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +22 -22
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +22 -22
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +21 -21
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +22 -22
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +22 -22
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +22 -22
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +22 -22
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +21 -21
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +21 -21
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +22 -22
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +22 -22
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +22 -22
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +21 -21
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +21 -21
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +22 -22
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +22 -22
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +21 -21
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +21 -21
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +21 -21
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +22 -22
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +22 -22
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +21 -21
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +22 -22
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +22 -22
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +22 -22
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +22 -22
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +22 -22
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +21 -21
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +22 -22
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +22 -22
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +22 -22
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +22 -22
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +22 -22
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +22 -22
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +22 -22
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +22 -22
  278. package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
  279. package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
  280. package/graphs/demo/persona-marketer/recipes.yaml +19 -0
  281. package/graphs/release/recipes.yaml +9 -0
  282. package/graphs/release/release-loop.yaml +26 -18
  283. package/graphs/video/explainer-line.yaml +4 -1
  284. package/package.json +1 -1
  285. package/scripts/ask-op-inbox-once.ts +17 -0
  286. package/scripts/brand/check.ts +13 -4
  287. package/scripts/dead-code/report.ts +169 -0
  288. package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
  289. package/scripts/gate-0226-failure-census.ts +39 -0
  290. package/scripts/intake-collect-telegram-saved-stage.ts +48 -0
  291. package/scripts/lib/morning-report-options.ts +3 -4
  292. package/scripts/lib/tui-regress-evidence.ts +56 -0
  293. package/scripts/morning-report.ts +5 -1
  294. package/scripts/provision-export-redactions.ts +15 -0
  295. package/scripts/public-copy-lint.ts +122 -0
  296. package/scripts/public-export.ts +77 -2
  297. package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
  298. package/scripts/ratchets/train-side-invariants.sh +7 -1
  299. package/scripts/release-loop/cut-branch.ts +61 -12
  300. package/scripts/release-loop/export-check-node.ts +21 -3
  301. package/scripts/release-loop/gate-node.ts +527 -60
  302. package/scripts/release-loop/gate-partial.ts +82 -3
  303. package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
  304. package/scripts/release-loop/gate-radius-live.ts +4 -2
  305. package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
  306. package/scripts/release-loop/gate-shard-receipts.ts +89 -0
  307. package/scripts/release-loop/gate-wall.ts +5 -5
  308. package/scripts/release-loop/preflight.ts +6 -2
  309. package/scripts/release-loop/resume-cap.ts +2 -1
  310. package/scripts/release-loop/resume-release.ts +317 -13
  311. package/scripts/release-loop/resume.ts +61 -5
  312. package/scripts/release-loop/traffic-node.ts +12 -4
  313. package/scripts/release-loop/traffic-transition.ts +53 -13
  314. package/scripts/release-loop/version-node.ts +35 -5
  315. package/scripts/release-story/draft.ts +1 -1
  316. package/scripts/research-bench/README.md +53 -0
  317. package/scripts/research-bench/questions.json +66 -0
  318. package/scripts/research-bench/rubric.md +33 -0
  319. package/scripts/research-bench/run.ts +523 -0
  320. package/scripts/tui-regress.ts +85 -10
  321. package/scripts/ux-sim.ts +1 -1
  322. package/scripts/video-pipeline.ts +2 -2
  323. package/src/acp/core-turn-bridge.ts +14 -1
  324. package/src/agent/autonomous-tools.ts +10 -3
  325. package/src/agent/monad-agent-turn.ts +4 -1
  326. package/src/agent/registry.ts +26 -2
  327. package/src/agent/run-context.ts +1 -1
  328. package/src/agent/shared-app-tools.ts +1 -1
  329. package/src/agent/surface-ux/build.ts +12 -3
  330. package/src/agent/surface-ux/types.ts +1 -1
  331. package/src/agent/task-notification.ts +78 -7
  332. package/src/agent/types.ts +3 -0
  333. package/src/agent-mission/driver.ts +29 -3
  334. package/src/agent-mission/mission-cli.ts +2 -1
  335. package/src/agent-substrate/review-context-pack.ts +365 -0
  336. package/src/agent-substrate/review-observation.ts +10 -0
  337. package/src/agent-substrate/self-review-cli.ts +419 -42
  338. package/src/ask-user-question/index.ts +6 -0
  339. package/src/ask-user-question/inline-resolver.ts +49 -0
  340. package/src/auto-research/question-ladder-contract.ts +156 -0
  341. package/src/auto-research/research-turn.ts +467 -0
  342. package/src/autopilot/agent-loop.ts +1 -1
  343. package/src/autopilot/discovery/doc-lint.ts +1 -1
  344. package/src/autopilot/pty-control-loop.ts +8 -1
  345. package/src/boot/daemon-tools/index.ts +4 -3
  346. package/src/boot/daemon-tools/self-implement.ts +270 -2
  347. package/src/boot/daemon-tools/types.ts +2 -0
  348. package/src/bots/screen-probe.ts +1 -1
  349. package/src/budget/llm-cost.ts +44 -5
  350. package/src/budget/unified-usage.ts +17 -1
  351. package/src/capture/tui-self-report.ts +24 -2
  352. package/src/chat/index.ts +34 -7
  353. package/src/chat/tool-render/dispatch.ts +8 -1
  354. package/src/cli/agent-cli.ts +43 -8
  355. package/src/cli/guardian-cli.ts +3 -1
  356. package/src/cli/intake-cli.ts +70 -13
  357. package/src/cli/lesson-cli.ts +86 -10
  358. package/src/cli/log-event-names.ts +1 -0
  359. package/src/cli/pod-cli.ts +17 -2
  360. package/src/cli/pr-land-overlap-evidence.ts +38 -5
  361. package/src/cli/pr-land-refusal.ts +1 -1
  362. package/src/cli/pty-takeover-cli.ts +125 -12
  363. package/src/cli/release-checklist-read-cli.ts +5 -2
  364. package/src/cli/release-cli.ts +99 -15
  365. package/src/cli/repo-cli.ts +2 -1
  366. package/src/cli/review-carry.ts +77 -0
  367. package/src/cli/self-update.ts +1 -1
  368. package/src/cli/tasks-card-show.ts +31 -1
  369. package/src/cli/tasks-cli.ts +98 -32
  370. package/src/cli/tasks-read-cli.ts +13 -5
  371. package/src/context-bus/context-now.ts +86 -2
  372. package/src/control-plane/ledger.ts +21 -4
  373. package/src/core-turn/run-core-turn.ts +51 -3
  374. package/src/core-turn/run-goal-loop.ts +152 -8
  375. package/src/core-turn/types.ts +12 -0
  376. package/src/dashboard/chat/acp-chat.ts +2 -2
  377. package/src/dashboard/classic-sigquit.ts +16 -0
  378. package/src/dashboard/index.ts +339 -44
  379. package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
  380. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
  381. package/src/dashboard/input/chat-main-slash-command.ts +7 -0
  382. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  383. package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
  384. package/src/dashboard/input/external-input-host.ts +2 -0
  385. package/src/dashboard/input/terminal-modal-router.ts +8 -159
  386. package/src/dashboard/side-basic-runtime.ts +61 -0
  387. package/src/dashboard/sidetab-runtime.ts +228 -0
  388. package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
  389. package/src/dashboard/slash-runtime/dashboard-handlers.ts +22 -8
  390. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
  391. package/src/dashboard/term-slash-runtime.ts +18 -18
  392. package/src/dashboard/turn-preamble.ts +30 -4
  393. package/src/domains/guardian-tick.ts +9 -0
  394. package/src/domains/knowledge.ts +1 -1
  395. package/src/esc-abort-gate.ts +33 -1
  396. package/src/execution-loop/launch-gate.ts +206 -1
  397. package/src/git-fs/watcher.ts +27 -22
  398. package/src/git-fs/worktree.ts +19 -3
  399. package/src/graph-runner/graph-cli.ts +6 -4
  400. package/src/graph-runner/graph-grow.ts +37 -9
  401. package/src/graph-runner/runner.ts +48 -11
  402. package/src/graph-wizard/generate.ts +16 -7
  403. package/src/graph-wizard/mission-compose.ts +201 -0
  404. package/src/grok/agent-search.ts +8 -2
  405. package/src/grok/credential.ts +112 -36
  406. package/src/grounding/ref-index.ts +11 -0
  407. package/src/grounding/ref-vector.ts +61 -0
  408. package/src/grounding/sources-cli.ts +2 -2
  409. package/src/grounding/sources.ts +15 -1
  410. package/src/harness/harness-cli-command.ts +38 -9
  411. package/src/harness/harness-pod-dispatch.ts +7 -1
  412. package/src/hq/fence-wrapper.ts +1 -1
  413. package/src/hq/transfer.ts +1 -1
  414. package/src/index.ts +60 -16
  415. package/src/input/external-input-queue.ts +10 -0
  416. package/src/intake-plane/collect-telegram-saved.ts +90 -6
  417. package/src/intake-plane/intake-to-tasks.ts +246 -3
  418. package/src/interactive-terminal-modal.ts +3 -0
  419. package/src/keybindings.ts +17 -22
  420. package/src/lessons/friction-ledger.ts +154 -0
  421. package/src/live-supply/collector.ts +149 -0
  422. package/src/live-supply/probes.ts +52 -0
  423. package/src/live-supply/snapshot.ts +40 -0
  424. package/src/llm/provider-credentials.ts +1 -1
  425. package/src/llm-tool-schema.ts +20 -0
  426. package/src/llm.ts +486 -61
  427. package/src/loops/orchestrator/inbox-once.ts +28 -0
  428. package/src/loops/orchestrator/inbox.ts +130 -1
  429. package/src/loops/orchestrator/tick.ts +14 -3
  430. package/src/maturity/feature-maturity.ts +1 -0
  431. package/src/nexus/api/channel-ask-op.ts +96 -0
  432. package/src/nexus/api/discord-trigger-bot.ts +28 -1
  433. package/src/nexus/api/harness-api.ts +2 -1
  434. package/src/nexus/api/telegram-trigger-bot.ts +24 -0
  435. package/src/nexus/api/terminals.ts +28 -6
  436. package/src/patents/ledger.ts +18 -1
  437. package/src/preview/terminal.ts +4 -2
  438. package/src/prompt-cache/anthropic.ts +2 -0
  439. package/src/prompt-enhance/enhance.ts +5 -0
  440. package/src/pty/snapshot.py +132 -0
  441. package/src/pty-shell/pty-control-ipc.ts +29 -2
  442. package/src/pty-shell/pty-manifest.ts +75 -5
  443. package/src/pty-shell/registry.ts +2 -0
  444. package/src/pty-shell/tui-run-state.ts +80 -3
  445. package/src/release-loop/gate-host-reservation.ts +13 -4
  446. package/src/release-loop/gate-shard-ledger.ts +68 -0
  447. package/src/release-loop/gate-shards.ts +61 -0
  448. package/src/release-loop/light-rc.ts +7 -4
  449. package/src/release-loop/merged-pr-checklist.ts +25 -2
  450. package/src/release-loop/rehearsal-shard-plan.ts +6 -1
  451. package/src/release-loop/rehearsal.ts +28 -1
  452. package/src/repl/index.ts +10 -0
  453. package/src/research/axis-fanout.ts +133 -0
  454. package/src/research/edge-decision.ts +197 -0
  455. package/src/research/gap-followup.ts +249 -0
  456. package/src/research/lenses/counter-evidence.ts +100 -0
  457. package/src/research/lenses/working-backwards.ts +89 -0
  458. package/src/research/output-router.ts +127 -0
  459. package/src/research/plugin-discovery.ts +242 -0
  460. package/src/research-bridge/format.ts +16 -1
  461. package/src/research-bridge/index.ts +1 -0
  462. package/src/research-bridge/invoke.ts +45 -7
  463. package/src/research-bridge/types.ts +2 -0
  464. package/src/self-dev/ask-launch-flow.ts +34 -106
  465. package/src/self-dev/decompose.ts +45 -9
  466. package/src/self-dev/dev-cli.ts +2 -0
  467. package/src/self-dev/dev-pipeline.ts +8 -4
  468. package/src/self-dev/draft-residue.ts +221 -2
  469. package/src/self-dev/draft-sweep.ts +29 -16
  470. package/src/self-dev/graph-journey-route.ts +10 -2
  471. package/src/self-dev/launch-preflight-text.ts +2 -2
  472. package/src/self-dev/launch-preflight.ts +38 -7
  473. package/src/self-dev/orchestrate-cli.ts +1 -0
  474. package/src/self-dev/orchestrate.ts +1 -0
  475. package/src/self-dev/run-supervisor.ts +41 -7
  476. package/src/self-dev/shard-run.ts +260 -3
  477. package/src/self-implement/comment-only-source.ts +54 -0
  478. package/src/self-implement/device-first.ts +8 -2
  479. package/src/self-implement/doctor-visit.ts +100 -57
  480. package/src/self-implement/gate-artifacts.ts +5 -2
  481. package/src/self-implement/gate-baseline.ts +119 -13
  482. package/src/self-implement/gate-cli.ts +466 -93
  483. package/src/self-implement/gate-failure-signature.ts +44 -0
  484. package/src/self-implement/gate-receipt-registry.ts +180 -0
  485. package/src/self-implement/gate-remote.ts +147 -22
  486. package/src/self-implement/goal-author-clarification.ts +178 -24
  487. package/src/self-implement/goal-author-decompose.ts +24 -15
  488. package/src/self-implement/goal-author.ts +82 -7
  489. package/src/self-implement/goal-doc/section.ts +22 -0
  490. package/src/self-implement/goal-supervisor-fill.ts +38 -4
  491. package/src/self-implement/host-regate.ts +120 -45
  492. package/src/self-implement/impl-findings-feedback.ts +188 -0
  493. package/src/self-implement/knowhow-pack.ts +301 -9
  494. package/src/self-implement/l8-merge-queue.ts +198 -32
  495. package/src/self-implement/off-diff-evidence.ts +147 -0
  496. package/src/self-implement/orchestrator.ts +137 -16
  497. package/src/self-implement/pod-inplace-worktree.ts +82 -0
  498. package/src/self-implement/pod-warm-pool-profile.ts +2 -2
  499. package/src/self-implement/premise-review.ts +7 -5
  500. package/src/self-implement/run-ledger.ts +304 -8
  501. package/src/self-implement/run-stop.ts +12 -0
  502. package/src/self-implement/seams.ts +39 -13
  503. package/src/self-implement/self-implement-cli.ts +30 -4
  504. package/src/session/channel-ask-op-envelope.ts +36 -0
  505. package/src/session/channel-op-reply-route.ts +200 -0
  506. package/src/session/chat.ts +92 -15
  507. package/src/session/index.ts +2 -0
  508. package/src/session-runtime/index.ts +9 -22
  509. package/src/session-runtime/provider-circuit.ts +140 -0
  510. package/src/shell-runner/file-engine.ts +1 -0
  511. package/src/shell-runner/types.ts +4 -0
  512. package/src/sidetab-core/model.ts +176 -0
  513. package/src/skills/runner.ts +7 -3
  514. package/src/skills/tools/dev-harness.ts +2 -2
  515. package/src/skills/tools/schedule-wakeup.ts +24 -7
  516. package/src/skills/tools/shell.ts +51 -5
  517. package/src/status/bar.ts +3 -3
  518. package/src/steward/directive-audit.ts +354 -0
  519. package/src/storage/file-lock.ts +17 -4
  520. package/src/surface/child-process.ts +31 -0
  521. package/src/surface/tui-stderr-owner.ts +48 -0
  522. package/src/task-agent/adopt-pr.ts +63 -2
  523. package/src/task-agent/cover.ts +30 -12
  524. package/src/task-agent/evidence-command-normalize.ts +42 -0
  525. package/src/task-agent/export-redactions-provision.ts +43 -0
  526. package/src/task-agent/judge.ts +56 -0
  527. package/src/task-agent/parent-host.ts +59 -12
  528. package/src/task-agent/postland-card.ts +35 -2
  529. package/src/task-agent/rejudge-on-head.ts +46 -2
  530. package/src/task-agent/repair-cycle.ts +68 -9
  531. package/src/task-agent/repair-worker.ts +37 -1
  532. package/src/task-agent/task-hand.ts +226 -33
  533. package/src/task-agent/tier-split.ts +142 -24
  534. package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
  535. package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
  536. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +57 -5
  537. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
  538. package/src/task-orchestrator/surfaces/pod-pool.ts +27 -4
  539. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
  540. package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
  541. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
  542. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
  543. package/src/task-orchestrator/surfaces/self-implement-pod.ts +310 -79
  544. package/src/task-orchestrator/surfaces/self-implement.ts +33 -2
  545. package/src/terminal/session-registry.ts +1 -0
  546. package/src/terminal/terminal-modal-router.ts +156 -0
  547. package/src/tool-hints/gate.ts +6 -4
  548. package/src/tool-hints/signals.ts +33 -1
  549. package/src/tool-runtime/skill-exec-runtime.ts +95 -5
  550. package/src/tui/chat/background-job-status.ts +8 -2
  551. package/src/tui/entry.ts +483 -32
  552. package/src/tui/inline-choice.ts +188 -0
  553. package/src/tui/sidetab/attach.ts +304 -0
  554. package/src/tui/sidetab/list.ts +2 -0
  555. package/src/tui/sidetab/nl-tool.ts +136 -0
  556. package/src/tui/slash/resume-command.ts +23 -0
  557. package/src/tui/slash/resume.ts +3 -23
  558. package/src/tui/slash/term-next.ts +2 -1
  559. package/src/tui/slash/term.ts +12 -1
  560. package/src/tui-client/dashboard-session.ts +7 -1
  561. package/src/tui-client/local-chat-turn.ts +29 -8
  562. package/src/user-config.ts +42 -3
  563. package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
  564. package/src/ux-sim/fake-land-queue.ts +88 -0
  565. package/src/ux-sim/fake-llm.ts +11 -5
  566. package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
  567. package/src/ux-sim/goal-interim-trace.ts +24 -0
  568. package/src/ux-sim/next-tui-seat-scenarios.ts +61 -14
  569. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
  570. package/src/version/packed-revision.json +1 -1
  571. package/src/video-pipeline/recipes/explainer.ts +54 -2
  572. package/src/web-search/grok.ts +32 -6
  573. package/src/web-search/index.ts +8 -7
  574. package/src/workflow-runtime/node-catalog.ts +53 -4
  575. package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +0 -62
  579. package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +0 -32
  587. package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +0 -148
  590. package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +0 -27
  594. package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/3199.6a1a9b0e6cd01dc6.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +0 -36
  601. package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +0 -90
  603. package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +0 -226
  604. package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +0 -287
  605. package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +0 -24
  612. package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +0 -104
  615. package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +0 -93
  622. package/apps/pwa/out/_next/static/chunks/5952.294fc574a8625184.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +0 -74
  624. package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +0 -149
  627. package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +0 -41
  631. package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +0 -24
  634. package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/7c5ed21f-f286708e57cf88f7.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +0 -8
  647. package/apps/pwa/out/_next/static/chunks/8080-40d781e7704d3671.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +0 -77
  649. package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +0 -286
  652. package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +0 -79
  656. package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +0 -94
  664. package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +0 -64
  666. package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-88a1edbff62eaf1d.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +0 -1
  725. package/scripts/migrate-monad-to-elanous.ts +0 -195
  726. package/scripts/rebrand-elanous.ts +0 -242
  727. /package/apps/pwa/out/_next/static/{8kITumG9GAZ1LwT9POrAR → HjeK7zONHfR7op1hKXp4k}/_ssgManifest.js +0 -0
@@ -0,0 +1,44 @@
1
+ import { createHash } from 'node:crypto';
2
+ import type { SelfImplementGateResult } from './orchestrator.js';
3
+
4
+ export interface GateFailureReceipt {
5
+ signature: `sha256:${string}`;
6
+ tests: string[];
7
+ }
8
+
9
+ /** Only measured, introduced, non-timeout test failures are stable enough to stop a repeated repair. */
10
+ export function gateFailureReceipt(gate: SelfImplementGateResult | undefined): GateFailureReceipt | null {
11
+ if (!gate || gate.passed || gate.testStepExecuted !== true || !gate.baselineFailures
12
+ || !gate.reflectGateFacts || gate.reflectGateFacts.unknown !== 0
13
+ || (gate.reflectGateFacts.timedOut ?? 0) > 0 || (gate.reflectGateFacts.rerunNotRun ?? 0) > 0
14
+ || (gate.reflectGateFacts.mayVaryNonTimeout ?? 0) > 0) return null;
15
+ const introduced = gate.baselineFailures.filter((failure) => failure.attribution === 'introduced');
16
+ if (!introduced.length || introduced.length !== gate.reflectGateFacts.introduced) return null;
17
+ const normalized: Array<{ file: string; name: string; kind: string }> = [];
18
+ for (const failure of introduced) {
19
+ const file = failure.file?.replace(/\\/g, '/').trim();
20
+ const name = failure.name.normalize('NFC').replace(/\s+/g, ' ').trim();
21
+ if (!file || file.startsWith('/') || /^[A-Za-z]:\//.test(file) || file.split('/').includes('..')
22
+ || !name || /[\r\n]/.test(name)
23
+ || failure.timeoutRegression || /\btimed out\b|\btimeout\b/i.test(failure.diagnostic ?? '')) return null;
24
+ const diagnostic = failure.diagnostic ?? '';
25
+ const kind = /module not found|cannot find module|ERR_MODULE_NOT_FOUND/i.test(diagnostic) ? 'module-load'
26
+ : /expect\(|AssertionError|Expected:/i.test(diagnostic) ? 'assertion'
27
+ : /\berror:/i.test(diagnostic) ? 'runtime-error' : 'test-failure';
28
+ normalized.push({ file, name, kind });
29
+ }
30
+ normalized.sort((a, b) => {
31
+ const left = JSON.stringify(a);
32
+ const right = JSON.stringify(b);
33
+ return left < right ? -1 : left > right ? 1 : 0;
34
+ });
35
+ const unique = [...new Map(normalized.map((entry) => [JSON.stringify(entry), entry])).values()];
36
+ if (unique.length !== introduced.length) return null;
37
+ const signature = `sha256:${createHash('sha256').update(JSON.stringify(unique)).digest('hex')}` as const;
38
+ return { signature, tests: unique.map(({ file, name, kind }) => `${file} > ${name} (${kind})`) };
39
+ }
40
+
41
+ /** The worker reads these exact lines from harness stdout and persists the receipt. */
42
+ export function gateFailureReceiptLines(receipt: GateFailureReceipt): string[] {
43
+ return [`GATE_FAILURE_SIGNATURE=${receipt.signature}`, `GATE_FAILURE_TESTS=${JSON.stringify(receipt.tests)}`];
44
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * GATE-ONCE-PER-HEAD (0.2.40 첫 조각 · OP 10-27 23:0x 지시) — host-regate 통과 영수증의 지속 등록부.
3
+ *
4
+ * S: 같은 PR head 의 자식 gate 뒤 host-regate 와 착지 게이트가 같은 시험을 다시 실행해 Pod 와 호스트 자원을 소모한다.
5
+ * C: 통과 사실이 어디에도 남지 않아 매 호출이 전 검사를 다시 돌릴 수밖에 없다.
6
+ * Q: 정확히 같은 통합 입력과 측정 범위에 대해 이미 통과한 게이트만 승계할 수 있는가?
7
+ * A: 통과 영수증을 이 등록부에 원자적으로 기록하고, runHostRegate 가 재검증·통합 후보 구성 뒤 현재 key 와
8
+ * 일치하는 통과 영수증만 승계한다. 불일치·결손·불완전·실패/측정불가 영수증은 원래 검사를 실행한다.
9
+ *
10
+ * 원본 영수증 없이 통과 판정 금지: 승계는 저장된 영수증 행 하나를 통해서만 일어나고, 그 행의 key 는
11
+ * 행 스스로의 필드에서 다시 계산되어야 한다(gateReceiptSelfKey). key 가 필드와 맞지 않는 행은 저장도
12
+ * 승계도 거절한다.
13
+ *
14
+ * 원자성: saveGateReceipts 는 임시 파일에 온전히 쓴 뒤 rename(2) 로 바꾼다 — 부분 쓰기는 관측될 수 없다.
15
+ * 프로세스끼리의 동시 저장은 각자 온전한 등록부를 남긴다(늦은 쪽이 이긴다). 잃은 영수증은 다음 호출을
16
+ * 원래 검사로 되돌릴 뿐, 잘못된 통과를 만들지 않는다 — 실패 방향으로 열린다.
17
+ */
18
+ import { createHash, randomUUID } from 'node:crypto';
19
+ import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
20
+ import { basename, dirname, join } from 'node:path';
21
+ import { gateTestBaseline } from '../../scripts/lib/gate-test-env.js';
22
+
23
+ export const GATE_RECEIPT_SCHEMA = 1;
24
+ export type GateReceiptVerdict = 'passed' | 'failed' | 'unmeasured';
25
+
26
+ const SHA40 = /^[0-9a-f]{40}$/i;
27
+ const SHA256 = /^[0-9a-f]{64}$/i;
28
+
29
+ /** 한 번의 host-regate 측정을 정체 짓는 입력. 판정(verdict)은 identity 가 아니라 key 계산에 들어간다. */
30
+ export interface GateReceiptIdentity {
31
+ /** 40자 PR head SHA */
32
+ headCommit: string;
33
+ /** 40자 실제 측정 base SHA — PR 에 기록된 baseRefOid 가 아니라 얹어 잰 끝 */
34
+ baseCommit: string;
35
+ /** 검사를 실행한 Bun 식별값(bun --version) */
36
+ bunVersion: string;
37
+ /** 검사가 설치·실행한 lockfile 의 SHA-256(bun.lock/bun.lockb 바이트) — 없으면 'absent' */
38
+ lockfileHash: string;
39
+ /** 정규화된 radius 파일 집합(병합 후보 기준 변경 파일 — 중복 제거·정렬) */
40
+ radiusFiles: readonly string[];
41
+ /** 이 영수증이 통과한 검사 토큰(종류 ⊕ 측정 범위 — 중복 제거·정렬) */
42
+ checks: readonly string[];
43
+ /** 실행 환경 지문(gateEnvFingerprint) */
44
+ envFingerprint: string;
45
+ }
46
+
47
+ export interface GateReceipt extends GateReceiptIdentity {
48
+ schema: typeof GATE_RECEIPT_SCHEMA;
49
+ key: string;
50
+ verdict: GateReceiptVerdict;
51
+ savedAt: string;
52
+ }
53
+
54
+ export type GateReceiptRegistry = Record<string, GateReceipt>;
55
+
56
+ /**
57
+ * 검사 종류·판정·환경까지 포함한 정준 직렬화의 SHA-256. 같은 측정·같은 판정만 같은 key 를 받는다.
58
+ * head/base 는 40자 hex 여야 한다 — 그보다 못한 입력으로 영수증을 만들 수 없게 문을 닫는다.
59
+ */
60
+ export function computeReceiptKey(identity: GateReceiptIdentity, verdict: GateReceiptVerdict): string {
61
+ if (!SHA40.test(identity.headCommit)) throw new Error('gate receipt head SHA is not 40 hex characters');
62
+ if (!SHA40.test(identity.baseCommit)) throw new Error('gate receipt base SHA is not 40 hex characters');
63
+ const canonical = JSON.stringify({
64
+ schema: GATE_RECEIPT_SCHEMA,
65
+ head: identity.headCommit.toLowerCase(),
66
+ base: identity.baseCommit.toLowerCase(),
67
+ bun: identity.bunVersion,
68
+ lockfile: identity.lockfileHash,
69
+ radius: [...new Set(identity.radiusFiles)].sort(),
70
+ checks: [...new Set(identity.checks)].sort(),
71
+ env: identity.envFingerprint,
72
+ verdict,
73
+ });
74
+ return createHash('sha256').update(canonical).digest('hex');
75
+ }
76
+
77
+ /** 행의 key 를 행 스스로의 필드에서 다시 계산한다 — 위조·불일치 행은 저장된 key 와 어긋난다. */
78
+ export function gateReceiptSelfKey(receipt: GateReceipt): string {
79
+ return computeReceiptKey(receipt, receipt.verdict);
80
+ }
81
+
82
+ function isGateReceipt(value: unknown): value is GateReceipt {
83
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
84
+ const row = value as Partial<GateReceipt>;
85
+ return row.schema === GATE_RECEIPT_SCHEMA && typeof row.key === 'string' && SHA256.test(row.key)
86
+ && (row.verdict === 'passed' || row.verdict === 'failed' || row.verdict === 'unmeasured')
87
+ && SHA40.test(row.headCommit ?? '') && SHA40.test(row.baseCommit ?? '')
88
+ && typeof row.bunVersion === 'string' && typeof row.lockfileHash === 'string'
89
+ && Array.isArray(row.radiusFiles) && row.radiusFiles.every((file) => typeof file === 'string')
90
+ && Array.isArray(row.checks) && row.checks.every((check) => typeof check === 'string')
91
+ && typeof row.envFingerprint === 'string' && typeof row.savedAt === 'string';
92
+ }
93
+
94
+ /**
95
+ * 결손·손상 파일은 빈 등록부로 복구한다 — 못 읽은 영수증은 «없다» 로 취급해 원래 검사를 실행한다.
96
+ * 모양이 어긋나거나 행의 key 가 맵 키와 다른 행은 버린다.
97
+ */
98
+ export function loadGateReceipts(path: string): GateReceiptRegistry {
99
+ let raw: string;
100
+ try { raw = readFileSync(path, 'utf8'); }
101
+ catch { return {}; }
102
+ let parsed: unknown;
103
+ try { parsed = JSON.parse(raw); }
104
+ catch { return {}; }
105
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
106
+ const registry: GateReceiptRegistry = {};
107
+ for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {
108
+ if (!isGateReceipt(value) || value.key !== key) continue;
109
+ registry[key] = value;
110
+ }
111
+ return registry;
112
+ }
113
+
114
+ /** write-then-rename 원자적 기록 — 부분 쓰기 노출 금지. 임시 파일은 같은 디렉터리에 무작위 이름으로 둔다. */
115
+ export function saveGateReceipts(path: string, registry: GateReceiptRegistry): void {
116
+ mkdirSync(dirname(path), { recursive: true });
117
+ const tmp = join(dirname(path), `.${basename(path)}.${process.pid}.${randomUUID()}.tmp`);
118
+ writeFileSync(tmp, `${JSON.stringify(registry, null, 2)}\n`);
119
+ try { renameSync(tmp, path); }
120
+ catch (error) {
121
+ try { unlinkSync(tmp); } catch { /* 최선의 정리 — 원래 오류를 지운다 */ }
122
+ throw error;
123
+ }
124
+ }
125
+
126
+ /** 통과 영수증을 지속 등록부에 원자적으로 병합 기록한다. key 가 필드와 맞지 않는 행은 쓰기 단계에서 거절한다. */
127
+ export function saveGateReceipt(path: string, receipt: GateReceipt): void {
128
+ if (gateReceiptSelfKey(receipt) !== receipt.key) throw new Error('gate receipt key does not match its own fields');
129
+ const registry = loadGateReceipts(path);
130
+ registry[receipt.key] = receipt;
131
+ saveGateReceipts(path, registry);
132
+ }
133
+
134
+ /**
135
+ * 승계 거절 사유. 불일치(head/base/env/Bun·lockfile/radius)·결손·불완전(현재 측정 범위 미커버)·
136
+ * 실패/측정불가 판정을 가려 한 줄로 남긴다 — debug.log 의 decline 이유가 된다.
137
+ */
138
+ export function describeGateReceiptDecline(probe: GateReceiptIdentity, registry: GateReceiptRegistry): string {
139
+ const receipts = Object.values(registry);
140
+ if (!receipts.length) return 'gate receipt registry empty';
141
+ const sameHeadBase = receipts.filter((receipt) => receipt.headCommit.toLowerCase() === probe.headCommit.toLowerCase()
142
+ && receipt.baseCommit.toLowerCase() === probe.baseCommit.toLowerCase());
143
+ if (!sameHeadBase.length) return `no receipt for head ${probe.headCommit.slice(0, 12)} base ${probe.baseCommit.slice(0, 12)}`;
144
+ for (const receipt of sameHeadBase) {
145
+ const differs: string[] = [];
146
+ if (receipt.verdict !== 'passed') differs.push(`verdict=${receipt.verdict}`);
147
+ if (receipt.envFingerprint !== probe.envFingerprint) differs.push('env fingerprint differs');
148
+ if (receipt.bunVersion !== probe.bunVersion || receipt.lockfileHash !== probe.lockfileHash) differs.push('bun/lockfile differs');
149
+ if ([...new Set(receipt.radiusFiles)].sort().join('\n') !== [...new Set(probe.radiusFiles)].sort().join('\n')) differs.push('changed-file radius differs');
150
+ const current = [...new Set(probe.checks)].sort();
151
+ const stored = [...new Set(receipt.checks)].sort();
152
+ if (stored.join('\n') !== current.join('\n')) {
153
+ const missing = current.filter((check) => !stored.includes(check));
154
+ differs.push(missing.length && stored.every((check) => current.includes(check))
155
+ ? `receipt does not cover: ${missing.join(',')}`
156
+ : `receipt checks differ (stored ${stored.join(',')})`);
157
+ }
158
+ if (differs.length) return `receipt ${receipt.key.slice(0, 12)} ${differs.join(' · ')}`;
159
+ }
160
+ return 'no stored receipt matches this measurement key';
161
+ }
162
+
163
+ /** 실행 환경 지문: 플랫폼 ⊕ 게이트 시험 baseline(TZ·locale·fake-LLM 스위치)의 정준 직렬화 SHA-256. */
164
+ export function gateEnvFingerprint(env: NodeJS.ProcessEnv): string {
165
+ const baseline = gateTestBaseline(env);
166
+ const canonical = JSON.stringify({
167
+ platform: process.platform,
168
+ env: Object.fromEntries(Object.entries(baseline).sort(([a], [b]) => a.localeCompare(b))),
169
+ });
170
+ return createHash('sha256').update(canonical).digest('hex');
171
+ }
172
+
173
+ /** 후보 워크트리가 실제로 설치·실행한 lockfile 의 SHA-256. 둘 다 없으면 'absent'. */
174
+ export function gateLockfileHash(worktree: string): string {
175
+ for (const name of ['bun.lock', 'bun.lockb']) {
176
+ if (!existsSync(join(worktree, name))) continue;
177
+ return createHash('sha256').update(readFileSync(join(worktree, name))).digest('hex');
178
+ }
179
+ return 'absent';
180
+ }
@@ -94,16 +94,20 @@ export function remoteSelfGateArgv(input: {
94
94
  changed?: boolean;
95
95
  base?: string;
96
96
  shards?: number;
97
+ shardConcurrency?: number;
97
98
  fixedShardDistribution?: boolean;
98
99
  includeImporters?: boolean;
100
+ noInherit?: boolean;
99
101
  artifactDir?: string;
100
102
  }, sha: (ref: string) => string): string[] {
101
103
  const shards = input.shards ?? (input.includeImporters ? 2 : undefined);
102
104
  return ['bun', 'bin/elanous.mjs', 'self', 'gate', '--local', ...(input.changed ? ['--changed'] : []),
103
105
  ...(input.base ? ['--base', input.base === 'origin/main' ? input.base : sha(input.base)] : []),
104
106
  ...(shards !== undefined ? ['--shards', String(shards)] : []),
107
+ ...(input.shardConcurrency !== undefined ? ['--shard-concurrency', String(input.shardConcurrency)] : []),
105
108
  ...(input.fixedShardDistribution ? ['--fixed-shard-distribution'] : []),
106
109
  ...(input.includeImporters ? ['--include-importers'] : []),
110
+ ...(input.noInherit ? ['--no-inherit'] : []),
107
111
  ...(input.artifactDir ? ['--artifact-dir', input.artifactDir] : [])];
108
112
  }
109
113
 
@@ -129,6 +133,8 @@ export function decideGateDispatch(input: { flags: Pick<GateRemoteFlags, 'remote
129
133
 
130
134
  export const SLOT_DIR = '/tmp/elanous-gate-remote-slots';
131
135
  const BUSY = '__GATE_REMOTE_BUSY';
136
+ const HEARTBEAT = '__GATE_REMOTE_HEARTBEAT=';
137
+ const REMOTE_RUN_LIMIT_SECONDS = 105 * 60;
132
138
 
133
139
  /** Shell lines that run "$W/run.sh" under the first free of `cap` slot locks, or print the busy marker and exit 98.
134
140
  * run.sh must create "$W/started" first: that is how a lock refusal is told apart from the run's own exit code. */
@@ -136,14 +142,14 @@ export type SlotLockTool = 'flock' | 'lockf';
136
142
  const SLOT_LOCK = { flock: 'flock -n', lockf: 'lockf -k -s -t 0' } as const;
137
143
 
138
144
  /** `tools` is the preference order (default: Linux flock, then BSD/macOS lockf); a test can pin one path. */
139
- function hostSlotScriptWithSlot(cap: number, dir: string, tools: readonly SlotLockTool[], passSlot: boolean): string[] {
145
+ function hostSlotScriptWithSlot(cap: number, dir: string, tools: readonly SlotLockTool[], passSlot: boolean, supervised = false): string[] {
140
146
  const n = Math.min(MAX_HOST_CAP, Math.max(1, Math.floor(cap)));
141
147
  const pick = tools.map((tool, i) => `${i ? 'elif' : 'if'} command -v ${tool} >/dev/null 2>&1; then GL="${SLOT_LOCK[tool]}"; `).join('');
142
148
  return [
143
149
  `GS=${quote(dir)}; mkdir -p "$GS" || infra slots`,
144
150
  `${pick}else infra lock-tool; fi`,
145
151
  '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; }',
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`,
152
+ `n=1; while [ $n -le ${n} ]; do $GL "$GS/slot$n" ${passSlot ? 'env GATE_REMOTE_SLOT="$n" ' : ''}sh "$W/${supervised ? 'supervise.sh' : 'run.sh'}"; s=$?; ${supervised ? '[ -f "$W/supervisor-timeout" ] && infra run-timeout; [ -f "$W/supervisor-infra" ] && infra supervisor-lost; ' : ''}[ -f "$W/started" ] && exit $s; n=$((n+1)); done`,
147
153
  `echo "${BUSY}=$((n-1));load1=$(load1)" >&2; exit 98`,
148
154
  ];
149
155
  }
@@ -152,6 +158,53 @@ export function hostSlotScript(cap: number, dir = SLOT_DIR, tools: readonly Slot
152
158
  return hostSlotScriptWithSlot(cap, dir, tools, false);
153
159
  }
154
160
 
161
+ /** A slot holder owns exactly one new process group. On a lost SSH shell or wall limit it signals only that group,
162
+ * after checking its unreaped direct child's PGID. The heartbeat also detects a severed SSH output pipe while
163
+ * a silent test is running; runOnRemote removes only these transport lines from the tool's stderr. */
164
+ export function remoteSupervisorScript(limitSeconds = REMOTE_RUN_LIMIT_SECONDS): string {
165
+ const limit = Number.isSafeInteger(limitSeconds) && limitSeconds > 0 ? limitSeconds : REMOTE_RUN_LIMIT_SECONDS;
166
+ return [
167
+ '#!/bin/sh',
168
+ 'child=',
169
+ 'ready=0',
170
+ 'owned_group() {',
171
+ ' [ -n "$child" ] && kill -0 "$child" 2>/dev/null && [ "$(ps -p "$child" -o pgid= 2>/dev/null | tr -d " ")" = "$child" ] || return 1',
172
+ '}',
173
+ 'reap() {',
174
+ // Our direct child stays unreaped until the caller waits, so its PID/PGID cannot be reused here.
175
+ ' [ "$ready" -eq 1 ] && owned_group || return 0',
176
+ ' kill -TERM -- "-$child" 2>/dev/null || kill -TERM "-$child" 2>/dev/null || :',
177
+ ' sleep 2',
178
+ // The leader remains our unreaped child until the caller waits, so its PGID cannot be reused here. A TERM-ignoring
179
+ // grandchild may outlive the leader; rechecking only the leader would miss that member of the same owned group.
180
+ ' kill -KILL -- "-$child" 2>/dev/null || kill -KILL "-$child" 2>/dev/null || :',
181
+ '}',
182
+ 'trap \'reap\' HUP INT TERM EXIT',
183
+ 'perl -MPOSIX -e \'POSIX::setpgid(0,0) == 0 or die "setpgid: $!"; exec @ARGV\' sh "$W/run.sh" &',
184
+ 'child=$!',
185
+ // Set this only after spawning the worker so the worker keeps its normal SIGPIPE behavior.
186
+ 'trap \'\' PIPE',
187
+ // The SSH parent can disappear before the child has called setpgid. Wait briefly for the ownership proof first.
188
+ 'ready=0; attempt=0',
189
+ 'while [ "$attempt" -lt 20 ] && kill -0 "$child" 2>/dev/null; do',
190
+ ' if owned_group; then ready=1; break; fi',
191
+ ' attempt=$((attempt+1)); sleep 1',
192
+ 'done',
193
+ 'if [ "$ready" -eq 0 ] && kill -0 "$child" 2>/dev/null; then kill -TERM "$child" 2>/dev/null || :; wait "$child" 2>/dev/null || :; : > "$W/supervisor-infra"; exit 125; fi',
194
+ 'started=$(date +%s)',
195
+ 'while kill -0 "$child" 2>/dev/null; do',
196
+ ' if [ "$(($(date +%s) - started))" -ge ' + limit + ' ]; then reap; wait "$child" 2>/dev/null || :; : > "$W/supervisor-timeout"; exit 124; fi',
197
+ ' if ! kill -0 "$GATE_REMOTE_SSH_SHELL" 2>/dev/null; then reap; wait "$child" 2>/dev/null || :; : > "$W/supervisor-infra"; exit 125; fi',
198
+ ' if ! printf "\\n' + HEARTBEAT + '%s\\n" "$W" >&2; then reap; wait "$child" 2>/dev/null || :; : > "$W/supervisor-infra"; exit 125; fi',
199
+ ' sleep 5',
200
+ 'done',
201
+ 'wait "$child"; rc=$?',
202
+ 'trap - HUP INT TERM EXIT',
203
+ 'exit "$rc"',
204
+ '',
205
+ ].join('\n');
206
+ }
207
+
155
208
  // ── remote execution ───────────────────────────────────────────────
156
209
 
157
210
  export interface ExecResult { rc: number | null; stdout: string; stderr: string; error?: string }
@@ -215,7 +268,7 @@ export interface PayloadFile { env: string; content: string }
215
268
  export type RemoteArgv = string[] | ((sha: (ref: string) => string) => string[]);
216
269
 
217
270
  /** Build the remote shell script (exported for tests). Every setup failure ends in an INFRA marker, the tool's rc in an RC marker. */
218
- export function remoteScript(input: { mirror: string; commit: string; fetchShas: string[]; mainSha?: string; argv: string[]; installPwa: boolean; stableCheckout?: boolean; payloadFiles?: PayloadFile[]; hostCap?: number; slotDir?: string }): string {
271
+ export function remoteScript(input: { mirror: string; commit: string; fetchShas: string[]; mainSha?: string; argv: string[]; installPwa: boolean; stableCheckout?: boolean; payloadFiles?: PayloadFile[]; hostCap?: number; slotDir?: string; runLimitSeconds?: number }): string {
219
272
  const mirror = input.mirror.startsWith('~/') ? `"$HOME"/${quote(input.mirror.slice(2))}` : quote(input.mirror);
220
273
  const fetches = input.fetchShas.map((sha) => `refs/elanous/gate/${sha}:refs/elanous/gate/${sha}`).join(' ');
221
274
  const payloads = (input.payloadFiles ?? []).filter((file) => /^[A-Z_][A-Z0-9_]*$/.test(file.env));
@@ -278,11 +331,16 @@ export function remoteScript(input: { mirror: string; commit: string; fetchShas:
278
331
  'W=$(mktemp -d /var/tmp/elanous-gate-remote-XXXXXXXX) || infra mktemp',
279
332
  'export W',
280
333
  'trap \'rm -rf "$W"\' EXIT',
334
+ 'command -v perl >/dev/null 2>&1 && command -v ps >/dev/null 2>&1 || infra supervisor-tool',
335
+ 'GATE_REMOTE_SSH_SHELL=$$; export GATE_REMOTE_SSH_SHELL',
281
336
  ...payloadLines,
282
337
  `cat > "$W/run.sh" <<'${RUN}' || infra run-script`,
283
338
  ...work,
284
339
  RUN,
285
- ...hostSlotScriptWithSlot(input.hostCap ?? GATE_REMOTE_DEFAULTS.hostCap, input.slotDir ?? SLOT_DIR, ['flock', 'lockf'], !!input.stableCheckout),
340
+ 'cat > "$W/supervise.sh" <<\'__GATE_REMOTE_SUPERVISE__\' || infra supervise-script',
341
+ remoteSupervisorScript(input.runLimitSeconds),
342
+ '__GATE_REMOTE_SUPERVISE__',
343
+ ...hostSlotScriptWithSlot(input.hostCap ?? GATE_REMOTE_DEFAULTS.hostCap, input.slotDir ?? SLOT_DIR, ['flock', 'lockf'], !!input.stableCheckout, true),
286
344
  '}',
287
345
  '',
288
346
  ].join('\n');
@@ -338,11 +396,22 @@ export function runOnRemote(opts: RemoteRunOptions, runner: GateRemoteRunner = r
338
396
  env: { ...process.env, GIT_SSH_COMMAND: 'ssh -o BatchMode=yes -o ConnectTimeout=10', GIT_TERMINAL_PROMPT: '0' },
339
397
  });
340
398
  if (push.rc !== 0 || push.error) return { kind: 'infra', stage: 'push', rc: push.rc, stderr: push.stderr || push.error || '', reason: `push-failed rc=${push.rc}: ${(push.stderr || push.error || '').trim().split('\n').slice(-2).join(' | ')}` };
341
- const script = remoteScript({ mirror: opts.mirror, commit, fetchShas: shas, mainSha, argv, installPwa: opts.installPwa ?? false, stableCheckout: opts.stableCheckout, payloadFiles: opts.payloadFiles, hostCap: opts.hostCap, slotDir: opts.slotDir });
342
- const run = runner.ssh(opts.host, script, opts.timeoutMs ?? 120 * 60_000);
399
+ const sshTimeoutMs = opts.timeoutMs ?? 120 * 60_000;
400
+ const script = remoteScript({ mirror: opts.mirror, commit, fetchShas: shas, mainSha, argv, installPwa: opts.installPwa ?? false, stableCheckout: opts.stableCheckout, payloadFiles: opts.payloadFiles, hostCap: opts.hostCap, slotDir: opts.slotDir,
401
+ runLimitSeconds: Math.min(REMOTE_RUN_LIMIT_SECONDS, Math.max(1, Math.floor((sshTimeoutMs - 30_000) / 1000))) });
402
+ const run = runner.ssh(opts.host, script, sshTimeoutMs);
343
403
  // The script prints "\n<marker><rc>\n": everything before that leading newline is the tool's own stderr, byte for byte.
344
404
  const stdoutBytes = Buffer.from(run.stdout);
345
- const stderrBytes = Buffer.from(run.stderr);
405
+ const rawStderr = Buffer.from(run.stderr);
406
+ // Transport heartbeats may arrive after the RC marker when a short run races the supervisor's final poll.
407
+ // Strip only complete, run-scoped heartbeat lines as bytes so arbitrary tool stderr stays byte-identical.
408
+ const heartbeatLine = /\n__GATE_REMOTE_HEARTBEAT=\/var\/tmp\/elanous-gate-remote-[A-Za-z0-9]+\n/g;
409
+ const heartbeatRanges = [...rawStderr.toString('latin1').matchAll(heartbeatLine)].map((match) => [match.index!, match.index! + match[0].length] as const);
410
+ let previous = 0;
411
+ const kept: Buffer[] = [];
412
+ for (const [from, to] of heartbeatRanges) { kept.push(rawStderr.subarray(previous, from)); previous = to; }
413
+ kept.push(rawStderr.subarray(previous));
414
+ const stderrBytes = Buffer.concat(kept);
346
415
  const stderrText = stderrBytes.toString('utf8');
347
416
  const marker = stderrBytes.lastIndexOf(Buffer.from(`\n${RC}`));
348
417
  // Busy (98) and setup failure (97) are the script's own exits, each with its marker as the last stderr line. A completed
@@ -448,6 +517,11 @@ export interface DispatchOptions {
448
517
  reportRemoteHost?: boolean;
449
518
  /** Release gate host reservations shared by self gate and changed typecheck. */
450
519
  reservationRoot?: string;
520
+ /** Self gate only: hosts to try when the first host holds a release reservation (default: `host-e-wsl` for
521
+ * `node-b`, the same alternative the unmeasured hint names — a reservation is never a local fallback). */
522
+ reservationAltHosts?: string[];
523
+ /** Self gate only: bounded wait for the reservation release, in seconds (default: `settings.slotWaitSeconds`). */
524
+ reservationWaitSeconds?: number;
451
525
  runLocal: () => number | Promise<number>;
452
526
  /** Called once with the final remote outcome (never on a local decision), before its output passes through or the
453
527
  * local fallback runs — e.g. `self gate --artifact-dir` fetches (ran) or removes (infra) the host-side artifact dir.
@@ -467,6 +541,26 @@ export interface DispatchDeps {
467
541
  write?: { out: (data: string | Uint8Array) => void; err: (data: string | Uint8Array) => void };
468
542
  }
469
543
 
544
+ /** Hosts a reserved self gate may fall back to: an explicit list wins, otherwise `node-b` (the only host the old
545
+ * unmeasured hint named an alternative for) falls back to `host-e-wsl`. Invalid or duplicate entries are dropped. */
546
+ export function gateReservationAlternateHosts(reservedHost: string, explicit?: string[]): string[] {
547
+ const candidates = explicit ?? (reservedHost === 'node-b' ? ['host-e-wsl'] : []);
548
+ const seen = new Set<string>([reservedHost]);
549
+ const hosts: string[] = [];
550
+ for (const candidate of candidates) {
551
+ if (!candidate || seen.has(candidate) || !isValidGateHost(candidate)) continue;
552
+ seen.add(candidate);
553
+ hosts.push(candidate);
554
+ }
555
+ return hosts;
556
+ }
557
+
558
+ /** Reservation diagnostics stamp — ISO 시각 printed next to the claim owner (runId). Claims written before
559
+ * `reservedAt` existed fall back to the gate's own observation time. */
560
+ export function formatReservationStamp(ms: number): string {
561
+ return new Date(ms).toISOString();
562
+ }
563
+
470
564
  async function loadSettings(): Promise<GateRemoteSettings> {
471
565
  try {
472
566
  const { getUserConfig } = await import('../user-config.js');
@@ -496,26 +590,59 @@ export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDe
496
590
  return opts.runLocal();
497
591
  }
498
592
  let host = decision.host!;
593
+ const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
594
+ const now = deps.now ?? Date.now;
499
595
  const reservationRoot = opts.tool === 'self-gate' || opts.tool === 'ci-typecheck-changed'
500
596
  ? opts.reservationRoot ?? (deps.runner ? undefined : gateHostReservationRoot()) : undefined;
501
597
  if (reservationRoot) {
502
598
  const reservationHost = host.split('@').at(-1)!;
503
599
  const first = inspectReleaseGateHost(reservationRoot, reservationHost);
504
600
  if (first.status !== 'free') {
505
- // Changed typecheck has a fixed node-b placement; a release reservation makes it unmeasured.
506
- const alternate = opts.tool === 'self-gate' && reservationHost === 'node-b' ? 'node-c' : null;
507
- const other = alternate ? inspectReleaseGateHost(reservationRoot, alternate) : null;
508
- if (alternate && other?.status === 'free') {
509
- debug.log('gate.remote', 'host-reserved-reroute', { from: host, to: alternate, reason: first.reason, status: first.status });
510
- write.err(`[gate.remote] ${host} reserved (${first.reason}) — using ${alternate}\n`);
511
- host = alternate;
601
+ // A reserved host is never a reason to run this check locally (반증: 예약 상태에서 --local 무거운 시험 금지).
602
+ // Self gate first tries another remote host, then waits bounded for the release, then ends unmeasured with
603
+ // the owner and the observation stamp.
604
+ const observedAt = formatReservationStamp(now());
605
+ const owner = first.runId || 'unknown';
606
+ // Owner (runId) plus 시각: the claim's own reservedAt when recorded, else the moment this gate observed it.
607
+ const stamp = first.reservedAt !== undefined
608
+ ? `reserved-at=${formatReservationStamp(first.reservedAt)}`
609
+ : `observed-at=${observedAt}`;
610
+ const alternates = opts.tool === 'self-gate'
611
+ ? gateReservationAlternateHosts(reservationHost, opts.reservationAltHosts) : [];
612
+ const alternate = alternates.find((candidate) => inspectReleaseGateHost(reservationRoot, candidate).status === 'free');
613
+ if (alternate) {
614
+ const rerouted = host.includes('@') ? `${host.slice(0, host.lastIndexOf('@'))}@${alternate}` : alternate;
615
+ debug.log('gate.remote', 'host-reserved-reroute', { tool: opts.tool, from: host, to: rerouted, owner, reason: first.reason, reservedAt: first.reservedAt, observedAt });
616
+ write.err(`[gate.remote] host-reserved: ${host} (${first.reason}) owner=${owner} ${stamp} — rerouting to ${rerouted}\n`);
617
+ host = rerouted;
512
618
  } else {
513
- const reason = `host-reserved: ${host} (${first.reason}); alternate ${alternate ?? '(none)'} ${other?.status ?? 'unavailable'}`;
514
- debug.log('gate.remote', 'host-reserved-unmeasured', { host, reason });
515
- write.err(opts.tool === 'self-gate'
516
- ? `[gate.remote] remote unmeasured on ${host} (stage=host-reserved, rc=unknown) — ${reason}\n`
517
- : `[gate.remote] remote unmeasured — ${reason}\n`);
518
- return 1;
619
+ const waitSeconds = opts.tool === 'self-gate' ? opts.reservationWaitSeconds ?? settings.slotWaitSeconds : 0;
620
+ const waitStart = now();
621
+ const deadline = waitStart + Math.max(0, waitSeconds) * 1000;
622
+ let latest = inspectReleaseGateHost(reservationRoot, reservationHost);
623
+ while (waitSeconds > 0 && latest.status !== 'free') {
624
+ const left = deadline - now();
625
+ if (left <= 0) break;
626
+ write.err(`[gate.remote] waiting for host-reserved release on ${host} — owner=${owner} ${stamp} elapsed=${Math.floor(Math.max(0, now() - waitStart) / 1000)}s/${waitSeconds}s\n`);
627
+ const before = now();
628
+ await sleep(Math.min(15_000, left));
629
+ if (now() <= before) break; // a frozen test clock must not spin past the bound
630
+ latest = inspectReleaseGateHost(reservationRoot, reservationHost);
631
+ }
632
+ const waitedMs = Math.max(0, now() - waitStart);
633
+ if (latest.status === 'free') {
634
+ debug.log('gate.remote', 'host-reserved-released', { tool: opts.tool, host, owner, waitedMs });
635
+ write.err(`[gate.remote] host-reserved released on ${host} after ${Math.floor(waitedMs / 1000)}s — proceeding remotely\n`);
636
+ } else {
637
+ const reason = `host-reserved: ${host} (${latest.reason})`;
638
+ const manualAlternative = reservationHost === 'node-b'
639
+ ? '; if available, non-PWA checks may explicitly select --remote host-e-wsl' : '';
640
+ debug.log('gate.remote', 'host-reserved-unmeasured', { host, reason, owner, reservedAt: latest.reservedAt ?? first.reservedAt, observedAt, waitedMs, alternates: alternates.length });
641
+ write.err(opts.tool === 'self-gate'
642
+ ? `[gate.remote] remote unmeasured on ${host} (stage=host-reserved, rc=unknown) — ${reason}; owner=${owner} ${stamp} waited=${Math.floor(waitedMs / 1000)}s${manualAlternative}\n`
643
+ : `[gate.remote] remote unmeasured — ${reason}\n`);
644
+ return 1;
645
+ }
519
646
  }
520
647
  }
521
648
  }
@@ -533,8 +660,6 @@ export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDe
533
660
  };
534
661
  if (opts.localOnlyReason) return fallback(opts.localOnlyReason, { stage: 'reproducibility', rc: null });
535
662
  const hostCap = gateRemoteHostCap(settings, host);
536
- const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
537
- const now = deps.now ?? Date.now;
538
663
  const deadline = now() + settings.slotWaitSeconds * 1000;
539
664
  let waitStartedAt: number | undefined;
540
665
  const logWait = deps.log ?? ((event: string, data: Record<string, unknown>) => debug.log('gate.remote', event, data));