elanous 0.2.38 → 0.2.41

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 (712) hide show
  1. package/README.md +7 -7
  2. package/apps/pwa/out/404/index.html +1 -1
  3. package/apps/pwa/out/404.html +1 -1
  4. package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → GiOLWmt4MqDZePubBjA4Q}/_buildManifest.js +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1115.434ae2ecb0ad986d.js +149 -0
  6. package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +36 -0
  7. package/apps/pwa/out/_next/static/chunks/1178.1aa9cad0e7695427.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1197-54da59d250a6e476.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{5203.51e5d8b5f1dcfe53.js → 1219.7e17964e0e7cd8e5.js} +3 -3
  10. package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +287 -0
  11. package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1661.0dd330f3d89f73f3.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +90 -0
  16. package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{7573.2376e13c9c21f1f8.js → 1765.679b29625c8e88d4.js} +2 -2
  18. package/apps/pwa/out/_next/static/chunks/{3528.e4b8ab70d339f965.js → 1800.f7ff51dc4978a958.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/1971-7efb628c471dc5a0.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2073.689dcb2680113d76.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{8879.ac06755bcf3e44a1.js → 2263.e09b6edea33bad2d.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2527-5c636a43c7cc5dde.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2743.5d3f76948be32b34.js +41 -0
  31. package/apps/pwa/out/_next/static/chunks/2773.0e80b9d325fb5635.js +32 -0
  32. package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{9fe1b809.738da85c8b17e3fb.js → 2fdf2931.b431eee4fb468bc3.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/{eaad0cba.771200940c529df7.js → 2fe2c302.41b517f88d6fe502.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/3097.864e92bdaa2f4d15.js +79 -0
  36. package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3230-49298c3b73ef2268.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +74 -0
  41. package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{b7478fef.5917716286213fcc.js → 385e4574.e9886ab32759eda3.js} +3 -3
  46. package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4133.2056bb4d78f621af.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4156.ba4de4a3664f04b4.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +148 -0
  53. package/apps/pwa/out/_next/static/chunks/{8911.bf5e712acb25fb6c.js → 4527.a69f2894d1bc9f4a.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +226 -0
  55. package/apps/pwa/out/_next/static/chunks/{5307.d7328020227880c2.js → 4667.97e31aa38c95c475.js} +4 -4
  56. package/apps/pwa/out/_next/static/chunks/{6142.913b44e260a3f925.js → 4702.4a4adc1f16d7c93b.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +94 -0
  64. package/apps/pwa/out/_next/static/chunks/{8487.291666583bebe640.js → 5159.115f1c2ca471386c.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/530.d26346e18089640a.js +115 -0
  67. package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +8 -0
  68. package/apps/pwa/out/_next/static/chunks/{89d6c04f-6b8ab341748e468a.js → 53aeb4ee-51c92f8d683f5220.js} +1 -1
  69. package/apps/pwa/out/_next/static/chunks/{3291.f6c1005387d514bd.js → 5471.1e611302ed3a7c53.js} +2 -2
  70. package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/{3086.fb14b60ce98b53d3.js → 5574.f35accf4f132b29d.js} +1 -1
  73. package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +24 -0
  74. package/apps/pwa/out/_next/static/chunks/{1632.7d87f998e714bede.js → 5744.b9415e18ad623100.js} +1 -1
  75. package/apps/pwa/out/_next/static/chunks/{5300.677c97e0393742e6.js → 5892.2526d962339662d8.js} +1 -1
  76. package/apps/pwa/out/_next/static/chunks/5937.c2df9e3447e1f667.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +286 -0
  78. package/apps/pwa/out/_next/static/chunks/{7161-8f22db3ec5ed005e.js → 5947-135e26537d80a6b9.js} +3 -3
  79. package/apps/pwa/out/_next/static/chunks/{3124-561f7f037943cde2.js → 5964-7e21164a8f2cf0ce.js} +1 -1
  80. package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +27 -0
  84. package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/6552.a3840aa7da35ad68.js +62 -0
  86. package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +24 -0
  87. package/apps/pwa/out/_next/static/chunks/6874.d5cf7eb8edb2cabe.js +2 -0
  88. package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +122 -0
  90. package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{2415.738b777642a02233.js → 7191.fdc955f7d96064a4.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{1026-44010f405704050c.js → 8050-9b364bdef8f71927.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/83184dcd-0ee6247ff41eb3f2.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +104 -0
  103. package/apps/pwa/out/_next/static/chunks/8464-e24f10451b658aac.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8880.64c445592f04acaf.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8981.c706964c8ba27aff.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{5638.107314dc479e2f37.js → 9048.212083de42d25be3.js} +2 -2
  110. package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{8019.21ca554a821dad01.js → 9507.7026657a2f47eb64.js} +16 -16
  117. package/apps/pwa/out/_next/static/chunks/9541.eb8e2f8480c7feca.js +93 -0
  118. package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9579.4a8169600fff2058.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +34 -0
  123. package/apps/pwa/out/_next/static/chunks/{6493.27ad77de7aac7966.js → 9834.63ab2bbc3153172e.js} +1 -1
  124. package/apps/pwa/out/_next/static/chunks/{3389.012c70767a872f9b.js → 9869.81a1e24ca682d5a0.js} +1 -1
  125. package/apps/pwa/out/_next/static/chunks/{8994d93e.33ba491f95345fc2.js → a0a01613.6d1cca322238d7fe.js} +1 -1
  126. package/apps/pwa/out/_next/static/chunks/{de8b930d.d94c0f42acf807fc.js → addc2b32.8c4ff8f0aefe987d.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-866aac5ff226a7f3.js → page-14949db884bfa672.js} +1 -1
  132. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-40f9e19149024298.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a142dfb0331a05f5.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/b2271e54.c1de3347976e90b0.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/{b7459770.6539b11860eb8a9c.js → c0c1a699.0ba79f97005965d4.js} +7 -7
  180. package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +1 -0
  184. package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +1 -0
  185. package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +1 -0
  186. package/apps/pwa/out/approvals/index.html +1 -1
  187. package/apps/pwa/out/approvals/index.txt +22 -22
  188. package/apps/pwa/out/autopilot/index.html +1 -1
  189. package/apps/pwa/out/autopilot/index.txt +22 -22
  190. package/apps/pwa/out/board/index.html +1 -1
  191. package/apps/pwa/out/board/index.txt +22 -22
  192. package/apps/pwa/out/botlab/index.html +1 -1
  193. package/apps/pwa/out/botlab/index.txt +21 -21
  194. package/apps/pwa/out/bots/index.html +1 -1
  195. package/apps/pwa/out/bots/index.txt +21 -21
  196. package/apps/pwa/out/ceo/index.html +1 -1
  197. package/apps/pwa/out/ceo/index.txt +22 -22
  198. package/apps/pwa/out/chat/index.html +1 -1
  199. package/apps/pwa/out/chat/index.txt +21 -21
  200. package/apps/pwa/out/consult/index.html +1 -1
  201. package/apps/pwa/out/consult/index.txt +22 -22
  202. package/apps/pwa/out/control/index.html +1 -1
  203. package/apps/pwa/out/control/index.txt +22 -22
  204. package/apps/pwa/out/decisions/index.html +1 -1
  205. package/apps/pwa/out/decisions/index.txt +21 -21
  206. package/apps/pwa/out/design-check/index.html +1 -1
  207. package/apps/pwa/out/design-check/index.txt +22 -22
  208. package/apps/pwa/out/editor/index.html +1 -1
  209. package/apps/pwa/out/editor/index.txt +22 -22
  210. package/apps/pwa/out/exec/index.html +1 -1
  211. package/apps/pwa/out/exec/index.txt +22 -22
  212. package/apps/pwa/out/field/index.html +1 -1
  213. package/apps/pwa/out/field/index.txt +22 -22
  214. package/apps/pwa/out/healthz +1 -1
  215. package/apps/pwa/out/index.html +1 -1
  216. package/apps/pwa/out/index.txt +21 -21
  217. package/apps/pwa/out/inside/index.html +1 -1
  218. package/apps/pwa/out/inside/index.txt +21 -21
  219. package/apps/pwa/out/intake/index.html +1 -1
  220. package/apps/pwa/out/intake/index.txt +22 -22
  221. package/apps/pwa/out/live/index.html +1 -1
  222. package/apps/pwa/out/live/index.txt +22 -22
  223. package/apps/pwa/out/live-run/index.html +1 -1
  224. package/apps/pwa/out/live-run/index.txt +22 -22
  225. package/apps/pwa/out/loops/index.html +1 -1
  226. package/apps/pwa/out/loops/index.txt +21 -21
  227. package/apps/pwa/out/market/index.html +1 -1
  228. package/apps/pwa/out/market/index.txt +21 -21
  229. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  230. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  231. package/apps/pwa/out/morning/index.html +1 -1
  232. package/apps/pwa/out/morning/index.txt +22 -22
  233. package/apps/pwa/out/observatory/index.html +1 -1
  234. package/apps/pwa/out/observatory/index.txt +22 -22
  235. package/apps/pwa/out/ops/checklist/index.html +1 -1
  236. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  237. package/apps/pwa/out/ops/release/index.html +1 -1
  238. package/apps/pwa/out/ops/release/index.txt +21 -21
  239. package/apps/pwa/out/ops/seats/index.html +1 -1
  240. package/apps/pwa/out/ops/seats/index.txt +21 -21
  241. package/apps/pwa/out/outputs/index.html +1 -1
  242. package/apps/pwa/out/outputs/index.txt +21 -21
  243. package/apps/pwa/out/reflection/index.html +1 -1
  244. package/apps/pwa/out/reflection/index.txt +22 -22
  245. package/apps/pwa/out/scheduler/index.html +1 -1
  246. package/apps/pwa/out/scheduler/index.txt +22 -22
  247. package/apps/pwa/out/sessions/index.html +1 -1
  248. package/apps/pwa/out/sessions/index.txt +21 -21
  249. package/apps/pwa/out/settings/devices/index.html +1 -1
  250. package/apps/pwa/out/settings/devices/index.txt +22 -22
  251. package/apps/pwa/out/settings/index.html +1 -1
  252. package/apps/pwa/out/settings/index.txt +22 -22
  253. package/apps/pwa/out/setup/done/index.html +1 -1
  254. package/apps/pwa/out/setup/done/index.txt +22 -22
  255. package/apps/pwa/out/setup/index.html +1 -1
  256. package/apps/pwa/out/setup/index.txt +22 -22
  257. package/apps/pwa/out/share/index.html +1 -1
  258. package/apps/pwa/out/share/index.txt +22 -22
  259. package/apps/pwa/out/showroom/index.html +1 -1
  260. package/apps/pwa/out/showroom/index.txt +21 -21
  261. package/apps/pwa/out/tasks/index.html +1 -1
  262. package/apps/pwa/out/tasks/index.txt +22 -22
  263. package/apps/pwa/out/term/index.html +1 -1
  264. package/apps/pwa/out/term/index.txt +22 -22
  265. package/apps/pwa/out/today/index.html +1 -1
  266. package/apps/pwa/out/today/index.txt +22 -22
  267. package/apps/pwa/out/trace/index.html +1 -1
  268. package/apps/pwa/out/trace/index.txt +22 -22
  269. package/apps/pwa/out/vault/index.html +1 -1
  270. package/apps/pwa/out/vault/index.txt +22 -22
  271. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  272. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  273. package/apps/pwa/out/workflows/index.html +1 -1
  274. package/apps/pwa/out/workflows/index.txt +22 -22
  275. package/apps/pwa/out/workspace/index.html +1 -1
  276. package/apps/pwa/out/workspace/index.txt +22 -22
  277. package/apps/pwa/out/worktrees/index.html +1 -1
  278. package/apps/pwa/out/worktrees/index.txt +22 -22
  279. package/bin/elanous.mjs +6 -1
  280. package/catalog/models/openai/gpt-6.1-sol.yaml +16 -0
  281. package/catalog/models/openai/gpt-6.1-terra.yaml +16 -0
  282. package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
  283. package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
  284. package/graphs/demo/persona-marketer/recipes.yaml +19 -0
  285. package/graphs/demo/persona-teacher/lesson-pack.yaml +16 -0
  286. package/graphs/demo/persona-teacher/recipes.yaml +17 -0
  287. package/graphs/demo/persona-teacher/weekly-lesson.yaml +36 -0
  288. package/graphs/overlays/stop-heal-ladder.yaml +23 -2
  289. package/graphs/release/release-loop.yaml +3 -1
  290. package/graphs/units/gate/gate.yaml +20 -0
  291. package/graphs/units/git/git.yaml +26 -0
  292. package/graphs/units/implement/implement.yaml +19 -0
  293. package/graphs/units/landing/landing.yaml +18 -0
  294. package/graphs/units/review/review.yaml +20 -0
  295. package/graphs/units/verbs/recipes.yaml +3 -0
  296. package/graphs/units/verbs/research.yaml +20 -0
  297. package/graphs/video/explainer-line.yaml +4 -1
  298. package/graphs/work/research-report.yaml +11 -1
  299. package/package.json +1 -1
  300. package/scripts/dead-code/report.ts +169 -0
  301. package/scripts/disk-steward.ts +46 -0
  302. package/scripts/fleet/node-setup.sh +50 -0
  303. package/scripts/graph-units/verbs/research.ts +55 -0
  304. package/scripts/lib/morning-report-options.ts +3 -4
  305. package/scripts/lib/tui-regress-evidence.ts +56 -0
  306. package/scripts/llm-cost-ledger.ts +179 -8
  307. package/scripts/measure-nl-routing-corpus.ts +10 -2
  308. package/scripts/morning-report.ts +5 -1
  309. package/scripts/persona-teacher/weekly-lesson-node.ts +172 -0
  310. package/scripts/public-copy-lint.ts +163 -19
  311. package/scripts/public-export.ts +15 -7
  312. package/scripts/ratchets/train-side-invariants.sh +0 -1
  313. package/scripts/release-loop/export-check-node.ts +21 -3
  314. package/scripts/release-loop/gate-autoheal.ts +117 -0
  315. package/scripts/release-loop/gate-baseline-receipt.ts +8 -1
  316. package/scripts/release-loop/gate-diff.ts +22 -3
  317. package/scripts/release-loop/gate-node.ts +583 -64
  318. package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
  319. package/scripts/release-loop/gate-shard-load-flaky.ts +256 -0
  320. package/scripts/release-loop/gate-shard-receipts.ts +89 -0
  321. package/scripts/release-loop/gate-triage-node.ts +70 -10
  322. package/scripts/release-loop/gate-wall.ts +5 -5
  323. package/scripts/release-loop/preflight.ts +6 -2
  324. package/scripts/release-loop/resume-release.ts +267 -20
  325. package/scripts/release-loop/resume.ts +48 -0
  326. package/scripts/release-loop/traffic-node.ts +6 -3
  327. package/scripts/release-loop/unattended-release.ts +4 -2
  328. package/scripts/release-loop/version-node.ts +7 -2
  329. package/scripts/release-story/draft.ts +1 -1
  330. package/scripts/research-bench/README.md +53 -0
  331. package/scripts/research-bench/questions.json +66 -0
  332. package/scripts/research-bench/rubric.md +33 -0
  333. package/scripts/research-bench/run.ts +523 -0
  334. package/scripts/shadow-authoring-probe.ts +20 -0
  335. package/scripts/tui-regress.ts +85 -10
  336. package/scripts/ux-sim.ts +19 -2
  337. package/src/acp/core-turn-bridge.ts +94 -4
  338. package/src/agent/autonomous-tools.ts +10 -3
  339. package/src/agent/monad-agent-turn.ts +4 -1
  340. package/src/agent/registry.ts +26 -2
  341. package/src/agent/shared-app-tools.ts +1 -1
  342. package/src/agent/surface-ux/build.ts +12 -3
  343. package/src/agent/surface-ux/types.ts +1 -1
  344. package/src/agent/task-notification.ts +75 -6
  345. package/src/agent/types.ts +3 -0
  346. package/src/agent-mission/driver.ts +29 -3
  347. package/src/agent-mission/mission-cli.ts +2 -1
  348. package/src/agent-substrate/review-context-pack.ts +365 -0
  349. package/src/agent-substrate/self-review-cli.ts +291 -20
  350. package/src/ask-user-question/index.ts +6 -0
  351. package/src/ask-user-question/inline-resolver.ts +49 -0
  352. package/src/auto-research/question-ladder-contract.ts +22 -3
  353. package/src/auto-research/research-turn.ts +359 -17
  354. package/src/autopilot/agent-loop.ts +1 -1
  355. package/src/autopilot/discovery/wiki-claim-proposer.ts +22 -1
  356. package/src/autopilot/pty-control-loop.ts +8 -1
  357. package/src/boot/daemon-tools/index.ts +4 -3
  358. package/src/boot/daemon-tools/self-implement.ts +312 -7
  359. package/src/boot/daemon-tools/types.ts +2 -0
  360. package/src/budget/llm-cost.ts +44 -5
  361. package/src/budget/shadow-arms.ts +52 -0
  362. package/src/budget/unified-usage.ts +17 -1
  363. package/src/capture/tui-self-report.ts +14 -0
  364. package/src/chat/index.ts +33 -7
  365. package/src/chat/pickers/state.ts +7 -1
  366. package/src/cli/agent-cli.ts +43 -8
  367. package/src/cli/intake-cli.ts +22 -1
  368. package/src/cli/lesson-cli.ts +19 -3
  369. package/src/cli/log-event-names.ts +6 -0
  370. package/src/cli/mcp-login.ts +8 -18
  371. package/src/cli/msg-cli.ts +57 -1
  372. package/src/cli/pod-cli.ts +17 -2
  373. package/src/cli/pr-land-heavy-remote.ts +15 -9
  374. package/src/cli/pty-takeover-cli.ts +67 -7
  375. package/src/cli/release-cli.ts +79 -7
  376. package/src/cli/repo-cli.ts +2 -1
  377. package/src/cli/sim-cli.ts +7 -1
  378. package/src/cli/tasks-cli.ts +41 -13
  379. package/src/codex/models.ts +30 -15
  380. package/src/control-plane/ledger.ts +21 -4
  381. package/src/core-turn/run-core-turn.ts +47 -3
  382. package/src/core-turn/run-goal-loop.ts +240 -10
  383. package/src/core-turn/types.ts +9 -0
  384. package/src/dashboard/acp-boot.ts +72 -3
  385. package/src/dashboard/chat/acp-chat.ts +2 -2
  386. package/src/dashboard/classic-sigquit.ts +16 -0
  387. package/src/dashboard/index.ts +327 -27
  388. package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
  389. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
  390. package/src/dashboard/input/chat-main-slash-command.ts +7 -0
  391. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  392. package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
  393. package/src/dashboard/input/external-input-host.ts +2 -0
  394. package/src/dashboard/sidetab-runtime.ts +228 -0
  395. package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
  396. package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -8
  397. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
  398. package/src/dashboard/term-slash-runtime.ts +16 -18
  399. package/src/dashboard/turn-preamble.ts +14 -1
  400. package/src/disk-steward/judge.ts +73 -0
  401. package/src/disk-steward/ledger.ts +122 -0
  402. package/src/disk-steward/steward.ts +373 -0
  403. package/src/domains/guardian-tick.ts +191 -2
  404. package/src/domains/knowledge.ts +1 -1
  405. package/src/esc-abort-gate.ts +33 -1
  406. package/src/execution-loop/launch-gate.ts +206 -1
  407. package/src/graph-runner/graph-cli.ts +27 -4
  408. package/src/graph-runner/in-process-registry.ts +37 -0
  409. package/src/graph-runner/runner.ts +63 -11
  410. package/src/graph-wizard/generate.ts +16 -7
  411. package/src/graph-wizard/mission-compose.ts +201 -0
  412. package/src/grok/agent-search.ts +8 -2
  413. package/src/grok/credential.ts +5 -0
  414. package/src/grounding/ref-index.ts +30 -0
  415. package/src/grounding/ref-vector.ts +61 -0
  416. package/src/grounding/sources-cli.ts +11 -3
  417. package/src/grounding/sources.ts +15 -1
  418. package/src/harness/harness-cli-command.ts +305 -23
  419. package/src/harness/harness-incidents.ts +312 -7
  420. package/src/harness/harness-pod-dispatch.ts +7 -1
  421. package/src/harness/harness-space.ts +15 -1
  422. package/src/harness/progress-worker-entry.ts +59 -0
  423. package/src/harness/progress-worker-runtime.ts +11 -0
  424. package/src/index.ts +35 -5
  425. package/src/input/external-input-queue.ts +10 -0
  426. package/src/instance/dev-project.ts +25 -0
  427. package/src/intake-plane/collect-telegram-saved.ts +36 -1
  428. package/src/intake-plane/intake-to-tasks.ts +246 -3
  429. package/src/intelligence-map/model-alias.ts +6 -5
  430. package/src/intelligence-map/model-catalog.ts +59 -2
  431. package/src/lessons/friction-ledger.ts +154 -0
  432. package/src/live-supply/collector.ts +149 -0
  433. package/src/live-supply/probes.ts +52 -0
  434. package/src/live-supply/snapshot.ts +40 -0
  435. package/src/llm/model-defaults.ts +4 -4
  436. package/src/llm.ts +473 -87
  437. package/src/loops/orchestrator/tick.ts +56 -0
  438. package/src/mcp/mcp-oauth.ts +3 -1
  439. package/src/model-tier/llm-tier-map.ts +9 -9
  440. package/src/model-tier/turn-tier.ts +1 -1
  441. package/src/msg/msg-mirror-github.ts +80 -0
  442. package/src/msg/msg-mirror-policy.ts +61 -0
  443. package/src/msg/msg-mirror-runner.ts +219 -0
  444. package/src/msg/msg-mirror-state.ts +33 -0
  445. package/src/msg/msg-store.ts +11 -0
  446. package/src/nexus/api/harness-api.ts +2 -1
  447. package/src/output-truncation.ts +41 -12
  448. package/src/project/project-store.ts +48 -1
  449. package/src/pty/snapshot.py +132 -0
  450. package/src/pty-shell/pty-control-ipc.ts +29 -2
  451. package/src/pty-shell/pty-manifest.ts +59 -3
  452. package/src/pty-shell/registry.ts +2 -0
  453. package/src/pty-shell/tui-run-state.ts +80 -3
  454. package/src/release-loop/gate-host-reservation.ts +157 -4
  455. package/src/release-loop/gate-shard-ledger.ts +68 -0
  456. package/src/release-loop/merged-pr-checklist.ts +25 -2
  457. package/src/release-loop/rehearsal-shard-plan.ts +6 -1
  458. package/src/release-loop/rehearsal.ts +27 -0
  459. package/src/release-loop/release-schedule.ts +90 -1
  460. package/src/research/bloom-exemplars.ts +135 -0
  461. package/src/research/edge-decision.ts +124 -15
  462. package/src/research/gap-followup.ts +249 -0
  463. package/src/research/lenses/counter-evidence.ts +100 -0
  464. package/src/research/lenses/working-backwards.ts +89 -0
  465. package/src/research/plugin-discovery.ts +242 -0
  466. package/src/research-bridge/invoke.ts +4 -2
  467. package/src/research-bridge/types.ts +2 -0
  468. package/src/self-dev/ask-launch-flow.ts +73 -131
  469. package/src/self-dev/dev-cli.ts +19 -17
  470. package/src/self-dev/dev-pipeline.ts +8 -4
  471. package/src/self-dev/graph-front-nodes.ts +23 -0
  472. package/src/self-dev/graph-journey-route.ts +10 -2
  473. package/src/self-dev/launch-preflight-text.ts +2 -2
  474. package/src/self-dev/launch-preflight.ts +47 -11
  475. package/src/self-dev/orchestrate-cli.ts +1 -0
  476. package/src/self-dev/orchestrate.ts +15 -0
  477. package/src/self-dev/run-supervisor.ts +204 -3
  478. package/src/self-dev/run-types.ts +3 -0
  479. package/src/self-implement/device-first.ts +8 -2
  480. package/src/self-implement/doctor-visit.ts +76 -58
  481. package/src/self-implement/gate-artifacts.ts +16 -0
  482. package/src/self-implement/gate-baseline.ts +75 -4
  483. package/src/self-implement/gate-cli.ts +368 -30
  484. package/src/self-implement/gate-receipt-registry.ts +180 -0
  485. package/src/self-implement/gate-remote.ts +165 -24
  486. package/src/self-implement/goal-author-clarification.ts +205 -32
  487. package/src/self-implement/goal-author-decompose.ts +24 -15
  488. package/src/self-implement/goal-author.ts +86 -10
  489. package/src/self-implement/graph-stage-units.ts +172 -0
  490. package/src/self-implement/graph-templates.ts +162 -1
  491. package/src/self-implement/graph-variant.ts +37 -4
  492. package/src/self-implement/host-regate.ts +124 -49
  493. package/src/self-implement/impl-findings-feedback.ts +188 -0
  494. package/src/self-implement/knowhow-pack.ts +227 -10
  495. package/src/self-implement/off-diff-evidence.ts +124 -0
  496. package/src/self-implement/orchestrator.ts +320 -28
  497. package/src/self-implement/run-ledger.ts +110 -14
  498. package/src/self-implement/run-stop.ts +33 -2
  499. package/src/self-implement/running-runs.ts +35 -12
  500. package/src/self-implement/seams.ts +6 -3
  501. package/src/self-implement/self-implement-cli.ts +40 -6
  502. package/src/self-implement/stop-autoheal-operational.ts +43 -0
  503. package/src/self-implement/stop-autoheal.ts +15 -6
  504. package/src/session/chat.ts +66 -15
  505. package/src/session/request-size-guard.ts +123 -0
  506. package/src/session-runtime/provider-circuit.ts +140 -0
  507. package/src/shell-runner/file-engine.ts +1 -0
  508. package/src/shell-runner/types.ts +4 -0
  509. package/src/sidetab-core/model.ts +312 -0
  510. package/src/skills/tools/schedule-wakeup.ts +23 -1
  511. package/src/skills/tools/shell.ts +51 -5
  512. package/src/steward/directive-audit.ts +354 -0
  513. package/src/surface/child-process.ts +31 -0
  514. package/src/surface/tui-stderr-owner.ts +48 -0
  515. package/src/task-agent/cover.ts +30 -12
  516. package/src/task-agent/judge.ts +56 -0
  517. package/src/task-agent/parent-host.ts +14 -1
  518. package/src/task-agent/postland-card.ts +35 -2
  519. package/src/task-agent/rejudge-on-head.ts +46 -2
  520. package/src/task-agent/repair-cycle.ts +1 -1
  521. package/src/task-agent/task-hand.ts +133 -25
  522. package/src/task-agent/tier-split.ts +105 -21
  523. package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
  524. package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
  525. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +70 -2
  526. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +29 -4
  527. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
  528. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
  529. package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
  530. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
  531. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
  532. package/src/task-orchestrator/surfaces/self-implement-pod.ts +298 -45
  533. package/src/task-orchestrator/surfaces/self-implement.ts +18 -0
  534. package/src/tool-runtime/skill-exec-runtime.ts +95 -5
  535. package/src/tui/entry.ts +25 -5
  536. package/src/tui/inline-choice.ts +188 -0
  537. package/src/tui/sidetab/list.ts +36 -165
  538. package/src/tui/sidetab/nl-tool.ts +2 -136
  539. package/src/tui/sidetab/peek.ts +52 -0
  540. package/src/tui/slash/term.ts +12 -1
  541. package/src/tui-client/dashboard-session.ts +10 -1
  542. package/src/user-config.ts +45 -9
  543. package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
  544. package/src/ux-sim/fake-land-queue.ts +88 -0
  545. package/src/ux-sim/fault-needs-human-reason-repair.ts +107 -0
  546. package/src/ux-sim/fault-pod-child-result.ts +42 -0
  547. package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
  548. package/src/ux-sim/goal-interim-trace.ts +24 -0
  549. package/src/ux-sim/next-tui-seat-scenarios.ts +8 -13
  550. package/src/ux-sim/release-sim-rig.ts +262 -0
  551. package/src/ux-sim/seminar-rehearsal.ts +109 -0
  552. package/src/ux-sim/subagent-tools-device.ts +2 -2
  553. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
  554. package/src/version/packed-revision.json +1 -1
  555. package/src/video-pipeline/recipes/explainer.ts +54 -2
  556. package/src/web-search/grok.ts +32 -6
  557. package/src/web-search/index.ts +8 -7
  558. package/src/workflow-runtime/node-catalog.ts +53 -4
  559. package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +0 -27
  560. package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/1938.0e6c60ee91c4d7f5.js +0 -148
  567. package/apps/pwa/out/_next/static/chunks/2104.70e086d5174a4736.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +0 -93
  571. package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +0 -104
  572. package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +0 -24
  581. package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +0 -36
  583. package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +0 -287
  586. package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +0 -94
  592. package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/3f0de3de-2340c532c00395db.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4199-f7c6eb40cd0322f8.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +0 -32
  604. package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +0 -90
  605. package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +0 -79
  607. package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +0 -74
  610. package/apps/pwa/out/_next/static/chunks/5041-5aada92ca215ffdd.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +0 -286
  614. package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +0 -8
  617. package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +0 -62
  629. package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7488.966b116789f3d41a.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7524.ce973525d30b3d52.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/7628.6b16863ac3972333.js +0 -34
  636. package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/7954.4f7a8832663ee979.js +0 -115
  639. package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/8509.3a54d4e61893d7cb.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +0 -149
  647. package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +0 -41
  648. package/apps/pwa/out/_next/static/chunks/9299.24e2a7d9b6d1f91b.js +0 -226
  649. package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +0 -24
  650. package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +0 -2
  654. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/bb6987f9.3647e1a23b0e3217.js +0 -122
  705. package/apps/pwa/out/_next/static/chunks/framework-4b12a946f352cee2.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +0 -1
  711. package/scripts/ratchets/next-tui-entry-budget.ts +0 -124
  712. /package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → GiOLWmt4MqDZePubBjA4Q}/_ssgManifest.js +0 -0
@@ -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
+ }
@@ -7,7 +7,7 @@ import { existsSync, lstatSync, realpathSync } from 'node:fs';
7
7
  import { loadavg } from 'node:os';
8
8
  import { isAbsolute, join, relative, resolve, sep } from 'node:path';
9
9
  import { debug } from '../debug/log.js';
10
- import { gateHostReservationRoot, inspectReleaseGateHost } from '../release-loop/gate-host-reservation.js';
10
+ import { gateHostReservationRoot, inspectReleaseGateHost, readGateHostResourcesForHost, type GateHostResourceReading } from '../release-loop/gate-host-reservation.js';
11
11
  import type { GateRemoteConfig } from '../user-config.js';
12
12
 
13
13
  export type GateRemoteTool = 'self-gate' | 'ci-typecheck-changed' | 'public-export-test-run';
@@ -97,6 +97,7 @@ export function remoteSelfGateArgv(input: {
97
97
  shardConcurrency?: number;
98
98
  fixedShardDistribution?: boolean;
99
99
  includeImporters?: boolean;
100
+ noInherit?: boolean;
100
101
  artifactDir?: string;
101
102
  }, sha: (ref: string) => string): string[] {
102
103
  const shards = input.shards ?? (input.includeImporters ? 2 : undefined);
@@ -106,6 +107,7 @@ export function remoteSelfGateArgv(input: {
106
107
  ...(input.shardConcurrency !== undefined ? ['--shard-concurrency', String(input.shardConcurrency)] : []),
107
108
  ...(input.fixedShardDistribution ? ['--fixed-shard-distribution'] : []),
108
109
  ...(input.includeImporters ? ['--include-importers'] : []),
110
+ ...(input.noInherit ? ['--no-inherit'] : []),
109
111
  ...(input.artifactDir ? ['--artifact-dir', input.artifactDir] : [])];
110
112
  }
111
113
 
@@ -131,6 +133,8 @@ export function decideGateDispatch(input: { flags: Pick<GateRemoteFlags, 'remote
131
133
 
132
134
  export const SLOT_DIR = '/tmp/elanous-gate-remote-slots';
133
135
  const BUSY = '__GATE_REMOTE_BUSY';
136
+ const HEARTBEAT = '__GATE_REMOTE_HEARTBEAT=';
137
+ const REMOTE_RUN_LIMIT_SECONDS = 105 * 60;
134
138
 
135
139
  /** Shell lines that run "$W/run.sh" under the first free of `cap` slot locks, or print the busy marker and exit 98.
136
140
  * run.sh must create "$W/started" first: that is how a lock refusal is told apart from the run's own exit code. */
@@ -138,14 +142,14 @@ export type SlotLockTool = 'flock' | 'lockf';
138
142
  const SLOT_LOCK = { flock: 'flock -n', lockf: 'lockf -k -s -t 0' } as const;
139
143
 
140
144
  /** `tools` is the preference order (default: Linux flock, then BSD/macOS lockf); a test can pin one path. */
141
- 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[] {
142
146
  const n = Math.min(MAX_HOST_CAP, Math.max(1, Math.floor(cap)));
143
147
  const pick = tools.map((tool, i) => `${i ? 'elif' : 'if'} command -v ${tool} >/dev/null 2>&1; then GL="${SLOT_LOCK[tool]}"; `).join('');
144
148
  return [
145
149
  `GS=${quote(dir)}; mkdir -p "$GS" || infra slots`,
146
150
  `${pick}else infra lock-tool; fi`,
147
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; }',
148
- `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`,
149
153
  `echo "${BUSY}=$((n-1));load1=$(load1)" >&2; exit 98`,
150
154
  ];
151
155
  }
@@ -154,6 +158,53 @@ export function hostSlotScript(cap: number, dir = SLOT_DIR, tools: readonly Slot
154
158
  return hostSlotScriptWithSlot(cap, dir, tools, false);
155
159
  }
156
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
+
157
208
  // ── remote execution ───────────────────────────────────────────────
158
209
 
159
210
  export interface ExecResult { rc: number | null; stdout: string; stderr: string; error?: string }
@@ -217,7 +268,7 @@ export interface PayloadFile { env: string; content: string }
217
268
  export type RemoteArgv = string[] | ((sha: (ref: string) => string) => string[]);
218
269
 
219
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. */
220
- 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 {
221
272
  const mirror = input.mirror.startsWith('~/') ? `"$HOME"/${quote(input.mirror.slice(2))}` : quote(input.mirror);
222
273
  const fetches = input.fetchShas.map((sha) => `refs/elanous/gate/${sha}:refs/elanous/gate/${sha}`).join(' ');
223
274
  const payloads = (input.payloadFiles ?? []).filter((file) => /^[A-Z_][A-Z0-9_]*$/.test(file.env));
@@ -280,11 +331,16 @@ export function remoteScript(input: { mirror: string; commit: string; fetchShas:
280
331
  'W=$(mktemp -d /var/tmp/elanous-gate-remote-XXXXXXXX) || infra mktemp',
281
332
  'export W',
282
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',
283
336
  ...payloadLines,
284
337
  `cat > "$W/run.sh" <<'${RUN}' || infra run-script`,
285
338
  ...work,
286
339
  RUN,
287
- ...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),
288
344
  '}',
289
345
  '',
290
346
  ].join('\n');
@@ -340,11 +396,22 @@ export function runOnRemote(opts: RemoteRunOptions, runner: GateRemoteRunner = r
340
396
  env: { ...process.env, GIT_SSH_COMMAND: 'ssh -o BatchMode=yes -o ConnectTimeout=10', GIT_TERMINAL_PROMPT: '0' },
341
397
  });
342
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(' | ')}` };
343
- 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 });
344
- 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);
345
403
  // The script prints "\n<marker><rc>\n": everything before that leading newline is the tool's own stderr, byte for byte.
346
404
  const stdoutBytes = Buffer.from(run.stdout);
347
- 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);
348
415
  const stderrText = stderrBytes.toString('utf8');
349
416
  const marker = stderrBytes.lastIndexOf(Buffer.from(`\n${RC}`));
350
417
  // Busy (98) and setup failure (97) are the script's own exits, each with its marker as the last stderr line. A completed
@@ -450,6 +517,11 @@ export interface DispatchOptions {
450
517
  reportRemoteHost?: boolean;
451
518
  /** Release gate host reservations shared by self gate and changed typecheck. */
452
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;
453
525
  runLocal: () => number | Promise<number>;
454
526
  /** Called once with the final remote outcome (never on a local decision), before its output passes through or the
455
527
  * local fallback runs — e.g. `self gate --artifact-dir` fetches (ran) or removes (infra) the host-side artifact dir.
@@ -466,9 +538,31 @@ export interface DispatchDeps {
466
538
  now?: () => number;
467
539
  /** Test seam for gate.remote events; production defaults to the structured debug log. */
468
540
  log?: (event: string, data: Record<string, unknown>) => void;
541
+ /** Read-only host-resource probe; production reads Pod pool ledgers, tests inject the same measured snapshot. */
542
+ readHostResources?: (host: string) => GateHostResourceReading;
469
543
  write?: { out: (data: string | Uint8Array) => void; err: (data: string | Uint8Array) => void };
470
544
  }
471
545
 
546
+ /** Hosts a reserved self gate may fall back to: an explicit list wins, otherwise `node-b` (the only host the old
547
+ * unmeasured hint named an alternative for) falls back to `host-e-wsl`. Invalid or duplicate entries are dropped. */
548
+ export function gateReservationAlternateHosts(reservedHost: string, explicit?: string[]): string[] {
549
+ const candidates = explicit ?? (reservedHost === 'node-b' ? ['host-e-wsl'] : []);
550
+ const seen = new Set<string>([reservedHost]);
551
+ const hosts: string[] = [];
552
+ for (const candidate of candidates) {
553
+ if (!candidate || seen.has(candidate) || !isValidGateHost(candidate)) continue;
554
+ seen.add(candidate);
555
+ hosts.push(candidate);
556
+ }
557
+ return hosts;
558
+ }
559
+
560
+ /** Reservation diagnostics stamp — ISO 시각 printed next to the claim owner (runId). Claims written before
561
+ * `reservedAt` existed fall back to the gate's own observation time. */
562
+ export function formatReservationStamp(ms: number): string {
563
+ return new Date(ms).toISOString();
564
+ }
565
+
472
566
  async function loadSettings(): Promise<GateRemoteSettings> {
473
567
  try {
474
568
  const { getUserConfig } = await import('../user-config.js');
@@ -498,26 +592,75 @@ export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDe
498
592
  return opts.runLocal();
499
593
  }
500
594
  let host = decision.host!;
595
+ const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
596
+ const now = deps.now ?? Date.now;
501
597
  const reservationRoot = opts.tool === 'self-gate' || opts.tool === 'ci-typecheck-changed'
502
598
  ? opts.reservationRoot ?? (deps.runner ? undefined : gateHostReservationRoot()) : undefined;
503
599
  if (reservationRoot) {
600
+ const resourceStatus = (target: string) => {
601
+ if (!deps.readHostResources && deps.runner) return null; // fake runners keep tests hermetic unless the producer is explicitly exercised
602
+ return (deps.readHostResources ?? ((selected) => readGateHostResourcesForHost(selected, env)))(target.split('@').at(-1)!);
603
+ };
604
+ const inspect = (target: string) => {
605
+ const claim = inspectReleaseGateHost(reservationRoot, target);
606
+ const resources = resourceStatus(target);
607
+ if (!resources) return claim;
608
+ if (resources.status === 'unmeasurable') {
609
+ // Keep a concrete release owner visible even if the independent Pod ledgers cannot be read.
610
+ if (claim.status === 'reserved') return claim;
611
+ return { status: 'unknown' as const, reason: `resource probe unmeasurable: ${resources.reason}` };
612
+ }
613
+ if (!resources.empty) return { status: 'reserved' as const, reason: `Pod resource pool occupied (${resources.reservations} reservations)` };
614
+ return claim;
615
+ };
504
616
  const reservationHost = host.split('@').at(-1)!;
505
- const first = inspectReleaseGateHost(reservationRoot, reservationHost);
617
+ const first = inspect(reservationHost);
506
618
  if (first.status !== 'free') {
507
- // Changed typecheck has a fixed node-b placement; a release reservation makes it unmeasured.
508
- const alternate = opts.tool === 'self-gate' && reservationHost === 'node-b' ? 'node-c' : null;
509
- const other = alternate ? inspectReleaseGateHost(reservationRoot, alternate) : null;
510
- if (alternate && other?.status === 'free') {
511
- debug.log('gate.remote', 'host-reserved-reroute', { from: host, to: alternate, reason: first.reason, status: first.status });
512
- write.err(`[gate.remote] ${host} reserved (${first.reason}) — using ${alternate}\n`);
513
- host = alternate;
619
+ // A reserved host is never a reason to run this check locally (반증: 예약 상태에서 --local 무거운 시험 금지).
620
+ // Self gate first tries another remote host, then waits bounded for the release, then ends unmeasured with
621
+ // the owner and the observation stamp.
622
+ const observedAt = formatReservationStamp(now());
623
+ const owner = first.runId || 'unknown';
624
+ // Owner (runId) plus 시각: the claim's own reservedAt when recorded, else the moment this gate observed it.
625
+ const stamp = first.reservedAt !== undefined
626
+ ? `reserved-at=${formatReservationStamp(first.reservedAt)}`
627
+ : `observed-at=${observedAt}`;
628
+ const alternates = opts.tool === 'self-gate'
629
+ ? gateReservationAlternateHosts(reservationHost, opts.reservationAltHosts) : [];
630
+ const alternate = alternates.find((candidate) => inspect(candidate).status === 'free');
631
+ if (alternate) {
632
+ const rerouted = host.includes('@') ? `${host.slice(0, host.lastIndexOf('@'))}@${alternate}` : alternate;
633
+ debug.log('gate.remote', 'host-reserved-reroute', { tool: opts.tool, from: host, to: rerouted, owner, reason: first.reason, reservedAt: first.reservedAt, observedAt });
634
+ write.err(`[gate.remote] host-reserved: ${host} (${first.reason}) owner=${owner} ${stamp} — rerouting to ${rerouted}\n`);
635
+ host = rerouted;
514
636
  } else {
515
- const reason = `host-reserved: ${host} (${first.reason}); alternate ${alternate ?? '(none)'} ${other?.status ?? 'unavailable'}`;
516
- debug.log('gate.remote', 'host-reserved-unmeasured', { host, reason });
517
- write.err(opts.tool === 'self-gate'
518
- ? `[gate.remote] remote unmeasured on ${host} (stage=host-reserved, rc=unknown) — ${reason}\n`
519
- : `[gate.remote] remote unmeasured — ${reason}\n`);
520
- return 1;
637
+ const waitSeconds = opts.tool === 'self-gate' ? opts.reservationWaitSeconds ?? settings.slotWaitSeconds : 0;
638
+ const waitStart = now();
639
+ const deadline = waitStart + Math.max(0, waitSeconds) * 1000;
640
+ let latest = inspect(reservationHost);
641
+ while (waitSeconds > 0 && latest.status !== 'free') {
642
+ const left = deadline - now();
643
+ if (left <= 0) break;
644
+ 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`);
645
+ const before = now();
646
+ await sleep(Math.min(15_000, left));
647
+ if (now() <= before) break; // a frozen test clock must not spin past the bound
648
+ latest = inspect(reservationHost);
649
+ }
650
+ const waitedMs = Math.max(0, now() - waitStart);
651
+ if (latest.status === 'free') {
652
+ debug.log('gate.remote', 'host-reserved-released', { tool: opts.tool, host, owner, waitedMs });
653
+ write.err(`[gate.remote] host-reserved released on ${host} after ${Math.floor(waitedMs / 1000)}s — proceeding remotely\n`);
654
+ } else {
655
+ const reason = `host-reserved: ${host} (${latest.reason})`;
656
+ const manualAlternative = reservationHost === 'node-b'
657
+ ? '; if available, non-PWA checks may explicitly select --remote host-e-wsl' : '';
658
+ debug.log('gate.remote', 'host-reserved-unmeasured', { host, reason, owner, reservedAt: latest.reservedAt ?? first.reservedAt, observedAt, waitedMs, alternates: alternates.length });
659
+ write.err(opts.tool === 'self-gate'
660
+ ? `[gate.remote] remote unmeasured on ${host} (stage=host-reserved, rc=unknown) — ${reason}; owner=${owner} ${stamp} waited=${Math.floor(waitedMs / 1000)}s${manualAlternative}\n`
661
+ : `[gate.remote] remote unmeasured — ${reason}\n`);
662
+ return 1;
663
+ }
521
664
  }
522
665
  }
523
666
  }
@@ -535,8 +678,6 @@ export async function dispatchHeavyCheck(opts: DispatchOptions, deps: DispatchDe
535
678
  };
536
679
  if (opts.localOnlyReason) return fallback(opts.localOnlyReason, { stage: 'reproducibility', rc: null });
537
680
  const hostCap = gateRemoteHostCap(settings, host);
538
- const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
539
- const now = deps.now ?? Date.now;
540
681
  const deadline = now() + settings.slotWaitSeconds * 1000;
541
682
  let waitStartedAt: number | undefined;
542
683
  const logWait = deps.log ?? ((event: string, data: Record<string, unknown>) => debug.log('gate.remote', event, data));