elanous 0.2.22 → 0.2.23

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 (705) hide show
  1. package/NOTICE +7 -0
  2. package/README.md +32 -22
  3. package/apps/pwa/out/404/index.html +1 -1
  4. package/apps/pwa/out/404.html +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
  9. package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
  11. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
  12. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
  14. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
  23. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
  24. package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
  27. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
  35. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
  39. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
  52. package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
  56. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
  64. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
  69. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
  71. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
  73. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
  74. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
  78. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
  83. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
  84. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
  85. package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
  86. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
  87. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
  90. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
  97. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
  99. package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
  101. package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
  105. package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
  110. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
  111. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
  112. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
  114. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
  116. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
  117. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
  120. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
  123. package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-6168a7c43e6ef8f5.js} +1 -1
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
  184. package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +1 -0
  185. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
  186. package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +1 -1
  187. package/apps/pwa/out/approvals/index.html +1 -1
  188. package/apps/pwa/out/approvals/index.txt +23 -23
  189. package/apps/pwa/out/autopilot/index.html +1 -1
  190. package/apps/pwa/out/autopilot/index.txt +23 -23
  191. package/apps/pwa/out/board/index.html +1 -1
  192. package/apps/pwa/out/board/index.txt +23 -23
  193. package/apps/pwa/out/botlab/index.html +1 -1
  194. package/apps/pwa/out/botlab/index.txt +22 -22
  195. package/apps/pwa/out/bots/index.html +1 -1
  196. package/apps/pwa/out/bots/index.txt +22 -22
  197. package/apps/pwa/out/ceo/index.html +1 -1
  198. package/apps/pwa/out/ceo/index.txt +23 -23
  199. package/apps/pwa/out/chat/index.html +1 -1
  200. package/apps/pwa/out/chat/index.txt +22 -22
  201. package/apps/pwa/out/consult/index.html +1 -1
  202. package/apps/pwa/out/consult/index.txt +23 -23
  203. package/apps/pwa/out/control/index.html +1 -1
  204. package/apps/pwa/out/control/index.txt +23 -23
  205. package/apps/pwa/out/decisions/index.html +1 -1
  206. package/apps/pwa/out/decisions/index.txt +22 -22
  207. package/apps/pwa/out/design-check/index.html +1 -1
  208. package/apps/pwa/out/design-check/index.txt +23 -23
  209. package/apps/pwa/out/editor/index.html +1 -1
  210. package/apps/pwa/out/editor/index.txt +24 -23
  211. package/apps/pwa/out/exec/index.html +1 -1
  212. package/apps/pwa/out/exec/index.txt +23 -23
  213. package/apps/pwa/out/field/index.html +1 -1
  214. package/apps/pwa/out/field/index.txt +23 -23
  215. package/apps/pwa/out/healthz +1 -1
  216. package/apps/pwa/out/index.html +1 -1
  217. package/apps/pwa/out/index.txt +22 -22
  218. package/apps/pwa/out/inside/index.html +1 -1
  219. package/apps/pwa/out/inside/index.txt +22 -22
  220. package/apps/pwa/out/intake/index.html +1 -1
  221. package/apps/pwa/out/intake/index.txt +23 -23
  222. package/apps/pwa/out/live/index.html +1 -1
  223. package/apps/pwa/out/live/index.txt +23 -23
  224. package/apps/pwa/out/live-run/index.html +1 -1
  225. package/apps/pwa/out/live-run/index.txt +24 -23
  226. package/apps/pwa/out/loops/index.html +1 -1
  227. package/apps/pwa/out/loops/index.txt +22 -22
  228. package/apps/pwa/out/market/index.html +1 -1
  229. package/apps/pwa/out/market/index.txt +22 -22
  230. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  231. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  232. package/apps/pwa/out/morning/index.html +1 -1
  233. package/apps/pwa/out/morning/index.txt +23 -23
  234. package/apps/pwa/out/observatory/index.html +1 -1
  235. package/apps/pwa/out/observatory/index.txt +23 -23
  236. package/apps/pwa/out/ops/checklist/index.html +1 -1
  237. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  238. package/apps/pwa/out/ops/release/index.html +1 -1
  239. package/apps/pwa/out/ops/release/index.txt +22 -22
  240. package/apps/pwa/out/ops/seats/index.html +1 -1
  241. package/apps/pwa/out/ops/seats/index.txt +22 -22
  242. package/apps/pwa/out/outputs/index.html +1 -1
  243. package/apps/pwa/out/outputs/index.txt +22 -22
  244. package/apps/pwa/out/reflection/index.html +1 -1
  245. package/apps/pwa/out/reflection/index.txt +23 -23
  246. package/apps/pwa/out/scheduler/index.html +1 -1
  247. package/apps/pwa/out/scheduler/index.txt +23 -23
  248. package/apps/pwa/out/sessions/index.html +1 -1
  249. package/apps/pwa/out/sessions/index.txt +22 -22
  250. package/apps/pwa/out/settings/devices/index.html +1 -1
  251. package/apps/pwa/out/settings/devices/index.txt +23 -23
  252. package/apps/pwa/out/settings/index.html +1 -1
  253. package/apps/pwa/out/settings/index.txt +23 -23
  254. package/apps/pwa/out/setup/done/index.html +1 -1
  255. package/apps/pwa/out/setup/done/index.txt +23 -23
  256. package/apps/pwa/out/setup/index.html +1 -1
  257. package/apps/pwa/out/setup/index.txt +23 -23
  258. package/apps/pwa/out/share/index.html +1 -1
  259. package/apps/pwa/out/share/index.txt +23 -23
  260. package/apps/pwa/out/showroom/index.html +1 -1
  261. package/apps/pwa/out/showroom/index.txt +22 -22
  262. package/apps/pwa/out/tasks/index.html +1 -1
  263. package/apps/pwa/out/tasks/index.txt +23 -23
  264. package/apps/pwa/out/term/index.html +1 -1
  265. package/apps/pwa/out/term/index.txt +23 -23
  266. package/apps/pwa/out/today/index.html +1 -1
  267. package/apps/pwa/out/today/index.txt +23 -23
  268. package/apps/pwa/out/trace/index.html +1 -1
  269. package/apps/pwa/out/trace/index.txt +23 -23
  270. package/apps/pwa/out/vault/index.html +1 -1
  271. package/apps/pwa/out/vault/index.txt +23 -23
  272. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  273. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  274. package/apps/pwa/out/workflows/index.html +1 -1
  275. package/apps/pwa/out/workflows/index.txt +23 -23
  276. package/apps/pwa/out/workspace/index.html +1 -1
  277. package/apps/pwa/out/workspace/index.txt +23 -23
  278. package/apps/pwa/out/worktrees/index.html +1 -1
  279. package/apps/pwa/out/worktrees/index.txt +23 -23
  280. package/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
  281. package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
  282. package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
  283. package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
  284. package/catalog/models/openai/gpt-6-astra.yaml +6 -0
  285. package/catalog/models/openai/gpt-6-luna.yaml +6 -0
  286. package/catalog/models/openai/gpt-6-sol.yaml +6 -0
  287. package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
  288. package/graphs/log-horizon/recipes.yaml +3 -0
  289. package/graphs/release/recipes.yaml +1 -1
  290. package/graphs/release/release-loop.yaml +6 -2
  291. package/graphs/release-rehearsal/recipes.yaml +12 -0
  292. package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
  293. package/package.json +4 -1
  294. package/scripts/bench-report.ts +82 -3
  295. package/scripts/ci-typecheck-changed.ts +10 -1
  296. package/scripts/hq/hq-fence-wrapper.sh +148 -0
  297. package/scripts/lib/typecheck-ratchet.ts +51 -0
  298. package/scripts/openai-relay-server.ts +5 -1
  299. package/scripts/release-loop/docs-node.ts +258 -43
  300. package/scripts/release-loop/gate-method.ts +59 -0
  301. package/scripts/release-loop/gate-node.ts +73 -7
  302. package/scripts/release-loop/gate-wall.ts +208 -0
  303. package/scripts/release-loop/known-issues-node.ts +53 -8
  304. package/scripts/release-loop/publish-at.ts +14 -0
  305. package/scripts/release-loop/publish-node.ts +17 -2
  306. package/scripts/release-loop/resume-release.ts +34 -4
  307. package/scripts/release-loop/resume.ts +53 -0
  308. package/scripts/release-loop/shard-plan.ts +3 -11
  309. package/scripts/release-loop/tui-node-checks.ts +22 -0
  310. package/scripts/release-loop/unattended-release.ts +8 -1
  311. package/scripts/rhythm/daily.ts +51 -2
  312. package/scripts/rhythm/weekly.ts +3 -2
  313. package/scripts/tsc-main-safety-net.ts +189 -0
  314. package/scripts/usage-rollup.ts +8 -4
  315. package/src/acp/codex-plugins.ts +48 -6
  316. package/src/agent/monad-agent-turn.ts +67 -5
  317. package/src/agent/run-context.ts +10 -0
  318. package/src/agent/tool-profile.ts +28 -2
  319. package/src/agent-mission/acp-judge.ts +8 -2
  320. package/src/agent-mission/capabilities-cli.ts +16 -1
  321. package/src/agent-mission/driver.ts +1 -1
  322. package/src/agent-mission/pr-review-watch.ts +6 -2
  323. package/src/agent-mission/review-loop.ts +33 -5
  324. package/src/agent-substrate/acp-reviewer.ts +17 -8
  325. package/src/agent-substrate/pr-reviewer.ts +164 -28
  326. package/src/agent-substrate/review-intent.ts +6 -4
  327. package/src/agent-substrate/self-review-cli.ts +111 -16
  328. package/src/agent-substrate/shard-boundary-intent.ts +92 -26
  329. package/src/ask-user-question/pending-questions.ts +8 -2
  330. package/src/autopilot/build/llm-conflict-merge.ts +216 -12
  331. package/src/autopilot/codebase-grounding.ts +44 -0
  332. package/src/autopilot/llm-control-brain.ts +13 -1
  333. package/src/autopilot/mission-codebase-gate.ts +8 -77
  334. package/src/autopilot/pr-manager.ts +12 -3
  335. package/src/boot/acp-server.ts +4 -7
  336. package/src/boot/acp-socket-path.ts +7 -0
  337. package/src/briefing/brief-items.ts +21 -13
  338. package/src/chat/index.ts +12 -3
  339. package/src/cli/agent-cli.ts +20 -0
  340. package/src/cli/brief-cli.ts +27 -21
  341. package/src/cli/cli-user-error.ts +9 -2
  342. package/src/cli/log-event-names.ts +3 -0
  343. package/src/cli/logs-cli.ts +1 -0
  344. package/src/cli/mcp-login.ts +111 -37
  345. package/src/cli/plugin-cli.ts +21 -1
  346. package/src/cli/pod-cli.ts +26 -0
  347. package/src/cli/pr-cli.ts +30 -2
  348. package/src/cli/pr-land-overlap-evidence.ts +131 -0
  349. package/src/cli/release-cli.ts +53 -11
  350. package/src/cli/self-update.ts +173 -10
  351. package/src/cli/skills-cli.ts +12 -3
  352. package/src/cli/tasks-cli.ts +133 -27
  353. package/src/context-bus/context-first.ts +51 -2
  354. package/src/context-bus/context-now-surfaces.ts +13 -2
  355. package/src/context-bus/long-term-memory.ts +3 -1
  356. package/src/context-bus/nightly-condense.ts +3 -2
  357. package/src/core-turn/run-goal-loop.ts +86 -2
  358. package/src/dashboard/chat-fold.ts +20 -0
  359. package/src/dashboard/first-screen-band.ts +151 -1
  360. package/src/dashboard/index.ts +27 -5
  361. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
  362. package/src/dashboard/stale-install-check.ts +13 -2
  363. package/src/dashboard/turn-stream-formatter.ts +25 -0
  364. package/src/debug/log-diet.ts +159 -0
  365. package/src/debug/log.ts +52 -17
  366. package/src/display/coordinator.ts +25 -2
  367. package/src/domains/coo-admin-tool.ts +27 -0
  368. package/src/domains/cron-match.ts +1 -0
  369. package/src/domains/outbound-alert.ts +17 -6
  370. package/src/domains/release-tool.ts +119 -10
  371. package/src/domains/schedule-registry.ts +10 -7
  372. package/src/domains/schedule-runner.ts +1 -0
  373. package/src/elanous-config-dir.ts +2 -2
  374. package/src/elanous-daemon.ts +3 -3
  375. package/src/execution-loop/launch-gate.ts +1 -1
  376. package/src/expression/i18n/messages.en.ts +5 -0
  377. package/src/expression/i18n/messages.ja.ts +5 -0
  378. package/src/expression/i18n/messages.ko.ts +5 -0
  379. package/src/expression/i18n/messages.zh.ts +5 -0
  380. package/src/expression/i18n/types.ts +8 -0
  381. package/src/github/pr-labels.ts +1 -0
  382. package/src/graph-runner/runner.ts +54 -5
  383. package/src/harness/dispatch-backpressure.ts +259 -0
  384. package/src/harness/harness-cli-command.ts +107 -28
  385. package/src/harness/harness-seams.ts +2 -20
  386. package/src/harness/harness-substrate-default.ts +72 -1
  387. package/src/harness/nested-elanous-policy.ts +4 -2
  388. package/src/hq/fence-wrapper.ts +7 -0
  389. package/src/hq/hq.ts +33 -2
  390. package/src/hq/lease.ts +13 -0
  391. package/src/hq/seats.ts +114 -18
  392. package/src/index.ts +163 -64
  393. package/src/intake-plane/collect-github.ts +19 -1
  394. package/src/intake-plane/digest.ts +45 -20
  395. package/src/intake-plane/lens.ts +36 -8
  396. package/src/intelligence-map/model-alias.ts +6 -0
  397. package/src/intelligence-map/model-catalog.ts +41 -0
  398. package/src/knowledge/kgs/pack.ts +5 -2
  399. package/src/knowledge/kgs/sqlite-store.ts +15 -0
  400. package/src/knowledge/tools/knowledge-query.ts +20 -2
  401. package/src/knowledge/write.ts +234 -2
  402. package/src/llm/bedrock-provider.ts +175 -0
  403. package/src/llm/bedrock.ts +345 -0
  404. package/src/llm/provider-credentials.ts +3 -1
  405. package/src/llm.ts +306 -35
  406. package/src/loops/budget.ts +150 -0
  407. package/src/loops/orchestrator/seat-share.ts +6 -49
  408. package/src/loops/orchestrator/traffic.ts +5 -81
  409. package/src/market/signed-index.ts +42 -0
  410. package/src/mcp/mcp-oauth.ts +136 -17
  411. package/src/model-tier/llm-tier-map.ts +48 -4
  412. package/src/models/prompts.ts +22 -1
  413. package/src/mss/logging/horizon-watch.ts +168 -0
  414. package/src/mss/logging/log-store.ts +204 -15
  415. package/src/native-tool-catalog.ts +1 -1
  416. package/src/nexus/api/consult-requests.ts +7 -10
  417. package/src/nexus/api/discord-trigger-bot.ts +6 -3
  418. package/src/nexus/api/error-reports.ts +30 -8
  419. package/src/nexus/api/http-server.ts +8 -0
  420. package/src/nexus/api/loop-resources.ts +42 -0
  421. package/src/nexus/api/outbound-report.ts +8 -3
  422. package/src/nexus/api/telegram-trigger-bot.ts +6 -3
  423. package/src/nexus/index.ts +10 -0
  424. package/src/nexus/outbound/format.ts +2 -0
  425. package/src/nexus/outbound/router.ts +198 -13
  426. package/src/oauth/codex-account-rotation.ts +16 -18
  427. package/src/oauth/codex-account-store.ts +134 -5
  428. package/src/oauth/fallback-chain.ts +28 -6
  429. package/src/onboarding.ts +2 -1
  430. package/src/plugins/adapters/claude-package.ts +4 -12
  431. package/src/plugins/core/capability-policy.ts +141 -0
  432. package/src/plugins/core/host.ts +21 -8
  433. package/src/plugins/core/manifest.ts +19 -2
  434. package/src/plugins/core/trust-store.ts +15 -0
  435. package/src/plugins/core/types.ts +12 -0
  436. package/src/plugins/install/market-fetch.ts +68 -16
  437. package/src/plugins/install/plugin-install.ts +187 -16
  438. package/src/plugins/maker/plugin-maker.ts +25 -20
  439. package/src/plugins/maker/wizard-generate.ts +16 -2
  440. package/src/policy/llm-policy.ts +14 -1
  441. package/src/process/pid-liveness.ts +1 -1
  442. package/src/prompt-cache/openai.ts +10 -6
  443. package/src/prompt-cache/openrouter.ts +94 -0
  444. package/src/prompt-enhance/enhance.ts +46 -5
  445. package/src/prompt-library/family-prompt-coverage.ts +1 -0
  446. package/src/prompt-library/universal-preamble.ts +2 -2
  447. package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
  448. package/src/registry/loader.ts +6 -1
  449. package/src/release-loop/checklist.ts +24 -9
  450. package/src/release-loop/feature-store.ts +3 -0
  451. package/src/release-loop/gate-shards.ts +48 -4
  452. package/src/release-loop/landed-to-green.ts +81 -0
  453. package/src/release-loop/light-rc.ts +11 -1
  454. package/src/release-loop/merged-pr-checklist.ts +10 -0
  455. package/src/release-loop/placement.ts +91 -22
  456. package/src/release-loop/rehearsal.ts +317 -0
  457. package/src/release-loop/release-schedule.ts +13 -1
  458. package/src/release-loop/rubric-types.ts +1 -0
  459. package/src/release-loop/rubric.ts +2 -2
  460. package/src/retro/daily.ts +23 -9
  461. package/src/seat-loop/seat-loop.ts +34 -1
  462. package/src/seat-loop/traffic-signal.ts +44 -0
  463. package/src/self-dev/ask-launch-flow.ts +2 -2
  464. package/src/self-dev/dev-cli.ts +67 -3
  465. package/src/self-dev/dev-pipeline.ts +4 -6
  466. package/src/self-dev/draft-residue.ts +463 -0
  467. package/src/self-dev/draft-sweep.ts +151 -10
  468. package/src/self-dev/draft-triage-rules.ts +27 -1
  469. package/src/self-dev/launch-preflight-text.ts +549 -0
  470. package/src/self-dev/launch-preflight.ts +10 -545
  471. package/src/self-dev/orchestrate-cli.ts +57 -2
  472. package/src/self-dev/orchestrate-summary-line.ts +13 -0
  473. package/src/self-dev/orchestrate.ts +8 -135
  474. package/src/self-dev/review-provider-fallback.ts +115 -19
  475. package/src/self-dev/run-store.ts +1 -3
  476. package/src/self-dev/run-supervisor.ts +3 -22
  477. package/src/self-dev/run-types.ts +178 -0
  478. package/src/self-dev/shard-aggregate.ts +61 -13
  479. package/src/self-dev/shard-plan.ts +5 -1
  480. package/src/self-dev/shard-run.ts +23 -5
  481. package/src/self-dev/supervisor-verdict-edges.ts +2 -4
  482. package/src/self-implement/blocked-draft-policy.ts +3 -19
  483. package/src/self-implement/draft-on-stop-mode.ts +18 -0
  484. package/src/self-implement/follow-up-goals.ts +114 -38
  485. package/src/self-implement/gate-baseline-reap.ts +157 -0
  486. package/src/self-implement/gate-baseline.ts +78 -16
  487. package/src/self-implement/gate-cli.ts +12 -2
  488. package/src/self-implement/gate-remote.ts +17 -6
  489. package/src/self-implement/goal-author.ts +24 -4
  490. package/src/self-implement/goal-digest.ts +19 -0
  491. package/src/self-implement/graph-overlay-condition.ts +4 -0
  492. package/src/self-implement/headless-elanous-driver.ts +11 -9
  493. package/src/self-implement/host-regate.ts +120 -29
  494. package/src/self-implement/l8-merge-queue.ts +67 -5
  495. package/src/self-implement/merge-train.ts +131 -0
  496. package/src/self-implement/off-diff-evidence.ts +9 -0
  497. package/src/self-implement/orchestrator.ts +133 -16
  498. package/src/self-implement/review-finding-recurrence.ts +28 -0
  499. package/src/self-implement/rework-policy.ts +2 -1
  500. package/src/self-implement/round-summary-card.ts +63 -0
  501. package/src/self-implement/run-ledger.ts +4 -3
  502. package/src/self-implement/run-step-projection.ts +147 -0
  503. package/src/self-implement/run-stop.ts +1 -1
  504. package/src/self-implement/seams.ts +36 -3
  505. package/src/self-implement/self-implement-cli.ts +3 -1
  506. package/src/self-implement/train-gate-remote.ts +158 -0
  507. package/src/session-runtime/index.ts +10 -1
  508. package/src/session-runtime/retry-api.ts +11 -1
  509. package/src/skills/gift-install.ts +119 -0
  510. package/src/skills/runner.ts +59 -2
  511. package/src/skills/skill-feedback.ts +31 -1
  512. package/src/skills/skill-tier.ts +1 -0
  513. package/src/smart-wizard/capability-index.ts +231 -0
  514. package/src/smart-wizard/rung.ts +74 -0
  515. package/src/steward/launch.ts +20 -9
  516. package/src/steward/triage.ts +4 -2
  517. package/src/storage/file-lock.ts +8 -1
  518. package/src/task-agent/actions.ts +4 -0
  519. package/src/task-agent/card-evidence.ts +59 -13
  520. package/src/task-agent/judge.ts +4 -3
  521. package/src/task-agent/land-worktree.ts +201 -0
  522. package/src/task-agent/live-move-history.ts +133 -0
  523. package/src/task-agent/live-moves.ts +106 -19
  524. package/src/task-agent/parent-host.ts +117 -8
  525. package/src/task-agent/rejudge-on-head.ts +297 -0
  526. package/src/task-agent/review-result-capture.ts +218 -0
  527. package/src/task-agent/shadow.ts +103 -7
  528. package/src/task-agent/task-hand.ts +136 -11
  529. package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
  530. package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
  531. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
  532. package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
  533. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
  534. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
  535. package/src/task-orchestrator/surfaces/pod-pool.ts +66 -14
  536. package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
  537. package/src/task-orchestrator/surfaces/self-implement.ts +6 -2
  538. package/src/telegram-service.ts +5 -1
  539. package/src/telegram.ts +17 -4
  540. package/src/time/format.ts +13 -4
  541. package/src/tool-runtime/goal-author-runtime.ts +1 -0
  542. package/src/tool-runtime/self-cognition-catalog.ts +23 -0
  543. package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
  544. package/src/user-config.ts +132 -24
  545. package/src/ux-sim/slash-menu-frames.ts +168 -0
  546. package/src/version/packed-revision.json +1 -1
  547. package/src/web-terminal/preview-tap-registry.ts +5 -2
  548. package/src/workflow-runtime/triggers/scheduler.ts +1 -0
  549. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
  550. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
  551. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
  552. package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
  554. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
  555. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
  556. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
  558. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
  563. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
  572. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
  573. package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
  586. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
  594. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
  599. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
  601. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
  605. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
  610. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
  615. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
  616. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
  618. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
  619. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
  627. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
  630. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
  640. package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
  643. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
  647. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
  648. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
  704. package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
  705. /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → rfkMm4movqkqMebBrCXiR}/_ssgManifest.js +0 -0
@@ -1,6 +1,6 @@
1
- // FOLLOWUP-LOOP① — after a harness PR merges, leftover findings become one
2
- // follow-up goal draft. Default mode is shadow: record only. `live` also
3
- // enqueues through the same function as `harness queue add`.
1
+ // FOLLOWUP-LOOP① — leftover findings after a merge or blocked run become
2
+ // follow-up drafts. Default mode is shadow; only merged drafts in `live` mode
3
+ // enqueue through the same function as `harness queue add`.
4
4
  //
5
5
  // The test process injects every store. Nothing here opens the operational
6
6
  // ledger or queue unless the caller passes those seams.
@@ -25,6 +25,9 @@ export type FollowUpMode = 'shadow' | 'live';
25
25
 
26
26
  export interface FollowUpDraftRecord {
27
27
  prNumber: number;
28
+ ending?: 'blocked';
29
+ runId?: string;
30
+ stage?: 'review-blocked' | 'gate-failed';
28
31
  cellId: string;
29
32
  depth: number;
30
33
  draftHash: string;
@@ -54,6 +57,17 @@ export interface FollowUpMergeInput {
54
57
  goalFile?: string;
55
58
  }
56
59
 
60
+ export interface FollowUpBlockedInput {
61
+ runId: string;
62
+ prNumber?: number;
63
+ stage: 'review-blocked' | 'gate-failed';
64
+ unresolvedMustFix?: readonly string[];
65
+ decompositionPieces?: readonly string[];
66
+ feature: string;
67
+ cellId?: string;
68
+ goalFile?: string;
69
+ }
70
+
57
71
  export interface FollowUpSeams {
58
72
  stateRoot?: string;
59
73
  mode?: FollowUpMode;
@@ -144,10 +158,15 @@ export function followUpDraftHash(text: string): string {
144
158
  return createHash('sha256').update(text).digest('hex').slice(0, 16);
145
159
  }
146
160
 
161
+ /** Legacy merge rows have no ending; blocked rows use run identity even without a PR. */
162
+ function followUpRecordKey(record: Pick<FollowUpDraftRecord, 'prNumber' | 'ending' | 'runId'>): string {
163
+ return record.ending === 'blocked' ? `run:${record.runId}` : `pr:${record.prNumber}`;
164
+ }
165
+
147
166
  /** Chain length of follow-up goals already recorded for this cell, before this one. */
148
- export function followUpChainDepth(prior: readonly Pick<FollowUpDraftRecord, 'kind' | 'prNumber'>[]): number {
149
- // 한 PR 이 «기록 → 대기열 확정» 두 줄을 남길 수 있으니 PR 번호로 센다.
150
- return new Set(prior.filter((record) => record.kind === 'draft' || record.kind === 'op-card-required').map((record) => record.prNumber)).size;
167
+ export function followUpChainDepth(prior: readonly Pick<FollowUpDraftRecord, 'kind' | 'prNumber' | 'ending' | 'runId'>[]): number {
168
+ // 기록 → 대기열 확정 두 줄은 하나로 세되, PR 없는 서로 다른 런은 분리한다.
169
+ return new Set(prior.filter((record) => record.kind === 'draft' || record.kind === 'op-card-required').map(followUpRecordKey)).size;
151
170
  }
152
171
 
153
172
  /** Seat = the cell's owner. `TC/rel` keeps the seat `TC`. Unknown or absent owners go to OP (ONEDOOR). */
@@ -175,13 +194,23 @@ function defaultReadDrafts(stateRoot: string, cellId: string): FollowUpDraftReco
175
194
  return out;
176
195
  }
177
196
 
178
- /** 같은 PR 은 칸과 무관하게 한 번 — 칸 id 가 달리 들어와도 다시 만들지 않는다. */
179
- function defaultPrRecorded(stateRoot: string, prNumber: number): boolean {
197
+ /** 같은 PR 또는 같은 blocked 런은 칸과 무관하게 한 번 기록한다. */
198
+ function defaultRecordExists(stateRoot: string, key: string): boolean {
180
199
  let text = '';
181
200
  try { text = readFileSync(followUpDraftsPath(stateRoot), 'utf8'); } catch { return false; }
182
201
  return text.split('\n').some((line) => {
183
202
  if (!line.trim()) return false;
184
- try { return (JSON.parse(line) as FollowUpDraftRecord).prNumber === prNumber; } catch { return false; }
203
+ try { return followUpRecordKey(JSON.parse(line) as FollowUpDraftRecord) === key; } catch { return false; }
204
+ });
205
+ }
206
+
207
+ function defaultAppendFirst(stateRoot: string, record: FollowUpDraftRecord): boolean {
208
+ const path = followUpDraftsPath(stateRoot);
209
+ mkdirSync(dirname(path), { recursive: true });
210
+ return withFileLockSync(`${path}.lock`, () => {
211
+ if (defaultRecordExists(stateRoot, followUpRecordKey(record))) return false;
212
+ defaultAppendDraft(stateRoot, record);
213
+ return true;
185
214
  });
186
215
  }
187
216
 
@@ -209,7 +238,10 @@ export async function recordFollowUpOnMerge(input: FollowUpMergeInput, seams: Fo
209
238
  const log = seams.log ?? ((category, event, data) => { debug.log(category, event, data); });
210
239
  try {
211
240
  const remainings = collectRemainings(input);
212
- if (remainings.length === 0) return null;
241
+ if (remainings.length === 0) {
242
+ log('self-implement.follow-up', 'draft-skipped-empty', { ending: 'merged', prNumber: input.prNumber });
243
+ return null;
244
+ }
213
245
  // No injected store and no explicit state root: this is the test process.
214
246
  // Do not open the operational ledger or the harness queue.
215
247
  // A test process handed the operational root (defaultSeams) is refused the same way.
@@ -222,8 +254,9 @@ export async function recordFollowUpOnMerge(input: FollowUpMergeInput, seams: Fo
222
254
  return null;
223
255
  }
224
256
  const prior = (seams.readDrafts ?? ((id) => defaultReadDrafts(stateRoot, id)))(cellId);
225
- if (prior.some((record) => record.prNumber === input.prNumber)) return null;
226
- if (!seams.readDrafts && defaultPrRecorded(stateRoot, input.prNumber)) return null;
257
+ const key = followUpRecordKey({ prNumber: input.prNumber });
258
+ if (prior.some((record) => followUpRecordKey(record) === key)) return null;
259
+ if (!seams.readDrafts && defaultRecordExists(stateRoot, key)) return null;
227
260
  const depth = followUpChainDepth(prior) + 1;
228
261
  const firstLine = originalAskFirstLine(input.feature);
229
262
  const mode = seams.mode ?? readFollowUpMode();
@@ -245,39 +278,37 @@ export async function recordFollowUpOnMerge(input: FollowUpMergeInput, seams: Fo
245
278
  const append = seams.appendDraft ?? ((row: FollowUpDraftRecord) => defaultAppendDraft(stateRoot, row));
246
279
  const appendFirst = seams.appendDraft
247
280
  ? (row: FollowUpDraftRecord) => { append(row); return true; }
248
- : (row: FollowUpDraftRecord) => (mkdirSync(dirname(followUpDraftsPath(stateRoot)), { recursive: true }), withFileLockSync(`${followUpDraftsPath(stateRoot)}.lock`, () => {
249
- if (defaultPrRecorded(stateRoot, row.prNumber)) return false;
250
- defaultAppendDraft(stateRoot, row);
251
- return true;
252
- }));
281
+ : (row: FollowUpDraftRecord) => defaultAppendFirst(stateRoot, row);
253
282
  if (!overDepth && mode === 'live' && draft) record.seat = seatForCellOwner((seams.cellOwner ?? defaultCellOwner)(cellId));
254
283
  // 원장 기록을 먼저 확정한다 — 기록이 실패하면 대기열에 넣지 않는다(같은 PR 한 번 · 원장 밖 연결골 0).
255
284
  if (!appendFirst(record)) return null;
256
285
  if (!overDepth && mode === 'live' && draft && record.seat) {
257
286
  const seat = record.seat;
258
- if (testProcess && !seams.enqueue) return record;
259
- try {
260
- await (seams.enqueue ?? ((item) => addHarnessQueue({ seat: item.seat, say: item.say, idempotencyKey: item.idempotencyKey })))({
261
- seat,
262
- say: draft,
263
- idempotencyKey: `follow-up:${input.prNumber}`,
264
- });
265
- record.queued = true;
266
- } catch (error) {
267
- // 대기열 넣기가 실패해도 초안은 남긴다 — 같은 PR 은 다시 오지 않으므로 여기서 잃으면 영영 없다.
268
- // queued=false ⊕ enqueueError 로 원장에 남기고, 재투입은 같은 idempotencyKey 로 사람이·다음 수리 노드가 한다.
269
- record.enqueueError = (error instanceof Error ? error.message : String(error)).slice(0, 300);
270
- log('self-implement.follow-up', 'enqueue-failed', { prNumber: input.prNumber, seat, error: record.enqueueError });
271
- }
272
- // 대기열 결과를 원장에 한 줄 더 — 이 쓰기의 실패는 대기열 실패와 다른 사건이다.
273
- try {
274
- append({ ...record });
275
- } catch (error) {
276
- log('self-implement.follow-up', 'ledger-confirm-failed', {
277
- prNumber: input.prNumber, seat, queued: record.queued, error: error instanceof Error ? error.message : String(error),
278
- });
287
+ if (!(testProcess && !seams.enqueue)) {
288
+ try {
289
+ await (seams.enqueue ?? ((item) => addHarnessQueue({ seat: item.seat, say: item.say, idempotencyKey: item.idempotencyKey })))({
290
+ seat,
291
+ say: draft,
292
+ idempotencyKey: `follow-up:${input.prNumber}`,
293
+ });
294
+ record.queued = true;
295
+ } catch (error) {
296
+ // 대기열 넣기가 실패해도 초안은 남긴다 — 같은 PR 은 다시 오지 않으므로 여기서 잃으면 영영 없다.
297
+ // queued=false ⊕ enqueueError 로 원장에 남기고, 재투입은 같은 idempotencyKey 로 사람이·다음 수리 노드가 한다.
298
+ record.enqueueError = (error instanceof Error ? error.message : String(error)).slice(0, 300);
299
+ log('self-implement.follow-up', 'enqueue-failed', { prNumber: input.prNumber, seat, error: record.enqueueError });
300
+ }
301
+ // 대기열 결과를 원장에 한 줄 더 — 이 쓰기의 실패는 대기열 실패와 다른 사건이다.
302
+ try {
303
+ append({ ...record });
304
+ } catch (error) {
305
+ log('self-implement.follow-up', 'ledger-confirm-failed', {
306
+ prNumber: input.prNumber, seat, queued: record.queued, error: error instanceof Error ? error.message : String(error),
307
+ });
308
+ }
279
309
  }
280
310
  }
311
+ log('self-implement.follow-up', 'drafted', { ending: 'merged', prNumber: input.prNumber, cellId, depth, kind: record.kind, mode, queued: record.queued, remainingCount: remainings.length });
281
312
  return record;
282
313
  } catch (error) {
283
314
  log('self-implement.follow-up', 'draft-failed', {
@@ -287,3 +318,48 @@ export async function recordFollowUpOnMerge(input: FollowUpMergeInput, seams: Fo
287
318
  return null;
288
319
  }
289
320
  }
321
+
322
+ /** Blocked runs leave a draft in the ledger only, even when follow-up mode is live. */
323
+ export async function recordFollowUpOnBlocked(input: FollowUpBlockedInput, seams: FollowUpSeams = {}): Promise<FollowUpDraftRecord | null> {
324
+ const log = seams.log ?? ((category, event, data) => { debug.log(category, event, data); });
325
+ const prNumber = input.prNumber ?? 0;
326
+ try {
327
+ const remainings = collectRemainings({ followUpMustFix: input.unresolvedMustFix, shouldFix: input.decompositionPieces });
328
+ if (remainings.length === 0) {
329
+ log('self-implement.follow-up', 'draft-skipped-empty', { ending: 'blocked', prNumber, runId: input.runId });
330
+ return null;
331
+ }
332
+ const testProcess = process.env.NODE_ENV === 'test' || !!process.env.ELANOUS_TEST_HOME;
333
+ if (!seams.readDrafts && !seams.appendDraft && (!seams.stateRoot || (testProcess && seams.stateRoot === elanousStateRoot()))) return null;
334
+ const stateRoot = seams.stateRoot ?? elanousStateRoot();
335
+ const cellId = followUpCellId(input);
336
+ if (!cellId) {
337
+ log('self-implement.follow-up', 'draft-skipped-no-cell', { ending: 'blocked', prNumber, runId: input.runId });
338
+ return null;
339
+ }
340
+ const prior = (seams.readDrafts ?? ((id) => defaultReadDrafts(stateRoot, id)))(cellId);
341
+ const key = followUpRecordKey({ ending: 'blocked', runId: input.runId, prNumber });
342
+ if (prior.some((record) => followUpRecordKey(record) === key)) return null;
343
+ if (!seams.readDrafts && defaultRecordExists(stateRoot, key)) return null;
344
+ const depth = followUpChainDepth(prior) + 1;
345
+ const firstLine = originalAskFirstLine(input.feature);
346
+ const mode = seams.mode ?? readFollowUpMode();
347
+ const overDepth = depth > FOLLOW_UP_DEPTH_LIMIT;
348
+ const draft = overDepth ? undefined : followUpDraftText(firstLine, remainings);
349
+ const record: FollowUpDraftRecord = {
350
+ ending: 'blocked', runId: input.runId, stage: input.stage, prNumber, cellId, depth,
351
+ draftHash: followUpDraftHash(draft ?? `${firstLine}\n${FOLLOW_UP_OP_CARD_REQUIRED}`),
352
+ kind: overDepth ? 'op-card-required' : 'draft', originalAskFirstLine: firstLine, remainings,
353
+ ...(draft ? { draft } : {}),
354
+ ...(overDepth ? { note: FOLLOW_UP_OP_CARD_REQUIRED } : {}),
355
+ queued: false,
356
+ };
357
+ if (seams.appendDraft) seams.appendDraft(record);
358
+ else if (!defaultAppendFirst(stateRoot, record)) return null;
359
+ log('self-implement.follow-up', 'drafted', { ending: 'blocked', prNumber, runId: input.runId, stage: input.stage, cellId, depth, kind: record.kind, mode, queued: false, remainingCount: remainings.length });
360
+ return record;
361
+ } catch (error) {
362
+ log('self-implement.follow-up', 'draft-failed', { ending: 'blocked', prNumber, runId: input.runId, stage: input.stage, error: error instanceof Error ? error.message : String(error) });
363
+ return null;
364
+ }
365
+ }
@@ -0,0 +1,157 @@
1
+ import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { basename, isAbsolute, join, resolve } from 'node:path';
4
+ import { debug } from '../debug/log.js';
5
+ import { runGitCommand, type GitCommandRunner } from '../git-fs/runner.js';
6
+
7
+ export interface GateWorktreeReapResult {
8
+ ok: boolean;
9
+ listed: number;
10
+ candidates: number;
11
+ removed: number;
12
+ keptLive: number;
13
+ keptYoung: number;
14
+ deferred: number;
15
+ failed: number;
16
+ orphanDirsRemoved: number;
17
+ }
18
+
19
+ export interface GateWorktreeReapOptions {
20
+ prefixes?: readonly string[];
21
+ minAgeMs?: number;
22
+ max?: number;
23
+ }
24
+
25
+ export interface GateWorktreeReapDeps {
26
+ run?: GitCommandRunner;
27
+ isPidAlive?: (pid: number) => boolean;
28
+ now?: () => number;
29
+ tmpRoots?: readonly string[];
30
+ }
31
+
32
+ interface Registration { path: string; reason?: string }
33
+
34
+ function pidAlive(pid: number): boolean {
35
+ try {
36
+ process.kill(pid, 0);
37
+ return true;
38
+ } catch (error) {
39
+ return (error as NodeJS.ErrnoException).code === 'EPERM';
40
+ }
41
+ }
42
+
43
+ function registrations(output: string): Registration[] {
44
+ return output.split(/\n\s*\n/).flatMap((block) => {
45
+ const lines = block.split('\n');
46
+ const path = lines.find((line) => line.startsWith('worktree '))?.slice('worktree '.length);
47
+ if (!path || !isAbsolute(path)) return [];
48
+ return [{ path: resolve(path), reason: lines.find((line) => line.startsWith('locked '))?.slice('locked '.length) }];
49
+ });
50
+ }
51
+
52
+ function metadataFor(path: string, metadataRoot: string): string | undefined {
53
+ for (const entry of readdirSync(metadataRoot, { withFileTypes: true })) {
54
+ if (!entry.isDirectory()) continue;
55
+ const folder = join(metadataRoot, entry.name);
56
+ const gitdir = join(folder, 'gitdir');
57
+ try {
58
+ if (!lstatSync(gitdir).isFile()) continue;
59
+ const target = readFileSync(gitdir, 'utf8').trim();
60
+ if (isAbsolute(target) && resolve(target) === join(path, '.git')) return folder;
61
+ } catch { continue; }
62
+ }
63
+ return undefined;
64
+ }
65
+
66
+ /** Only gate-prefixed registrations and direct children of the supplied temp roots are eligible. */
67
+ export function reapStaleGateWorktrees(
68
+ cwd: string,
69
+ opts: GateWorktreeReapOptions = {},
70
+ deps: GateWorktreeReapDeps = {},
71
+ ): GateWorktreeReapResult {
72
+ const result: GateWorktreeReapResult = {
73
+ ok: false, listed: 0, candidates: 0, removed: 0, keptLive: 0,
74
+ keptYoung: 0, deferred: 0, failed: 0, orphanDirsRemoved: 0,
75
+ };
76
+ const emit = (): GateWorktreeReapResult => {
77
+ if (!result.ok || result.candidates > 0) debug.log('self-implement.gate-baseline', 'reap', { ...result });
78
+ return result;
79
+ };
80
+ const run = deps.run ?? runGitCommand;
81
+ const git = (args: string[]) => run(cwd, args, { encoding: 'utf8', timeout: 60_000 });
82
+ try {
83
+ const listing = git(['worktree', 'list', '--porcelain']);
84
+ if (listing.status !== 0 || listing.signal || typeof listing.stdout !== 'string') return emit();
85
+ if (!listing.stdout.startsWith('worktree ')) return emit();
86
+ const entries = registrations(listing.stdout);
87
+ result.ok = true;
88
+ result.listed = entries.length;
89
+ const prefixes = opts.prefixes ?? ['elanous-gate-baseline-'];
90
+ const minAgeMs = opts.minAgeMs ?? 2 * 60 * 60_000;
91
+ const max = Math.max(0, opts.max ?? 20);
92
+ const now = (deps.now ?? Date.now)();
93
+ const isAlive = deps.isPidAlive ?? pidAlive;
94
+ const registered = new Set(entries.map((entry) => entry.path));
95
+ const matches = (path: string) => prefixes.some((prefix) => prefix.length > 0 && basename(path).startsWith(prefix));
96
+ const candidates = entries.filter((entry) => matches(entry.path));
97
+ result.candidates = candidates.length;
98
+ let metadataRoot: string | undefined;
99
+ const getMetadataRoot = (): string | undefined => {
100
+ if (metadataRoot) return metadataRoot;
101
+ const common = git(['rev-parse', '--git-common-dir']);
102
+ if (common.status !== 0 || typeof common.stdout !== 'string' || !common.stdout.trim()) return undefined;
103
+ const root = common.stdout.trim();
104
+ metadataRoot = join(realpathSync(isAbsolute(root) ? root : resolve(cwd, root)), 'worktrees');
105
+ return metadataRoot;
106
+ };
107
+ let attempted = 0;
108
+ for (const entry of candidates) {
109
+ try {
110
+ const owner = entry.reason?.match(/^elanous-gate pid=([1-9]\d*)\b/);
111
+ if (owner && isAlive(Number(owner[1]))) {
112
+ result.keptLive++;
113
+ continue;
114
+ }
115
+ const started = owner ? entry.reason?.match(/\bstarted=(\d+)\b/) : undefined;
116
+ const startedAt = started ? Number(started[1]) : undefined;
117
+ const root = startedAt === undefined || !existsSync(entry.path) ? getMetadataRoot() : undefined;
118
+ const metadata = root ? metadataFor(entry.path, root) : undefined;
119
+ const timestamp = startedAt !== undefined && Number.isSafeInteger(startedAt)
120
+ ? startedAt : metadata ? statSync(metadata).mtimeMs : undefined;
121
+ if (timestamp === undefined || !Number.isFinite(timestamp)) { result.failed++; continue; }
122
+ if (now - timestamp < minAgeMs) { result.keptYoung++; continue; }
123
+ if (attempted >= max) { result.deferred++; continue; }
124
+ attempted++;
125
+ const removed = git(['worktree', 'remove', '--force', '--force', entry.path]);
126
+ if (removed.status === 0) { result.removed++; continue; }
127
+ // A missing checkout cannot be removed by git. Verify the single metadata record before unlinking it.
128
+ if (!existsSync(entry.path) && metadata && metadataFor(entry.path, root!) === metadata) {
129
+ rmSync(metadata, { recursive: true });
130
+ result.removed++;
131
+ } else result.failed++;
132
+ } catch { result.failed++; }
133
+ }
134
+ for (const root of deps.tmpRoots ?? [realpathSync(tmpdir())]) {
135
+ try {
136
+ const realRoot = realpathSync(root);
137
+ for (const entry of readdirSync(realRoot, { withFileTypes: true })) {
138
+ const path = join(realRoot, entry.name);
139
+ if (!entry.isDirectory() || !matches(path) || registered.has(path)) continue;
140
+ try {
141
+ const stat = lstatSync(path);
142
+ if (!stat.isDirectory() || now - stat.mtimeMs < minAgeMs) continue;
143
+ // A checkout owned by another repository is absent from this repository's listing.
144
+ // Its .git file (or directory) must never be treated as an unregistered orphan.
145
+ // With no .git, only an empty directory is provably unused; preserve unknown contents.
146
+ if (existsSync(join(path, '.git')) || readdirSync(path).length !== 0) continue;
147
+ rmSync(path, { recursive: true });
148
+ result.orphanDirsRemoved++;
149
+ } catch { result.failed++; }
150
+ }
151
+ } catch { result.failed++; }
152
+ }
153
+ } catch {
154
+ result.ok = false;
155
+ }
156
+ return emit();
157
+ }
@@ -6,6 +6,7 @@ import { prepareDeterministicChildEnvironment } from '../../scripts/lib/determin
6
6
  import { debug } from '../debug/log.js';
7
7
  import { runGitCommand } from '../git-fs/runner.js';
8
8
  import { linkWorktreeDependencies } from '../git-fs/worktree.js';
9
+ import { reapStaleGateWorktrees } from './gate-baseline-reap.js';
9
10
 
10
11
  export type GateFailureAttribution = 'introduced' | 'preexisting' | 'unknown' | 'precondition-unmet' | 'flaky-timeout' | 'flaky-rerun';
11
12
  export type GateBaselinePresence = 'present' | 'missing' | 'unknown';
@@ -25,7 +26,7 @@ export interface GateTestFailure {
25
26
  attribution: GateFailureAttribution;
26
27
  /** 기준선 실행 산출과 기존 missingAtBase 입력에서 독립적으로 도출한 파일 존재 상태. */
27
28
  baselinePresence: GateBaselinePresence;
28
- attributedBy?: 'name-across-files';
29
+ attributedBy?: 'name-across-files' | 'copied-across-files';
29
30
  precondition?: GateFailurePrecondition;
30
31
  /** 같은 gate 실행 안에서 같은 시험의 통과 기록이 있으면 `may-vary`로 보존한다. 타임아웃은 재실행 결과 변동성도 함께 표현한다. */
31
32
  timeoutVariability?: TimeoutVariability;
@@ -564,6 +565,26 @@ export function classifyGateTestFailures(
564
565
  debug.log('self-implement.gate', 'attributed-across-files', { name: path, file: failure.file, baselineFile: baseline.file });
565
566
  return { ...failure, attribution: 'preexisting' as const, attributedBy: 'name-across-files' as const, baselinePresence };
566
567
  }
568
+ const baseCandidates = path ? baselineFailures.filter((entry) => testPath(entry) === path) : [];
569
+ const original = baseCandidates.length === 1 ? baseCandidates[0] : undefined;
570
+ const currentCandidates = path ? worktreeFailures.filter((entry) => testPath(entry) === path) : [];
571
+ const currentOriginal = original && currentCandidates.length === 2
572
+ ? currentCandidates.find((entry) => entry.file === original.file)
573
+ : undefined;
574
+ const copies = currentCandidates.filter((entry) => entry.file === failure.file);
575
+ // Only file position tokens (`[file://]<file>.<ext>:<line>:<col>`, any extension) are erased. A token preceded by `:`, `/`,
576
+ // a word char, `.` or `-` (URL hosts such as `https://a.example.com:443:10`) is part of the message and stays.
577
+ const comparableDiagnostic = (diagnostic: string): string =>
578
+ diagnostic.replace(/(?<![:/\w.-])(?:file:\/\/)?(?:\/?[A-Za-z]:)?[^\s():]+\.[A-Za-z][A-Za-z0-9]*:\d+:\d+/g, '');
579
+ if (original?.file && original.file !== failure.file && currentOriginal && copies.length === 1
580
+ && original.diagnostic && currentOriginal.diagnostic && failure.diagnostic
581
+ && ![original, currentOriginal, failure].some((entry) => isTimeoutDiagnostic(entry.diagnostic)
582
+ || matchedGatePrecondition(entry.diagnostic ?? ''))
583
+ && comparableDiagnostic(original.diagnostic) === comparableDiagnostic(currentOriginal.diagnostic)
584
+ && comparableDiagnostic(original.diagnostic) === comparableDiagnostic(failure.diagnostic)) {
585
+ debug.log('self-implement.gate', 'attributed-copy-across-files', { name: path, file: failure.file, baselineFile: original.file });
586
+ return { ...failure, attribution: 'preexisting' as const, attributedBy: 'copied-across-files' as const, baselinePresence };
587
+ }
567
588
  return { ...failure, attribution: 'introduced' as const, baselinePresence };
568
589
  }
569
590
  if (baselineLog === undefined || !failure.file) return { ...failure, attribution: 'unknown' as const, baselinePresence };
@@ -764,11 +785,52 @@ export function classifyBaselineProcess(result: ProcessResult, budget?: { timeou
764
785
  };
765
786
  }
766
787
 
788
+ let lastGateWorktreeReapAt = 0;
789
+
790
+ function reapBeforeGateAdd(cwd: string): void {
791
+ const now = Date.now();
792
+ if (now - lastGateWorktreeReapAt < 10 * 60_000) return;
793
+ lastGateWorktreeReapAt = now;
794
+ try {
795
+ reapStaleGateWorktrees(cwd);
796
+ } catch (error) {
797
+ debug.log('self-implement.gate-baseline', 'reap', { ok: false, error: String(error) });
798
+ }
799
+ }
800
+
801
+ function gateWorktreeAddArgs(dir: string, ref: string): string[] {
802
+ return ['worktree', 'add', '--detach', '--lock', '--reason', `elanous-gate pid=${process.pid} started=${Date.now()}`, dir, ref];
803
+ }
804
+
805
+ function removeGateWorktree(cwd: string, dir: string, addFailed: boolean): void {
806
+ try {
807
+ const registered = addFailed
808
+ ? runGitCommand(cwd, ['worktree', 'list', '--porcelain'], { encoding: 'utf8', timeout: 60_000 })
809
+ : undefined;
810
+ if (addFailed) {
811
+ // git lists real paths (macOS tmpdir() is /var/… while git prints /private/var/…).
812
+ let real = dir;
813
+ try { real = realpathSync(dir); } catch { /* dir already gone: compare the spelling we have */ }
814
+ const lines = registered?.status === 0 ? (registered.stdout ?? '').split('\n') : [];
815
+ if (!lines.includes(`worktree ${dir}`) && !lines.includes(`worktree ${real}`)) return;
816
+ }
817
+ const removed = runGitCommand(cwd, ['worktree', 'remove', '--force', '--force', dir], { encoding: 'utf8', timeout: 60_000 });
818
+ if (removed.status !== 0) debug.log('self-implement', 'gate.baseline.cleanup', {
819
+ stage: addFailed ? 'add-failed-remove' : 'worktree-remove', dir, status: removed.status,
820
+ });
821
+ } catch (error) {
822
+ debug.log('self-implement', 'gate.baseline.cleanup', {
823
+ stage: addFailed ? 'add-failed-remove' : 'worktree-remove', dir, status: null, error: String(error),
824
+ });
825
+ }
826
+ }
827
+
767
828
  export function withBaselineWorktree<T>(cwd: string, baseRef: string, run: (baselineDir: string) => T): T | BaselineProcessResult {
829
+ reapBeforeGateAdd(cwd);
768
830
  const baselineDir = mkdtempSync(join(tmpdir(), 'elanous-gate-baseline-'));
769
831
  let attached = false;
770
832
  try {
771
- const add = runGitCommand(cwd, ['worktree', 'add', '--detach', baselineDir, baseRef], { encoding: 'utf8', timeout: 60_000 });
833
+ const add = runGitCommand(cwd, gateWorktreeAddArgs(baselineDir, baseRef), { encoding: 'utf8', timeout: 60_000 });
772
834
  if (add.status !== 0) return classifyBaselineProcess({ status: add.status, stdout: add.stdout, stderr: add.stderr });
773
835
  attached = true;
774
836
  linkDependencies(cwd, baselineDir);
@@ -781,8 +843,12 @@ export function withBaselineWorktree<T>(cwd: string, baseRef: string, run: (base
781
843
  log: `baseline setup failed: ${String(error)}`,
782
844
  };
783
845
  } finally {
784
- if (attached) runGitCommand(cwd, ['worktree', 'remove', '--force', baselineDir], { encoding: 'utf8', timeout: 60_000 });
785
- rmSync(baselineDir, { recursive: true, force: true });
846
+ removeGateWorktree(cwd, baselineDir, !attached);
847
+ try {
848
+ rmSync(baselineDir, { recursive: true, force: true });
849
+ } catch (error) {
850
+ debug.log('self-implement', 'gate.baseline.cleanup', { stage: 'exception', dir: baselineDir, error: String(error) });
851
+ }
786
852
  }
787
853
  }
788
854
 
@@ -792,11 +858,12 @@ function linkDependencies(cwd: string, dir: string): void {
792
858
  }
793
859
 
794
860
  function withVerifyWorktree<T>(cwd: string, baseRef: string, run: (dir: string) => T): T | BaselineProcessResult {
861
+ reapBeforeGateAdd(cwd);
795
862
  let dir = '';
796
863
  let attached = false;
797
864
  try {
798
865
  dir = mkdtempSync(join(tmpdir(), 'elanous-gate-baseline-'));
799
- const add = runGitCommand(cwd, ['worktree', 'add', '--detach', dir, baseRef], { encoding: 'utf8', timeout: 60_000 });
866
+ const add = runGitCommand(cwd, gateWorktreeAddArgs(dir, baseRef), { encoding: 'utf8', timeout: 60_000 });
800
867
  if (add.status !== 0) return classifyBaselineProcess({ status: add.status, stdout: add.stdout, stderr: add.stderr });
801
868
  attached = true;
802
869
  linkDependencies(cwd, dir);
@@ -805,20 +872,15 @@ function withVerifyWorktree<T>(cwd: string, baseRef: string, run: (dir: string)
805
872
  const reason = `baseline setup failed: ${String(error)}`;
806
873
  return { status: 'unknown', log: reason, output: reason };
807
874
  } finally {
808
- try {
809
- const removed = attached
810
- ? runGitCommand(cwd, ['worktree', 'remove', '--force', dir], { encoding: 'utf8', timeout: 60_000 })
811
- : undefined;
812
- if (removed && removed.status !== 0) {
875
+ if (dir) {
876
+ removeGateWorktree(cwd, dir, !attached);
877
+ try {
878
+ rmSync(dir, { recursive: true, force: true });
879
+ } catch (error) {
813
880
  debug.log('self-implement', 'gate.verify-by-breaking.cleanup', {
814
- stage: 'worktree-remove', dir, status: removed.status, stderr: (removed.stderr ?? '').slice(0, 300),
881
+ stage: 'exception', dir, error: String(error).slice(0, 300),
815
882
  }, { level: 'warn' });
816
883
  }
817
- if (dir) rmSync(dir, { recursive: true, force: true });
818
- } catch (error) {
819
- debug.log('self-implement', 'gate.verify-by-breaking.cleanup', {
820
- stage: 'exception', dir, error: String(error).slice(0, 300),
821
- }, { level: 'warn' });
822
884
  }
823
885
  }
824
886
  }
@@ -118,6 +118,9 @@ export interface SelfGateCliResult {
118
118
  /** New vs. already-present failures (unknown/preconditionUnmet = failures it could not classify). Absent = the test
119
119
  * step did not produce a measurement (e.g. shards unmeasured). */
120
120
  baseline?: { introduced: number; preexisting: number; unknown: number; preconditionUnmet: number };
121
+ /** LIGHT-RC-MEASURE ③ — why the sharded test step produced no measurement (the same text as the
122
+ * `shards: unmeasured (…)` line). Absent when it measured, or on the unsharded path. */
123
+ unmeasuredReason?: string;
121
124
  }
122
125
 
123
126
  /** 시험 단계와 독립인 정책 관문 넷. skipTestStep 이든 시험 통과든 같은 함수를 부른다. */
@@ -667,10 +670,16 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
667
670
  if (options.shards !== undefined) {
668
671
  const sharded = (deps.runShards ?? runShardedGateTests)(cwd, testFiles, selection.baseRef, options.shards);
669
672
  lines.push(`shards: ${sharded.shards.length} (${sharded.shards.map((shard) => `${shard.id}=${shard.files.join(',')}`).join('; ')})${sharded.measurementFailures ? ` · 측정 실패 ${sharded.measurementFailures}` : ''}`);
670
- for (const attempt of sharded.attempts) lines.push(`shard attempt: ${attempt.shardId} #${attempt.attempt}`);
673
+ // 조각이 «못 쟀다»일 때 이유가 줄에 없으면 자리·시간 초과·죽음을 가를 수 없다(OP 10-09 light RC) — 종료 코드·신호를 같이 싣는다.
674
+ const side = (code: number | null, signal: string | null | undefined, junit: string | undefined) => signal ? `signal ${signal}` : code === null ? 'exit ?' : `exit ${code}${junit === undefined ? ' · junit 없음' : ''}`;
675
+ for (const attempt of sharded.attempts) lines.push(`shard attempt: ${attempt.shardId} #${attempt.attempt} · 지금 ${side(attempt.currentExitCode, attempt.currentSignal, attempt.currentJUnit)} · 기준 ${side(attempt.baselineExitCode, attempt.baselineSignal, attempt.baselineJUnit)}`);
671
676
  const { aggregate } = sharded;
672
677
  let shardBaseline: SelfGateCliResult['baseline'];
673
- if (aggregate.status === 'unmeasured') lines.push(`shards: unmeasured (${aggregate.retryShardIds.join(', ') || sharded.reason || 'no complete JUnit'})`);
678
+ let unmeasuredReason: string | undefined;
679
+ if (aggregate.status === 'unmeasured') {
680
+ unmeasuredReason = aggregate.retryShardIds.join(', ') || sharded.reason || 'no complete JUnit';
681
+ lines.push(`shards: unmeasured (${unmeasuredReason})`);
682
+ }
674
683
  else if (aggregate.report) {
675
684
  const report = aggregate.report;
676
685
  logGateCliBaseline(cwd, {
@@ -692,6 +701,7 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
692
701
  lines, changedFiles: selection.files, testFiles, unverified: scope.unverified,
693
702
  documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests,
694
703
  alwaysIncludeMissing, ...(shardBaseline ? { baseline: shardBaseline } : {}),
704
+ ...(unmeasuredReason !== undefined ? { unmeasuredReason } : {}),
695
705
  };
696
706
  }
697
707
 
@@ -156,6 +156,8 @@ export interface RemoteRunOptions {
156
156
  repo: string;
157
157
  host: string;
158
158
  mirror: string;
159
+ /** Exact local commit to run instead of HEAD; permits a dirty worktree. */
160
+ commit?: string;
159
161
  /** argv run from the remote checkout root, e.g. ['bun', 'bin/elanous.mjs', 'self', 'gate', ...]; a function receives
160
162
  * `sha(ref)` for each of `refs` so the remote command names the exact commit, not a ref the host may not have. */
161
163
  argv: RemoteArgv;
@@ -233,12 +235,21 @@ function revParse(runner: GateRemoteRunner, repo: string, ref: string): string |
233
235
 
234
236
  export function runOnRemote(opts: RemoteRunOptions, runner: GateRemoteRunner = realGateRemoteRunner): RemoteRunOutcome {
235
237
  const started = Date.now();
236
- const status = runner.local('git', ['status', '--porcelain'], opts.repo);
237
- if (status.rc !== 0) return { kind: 'infra', reason: 'git-status-failed' };
238
- // A remote checkout can only reproduce a commit — uncommitted or untracked files would silently not be measured.
239
- if (status.stdout.trim()) return { kind: 'infra', reason: 'dirty-tree' };
240
- const commit = revParse(runner, opts.repo, 'HEAD');
241
- if (!commit) return { kind: 'infra', reason: 'head-unresolved' };
238
+ let commit: string;
239
+ if (opts.commit !== undefined) {
240
+ if (!shaPattern.test(opts.commit)) return { kind: 'infra', reason: 'invalid-commit' };
241
+ const object = runner.local('git', ['cat-file', '-t', opts.commit], opts.repo);
242
+ if (object.rc !== 0 || object.stdout.trim() !== 'commit') return { kind: 'infra', reason: 'commit-missing' };
243
+ commit = opts.commit;
244
+ } else {
245
+ const status = runner.local('git', ['status', '--porcelain'], opts.repo);
246
+ if (status.rc !== 0) return { kind: 'infra', reason: 'git-status-failed' };
247
+ // A remote checkout can only reproduce a commit — uncommitted or untracked files would silently not be measured.
248
+ if (status.stdout.trim()) return { kind: 'infra', reason: 'dirty-tree' };
249
+ const head = revParse(runner, opts.repo, 'HEAD');
250
+ if (!head) return { kind: 'infra', reason: 'head-unresolved' };
251
+ commit = head;
252
+ }
242
253
  // Every check measures against merge-base(origin/main); without the local one the host would fall back to its mirror's
243
254
  // (possibly stale) branch — not the same measurement.
244
255
  const mainSha = revParse(runner, opts.repo, 'origin/main');