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
@@ -5,6 +5,7 @@ import { createHash } from 'node:crypto';
5
5
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
6
6
  import { constants as osConstants, hostname } from 'node:os';
7
7
  import { basename, dirname, join, resolve, sep } from 'node:path';
8
+ import { HarnessCliInputError } from '../cli/cli-user-error.js';
8
9
  import { findGitDir } from '../git-fs/locate.js';
9
10
  import { LogStore, logsDbPath } from '../mss/logging/log-store.js';
10
11
  import { loadSelfDevRun } from '../self-dev/run-store.js';
@@ -20,12 +21,15 @@ import { GOAL_TYPES, lintGoalFile, parseGoalId, parseGoalType, resolveGoalAuthor
20
21
  import { templateForGoalType } from '../self-implement/graph-templates.js';
21
22
  import { listRunLedgers, loadFederatedRunLedger, loadRunLedger, queryRunScreenKey, runLedgerDir, type RunLedgerMatch } from '../self-implement/run-ledger.js';
22
23
  import { classifyPodExitStop, recordRunStop, runStopRecorded, RUN_STOP_EVENT } from '../self-implement/run-stop.js';
23
- import { resolveChildLlmEffort, resolveImplementationChildModel } from '../self-dev/dev-cli.js';
24
+ import { ensureOpenRouterChildModelLive, resolveChildLlmEffort, resolveImplementationChildModel } from '../self-dev/dev-cli.js';
24
25
  import { resolveHarnessTarget } from '../self-implement/harness-target-options.js';
25
26
  import { queryRunningRuns } from '../self-implement/running-runs.js';
26
27
  import { DevPipelineError } from '../self-dev/dev-pipeline.js';
27
28
  import { collectDraftMetrics, collectOverlapMetrics, DRAFT_SWEEP_CONCURRENCY, mapBounded, resolveDraftSweepCloseCap, runDraftSweep, sweepFailureReason, type DraftSweepAdapters, type DraftSweepResult, type OverlapMetricAdapters, type SweepDraft, type SweepMergedPr, type SweepReviewGate } from '../self-dev/draft-sweep.js';
28
29
  import { readAskPreflightRowsSince, readSalvagedRowsSince } from '../self-dev/ask-launch-io.js';
30
+ import { replayPodTerminals, type DraftResidueReplayOptions, type PrTerminalRecord } from '../self-dev/draft-residue.js';
31
+ import { draftClaimComment, draftReleaseComment } from '../self-dev/draft-triage-rules.js';
32
+ import { readTaskAgentState, taskAgentStatePath, type TaskCard } from '../task-agent/task-hand.js';
29
33
  import { debug } from '../debug/log.js';
30
34
  import { installHarnessSalvageCommand, installHarnessSalvageRetentionCommand } from './harness-salvage-cli.js';
31
35
  import { decideNestedElanousLaunch, readNestedElanousDepth } from './nested-elanous-policy.js';
@@ -44,8 +48,10 @@ import { resolveRepositoryName } from './repository-name.js';
44
48
  import { installHarnessCliSinkHook } from './harness-cli-sink.js';
45
49
  import { addHarnessQueue, HarnessQueueDuplicateError, harnessQueueReceiptPath, listHarnessQueue, queueSeatForCwd, reconcileHarnessQueue, removeHarnessQueue, setHarnessQueuePriority, tickHarnessQueue, type HarnessQueueDeps, type QueueItem, type QueueSeat } from './harness-queue.js';
46
50
  import { writeHarnessQueueReceipt } from './harness-queue-child.js';
51
+ import { decideBackpressure, readBackpressureSignals, type BackpressureReadDeps } from './dispatch-backpressure.js';
47
52
  import { parseDoorSince, queryLaunchDoors, renderLaunchDoors, type DoorTable } from './launch-stamp.js';
48
53
  import { resolveHarnessSubstrate, type ResolvedHarnessSubstrate } from './harness-substrate-default.js';
54
+ import { podChildProviderRefusal } from '../task-orchestrator/surfaces/pod-child-providers.js';
49
55
  import { runHarnessPlanRfc } from './harness-plan-rfc.js';
50
56
  import { classifyGarbage, isGarbageProcessTarget, type GarbageProcess } from './process-garbage.js';
51
57
  import type { MissionSolveOutcome } from './mission-solve-loop.js';
@@ -97,16 +103,9 @@ export function setHarnessPlanRfcForTesting(fn: typeof runHarnessPlanRfc | undef
97
103
  harnessPlanRfcForTesting = fn;
98
104
  }
99
105
 
100
- export type HarnessSupervisorSource = 'flag' | 'default';
106
+ export { HarnessCliInputError } from '../cli/cli-user-error.js';
101
107
 
102
- /** A command-line value was rejected before any harness work began. */
103
- export class HarnessCliInputError extends Error {
104
- constructor(message: string) {
105
- super(message);
106
- this.name = 'HarnessCliInputError';
107
- Object.defineProperty(this, Symbol.for('elanous.cli.HarnessCliInputError'), { value: true });
108
- }
109
- }
108
+ export type HarnessSupervisorSource = 'flag' | 'default';
110
109
 
111
110
  export interface HarnessAskSayOptions {
112
111
  seat?: QueueSeat;
@@ -427,6 +426,7 @@ export function classifyHarnessPodExit(
427
426
  ): { lines: string[]; reason: PodExitReason | 'pod-failure' } {
428
427
  let podFailure: string | undefined;
429
428
  let podJobFailed = false;
429
+ let podChildFailed = false;
430
430
  for (const line of output.split('\n').reverse()) {
431
431
  if (!line.trimStart().startsWith('[{') || !line.includes('"error"')) continue;
432
432
  try {
@@ -438,6 +438,7 @@ export function classifyHarnessPodExit(
438
438
  if (typeof error?.code !== 'string' || typeof error.message !== 'string' || !error.code.startsWith('pod-')) continue;
439
439
  podFailure = error.message;
440
440
  podJobFailed = error.code === 'pod-job-failed';
441
+ podChildFailed = error.code === 'pod-child-failed';
441
442
  break;
442
443
  }
443
444
  } catch { /* Non-result stdout cannot establish that a Pod child ran. */ }
@@ -447,6 +448,8 @@ export function classifyHarnessPodExit(
447
448
  const summary = output.split('\n').find((line) => /\s❌\sfailed · .* — pod-[\w-]+: /.test(line));
448
449
  podFailure = summary?.split(/\s❌\sfailed · .* — pod-[\w-]+: /)[1];
449
450
  podJobFailed = summary?.includes(' — pod-job-failed: ') ?? false;
451
+ // src/self-dev/orchestrate-summary-line.ts prints the pod-child-failed message (the Pod reason) on this line.
452
+ podChildFailed = summary?.includes(' — pod-child-failed: ') ?? false;
450
453
  }
451
454
  // Only the run announced at launch — another run id quoted in the output is not this run (review round 3).
452
455
  const observedRunId = deps.runId ?? harnessPodRunId(output);
@@ -454,9 +457,11 @@ export function classifyHarnessPodExit(
454
457
  if (podFailure) {
455
458
  const childError = podJobFailed ? podFailure.split('childError=')[1]?.split('\\n', 1)[0]?.split('\n', 1)[0] : undefined;
456
459
  try { debug.log('harness.pod', 'exit-classified', { runId, reason: 'pod-failure', status: exit.status, signal: exit.signal ?? null }); } catch { /* observation is fail-soft */ }
457
- return { reason: 'pod-failure', lines: [podJobFailed && childError && childError !== 'no-result-line'
458
- ? `Pod 안 자식이 실패했다 — ${childError}`
459
- : `Pod 실행이 실패했다 — ${podFailure.split('\\n', 1)[0]}`] };
460
+ return { reason: 'pod-failure', lines: [podChildFailed
461
+ ? `Pod 안 자식이 실패했다 — ${podFailure.split('\\n', 1)[0]}`
462
+ : podJobFailed && childError && childError !== 'no-result-line'
463
+ ? `Pod 안 자식이 실패했다 — ${childError}`
464
+ : `Pod 실행이 실패했다 — ${podFailure.split('\\n', 1)[0]}`] };
460
465
  }
461
466
  let ledger: ReturnType<typeof loadRunLedger> = null;
462
467
  let ledgerReadable = false;
@@ -677,6 +682,7 @@ async function onPod(opts: unknown, entrance: 'cli-harness-ask' | 'cli-harness-s
677
682
  output = (output + text).slice(-16_000);
678
683
  } });
679
684
  if (status !== 0) {
685
+ // onPod is the existing ask/say caller: classify the dispatchHarnessOnPod output for both entrances.
680
686
  const classified = classifyHarnessPodExit({ status }, output, { ...(runId ? { runId } : {}) });
681
687
  recordClassifiedHarnessPodExit(runId ?? harnessPodRunId(output), classified.reason, status,
682
688
  { entrance, seat: o.seat, output });
@@ -714,6 +720,25 @@ export function recordHarnessPodStop(
714
720
  } catch { return false; /* ledger observation cannot change Pod output or exit */ }
715
721
  }
716
722
 
723
+ /**
724
+ * POD-ANTHROPIC-PROVIDER ⓓ — 발사 관문과 Pod 가 «한 목록»(`POD_CHILD_PROVIDERS`)을 본다.
725
+ * 🩸 10-10: 관문은 anthropic 을 «예산 판정 밖» 으로 통과시켰고 Pod 단계가 rc=2 로 죽었다(관문·Pod 목록 엇갈림).
726
+ * Pod 기질에서 목록 밖 provider 는 발사 «전»에 Pod 와 같은 문면으로 거부한다 — 로컬 기질은 판정하지 않는다.
727
+ */
728
+ export function podChildProviderLaunchRefusal(substrate: ResolvedHarnessSubstrate['substrate'], childLlmProvider: string | undefined): string | undefined {
729
+ return substrate === 'pod' ? podChildProviderRefusal(childLlmProvider) : undefined;
730
+ }
731
+
732
+ function refusePodChildProviderBeforeLaunch(resolved: ResolvedHarnessSubstrate, opts: { readonly childLlmProvider?: string }): boolean {
733
+ const refusal = podChildProviderLaunchRefusal(resolved.substrate, opts.childLlmProvider);
734
+ if (!refusal) return false;
735
+ console.error(`❌ launch gate: ${refusal}`);
736
+ try { debug.log('execution-loop.launch-gate', 'pod-child-provider-refused', { provider: opts.childLlmProvider?.trim() ?? null, substrate: resolved.substrate }); }
737
+ catch { /* observation is fail-soft */ }
738
+ process.exitCode = 2;
739
+ return true;
740
+ }
741
+
717
742
  const LAUNCH_BUDGET_PROVIDER: Readonly<Record<string, string>> = { 'codex-rotate': CODEX_PROVIDER, grok: GROK_PROVIDER };
718
743
 
719
744
  /**
@@ -785,6 +810,10 @@ async function dispatchHarnessAskSay(
785
810
  // HARNESS-FULL-GRAPH — 여정 조인 키는 이 발사 동안만 환경에 싣는다(자식은 그동안 물려받는다).
786
811
  const journeyPreset = Boolean(process.env[JOURNEY_KEY_ENV]?.trim());
787
812
  try { await runInjectedHarnessHandler(async () => {
813
+ // POD-ANTHROPIC-PROVIDER ⓓ — Pod 가 못 받는 provider 는 모델 검사·대기열·관문 «전»에(그리고 `--dry-run` 머리 줄보다 먼저) 거부한다 —
814
+ // Pod 와 같은 목록·같은 문면. 기질 판정은 아래 resolveLaunchSubstrate 와 같은 리졸버(같은 입력)다.
815
+ if (refusePodChildProviderBeforeLaunch(resolveHarnessSubstrate({ flag: opts as HarnessSubstrateOpts, config: getUserConfig(), env: process.env }), opts)) return;
816
+ if (opts.childLlmModel !== undefined) await ensureOpenRouterChildModelLive(opts.childLlmProvider, opts.childLlmModel, { persist: !isHarnessDryRun(opts) });
788
817
  assertHarnessChildLlmModel(opts);
789
818
  if (isHarnessDryRun(opts)) {
790
819
  resolveLaunchSubstrate(opts);
@@ -2392,6 +2421,16 @@ export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: Dr
2392
2421
  ...(gatePass && !gateFail ? { gate: 'pass' as const } : gateFail ? { gate: 'fail' as const } : {}),
2393
2422
  };
2394
2423
  };
2424
+ const claimCommentsFor = async (repository: string, number: number): Promise<string[]> => {
2425
+ const batched = (await detailFor(repository, number))?.comments;
2426
+ if (batched) return batched;
2427
+ const pages = ghJson<Array<Array<{ body: string; created_at: string }>>>(['api', '--paginate', '--slurp',
2428
+ `repos/${repository}/issues/${number}/comments?per_page=100`], execute);
2429
+ if (!Array.isArray(pages) || pages.some((page) => !Array.isArray(page)
2430
+ || page.some((comment) => typeof comment.body !== 'string' || !Number.isFinite(Date.parse(comment.created_at)))))
2431
+ throw new Error('Incomplete claim comments');
2432
+ return pages.flat().sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at)).map((comment) => comment.body);
2433
+ };
2395
2434
  const landingCommentsFor = async (repository: string, number: number): Promise<string[]> =>
2396
2435
  ((await detailFor(repository, number))?.comments ?? await issueCommentsFor(repository, number, 'landing'))
2397
2436
  .filter((body) => /\blanding-verified\b/i.test(body));
@@ -2520,18 +2559,14 @@ export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: Dr
2520
2559
  execute(['pr', 'close', String(number), '--repo', repository, '--comment', comment]);
2521
2560
  },
2522
2561
  getClaimOwner: async (repository, number) => claimCommentOwner(repository, number, execute),
2523
- getActiveClaimOwner: async (repository, number) => {
2524
- // DRAFT-METRIC: the batched GraphQL comments (oldest first, proven complete) answer without a per-draft REST call.
2525
- const batched = (await detailFor(repository, number))?.comments;
2526
- if (batched) return activeClaimOwnerFromBodies(batched);
2527
- const pages = ghJson<Array<Array<{ body: string; created_at: string }>>>(['api', '--paginate', '--slurp',
2528
- `repos/${repository}/issues/${number}/comments?per_page=100`], execute);
2529
- if (!Array.isArray(pages) || pages.some((page) => !Array.isArray(page)
2530
- || page.some((comment) => typeof comment.body !== 'string' || !Number.isFinite(Date.parse(comment.created_at)))))
2531
- throw new Error('Incomplete claim comments');
2532
- return activeClaimOwnerFromBodies(pages.flat().sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at))
2533
- .map((comment) => comment.body));
2534
- },
2562
+ getActiveClaimOwner: async (repository, number) => activeClaimOwnerFromBodies(await claimCommentsFor(repository, number)),
2563
+ getActiveClaimRunId: async (repository, number) => activeClaimRunIdFromBodies(await claimCommentsFor(repository, number)),
2564
+ getLastClaimReleaseAt: async (repository, number) => lastClaimReleaseAtFromBodies(await claimCommentsFor(repository, number)),
2565
+ listTaskCards: async () => Object.values(readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(taskAgentStatePath()).tasks ?? {}),
2566
+ listPrTerminals: async () => listRunLedgers().matches.flatMap((match) => match.entries.filter((entry) => entry.event === 'pr-terminal')
2567
+ .map((entry) => entry.data as unknown as PrTerminalRecord)),
2568
+ commentDraft: async (repository, number, body) => { execute(['pr', 'comment', String(number), '--repo', repository, '--body', body]); },
2569
+ removeLabel: async (repository, number, name) => { execute(['pr', 'edit', String(number), '--repo', repository, '--remove-label', name]); },
2535
2570
  getReviewGate: async (draft, repository) => reviewGateForDraft(draft, repository),
2536
2571
  };
2537
2572
  }
@@ -2548,6 +2583,8 @@ export interface HarnessDraftSweepDeps {
2548
2583
  readonly runTtl?: RunTtlAdapters;
2549
2584
  /** Test seam for `tools.selfImplement.draftSweepCloseCap`; omitted ⇒ the user config. */
2550
2585
  readonly closeCapConfig?: () => unknown;
2586
+ /** Replay test seam; production reads this instance's host run-ledger directory. */
2587
+ readonly residueReplay?: DraftResidueReplayOptions;
2551
2588
  }
2552
2589
 
2553
2590
  /** RUN-TTL step inside the draft sweep — fail-soft: its failure never changes the sweep verdict. */
@@ -2576,6 +2613,18 @@ export function activeClaimOwnerFromBodies(bodies: readonly string[]): string |
2576
2613
  return last ? draftClaimOwner(last) : undefined;
2577
2614
  }
2578
2615
 
2616
+ export function activeClaimRunIdFromBodies(bodies: readonly string[]): string | undefined {
2617
+ const last = [...bodies].reverse().find((body) => draftClaimOwner(body) !== undefined || body.startsWith('🔧 처리 끝 —'));
2618
+ return last && draftClaimOwner(last) ? / · run (\S+)/.exec(last)?.[1] : undefined;
2619
+ }
2620
+
2621
+ /** Timestamp of the latest marker when it is a release ('' when its time is unreadable); undefined otherwise. */
2622
+ export function lastClaimReleaseAtFromBodies(bodies: readonly string[]): string | undefined {
2623
+ const last = [...bodies].reverse().find((body) => draftClaimOwner(body) !== undefined || body.startsWith('🔧 처리 끝 —'));
2624
+ if (!last || draftClaimOwner(last) !== undefined) return undefined;
2625
+ return /^🔧 처리 끝 — (\S+)/.exec(last)?.[1] ?? '';
2626
+ }
2627
+
2579
2628
  function draftClaimOwner(body: string): string | undefined {
2580
2629
  return /^🔧 처리 중 — owner ([^\n·]+?) · /m.exec(body)?.[1]?.trim();
2581
2630
  }
@@ -2619,12 +2668,12 @@ function installHarnessDraftSweepCommand(harnessCmd: Command, deps: HarnessDraft
2619
2668
  }
2620
2669
  const stalled = PR_LABELS.find((label) => label.axis === 'state' && label.sweep.action === 'close' && label.name.endsWith(':stalled'))!.name;
2621
2670
  execute(['pr', 'edit', number, '--repo', repository, '--add-label', stalled, '--remove-label', running]);
2622
- execute(['pr', 'comment', number, '--repo', repository, '--body', `🔧 처리 끝 — ${(deps.now?.() ?? new Date()).toISOString()}`]);
2671
+ execute(['pr', 'comment', number, '--repo', repository, '--body', draftReleaseComment(deps.now?.() ?? new Date())]);
2623
2672
  } else {
2624
2673
  execute(['pr', 'edit', number, '--repo', repository, '--add-label', running,
2625
2674
  ...otherStates.flatMap((item) => ['--remove-label', item.name])]);
2626
2675
  execute(['pr', 'comment', number, '--repo', repository, '--body',
2627
- `🔧 처리 중 — owner ${owner} · ${(deps.now?.() ?? new Date()).toISOString()}${opts.note?.trim() ? ` · ${opts.note.trim()}` : ''}`]);
2676
+ draftClaimComment(owner!, deps.now?.() ?? new Date(), opts.note)]);
2628
2677
  }
2629
2678
  (deps.write ?? console.log)(`#${number} ${opts.release ? 'release' : 'claim'}: ${repository}`);
2630
2679
  } catch (error) {
@@ -2689,8 +2738,19 @@ function installHarnessDraftSweepCommand(harnessCmd: Command, deps: HarnessDraft
2689
2738
  console.error(`⚠ ${warning}`);
2690
2739
  try { debug.log('self-dev.draft-sweep', 'close-cap-rejected', { warning, closeCap: cap.closeCap, closeCapSource: cap.closeCapSource }); } catch { /* fail-soft */ }
2691
2740
  }
2741
+ let replayClosed = 0;
2742
+ if (opts.apply && (!deps.adapters || deps.residueReplay)) {
2743
+ try {
2744
+ replayClosed = (await replayPodTerminals({ ...deps.residueReplay, repository, closeCap: cap.closeCap })).closed;
2745
+ } catch (error) {
2746
+ // Review r5: a replay that throws may already have closed PRs — spend the whole cap so this tick cannot exceed it.
2747
+ replayClosed = cap.closeCap;
2748
+ debug.log('draft.residue', 'failed', { childRunId: null, prNumber: null, terminalClass: null,
2749
+ owner: 'unknown', ownerSource: 'unknown', step: 'replay', reason: sweepFailureReason(error) });
2750
+ }
2751
+ }
2692
2752
  const result: DraftSweepResult = await runDraftSweep({ repository, apply: opts.apply === true, adapters: deps.adapters ?? github!,
2693
- closeCap: cap.closeCap, closeCapSource: cap.closeCapSource });
2753
+ closeCap: cap.closeCap, closeCapSource: cap.closeCapSource, alreadyClosed: replayClosed });
2694
2754
  const reason = result.error ? sweepFailureReason(result.error) : undefined;
2695
2755
  const ttlStarted = Date.now();
2696
2756
  const runTtl = await draftSweepRunTtl(repository, deps, github);
@@ -2955,6 +3015,7 @@ export interface HarnessCliCommandDeps {
2955
3015
  processObservation?: HarnessProcessObservationDeps;
2956
3016
  draftSweep?: HarnessDraftSweepDeps;
2957
3017
  queue?: HarnessQueueDeps;
3018
+ backpressure?: BackpressureReadDeps;
2958
3019
  goalLookup?: GoalLookupOptions;
2959
3020
  goalArchive?: GoalArchiveOptions;
2960
3021
  ask?: HarnessAskHandler;
@@ -3034,6 +3095,24 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
3034
3095
  installHarnessGoalCommand(harnessCmd, deps.goalLookup, deps.goalArchive);
3035
3096
  installHarnessDraftSweepCommand(harnessCmd, deps.draftSweep);
3036
3097
  const queue = harnessCmd.command('queue').description('자리별 영속 발사 대기열');
3098
+ queue.command('backpressure').description('읽기 전용 발사 역압 판정')
3099
+ .option('--json', '판정 객체 JSON 한 줄').option('--max <n>', '주기당 발사 상한 (기본 6)')
3100
+ .action((opts: { json?: boolean; max?: string }) => {
3101
+ if (opts.max !== undefined && (!/^(0|[1-9][0-9]*)$/.test(opts.max) || !Number.isSafeInteger(Number(opts.max)))) {
3102
+ console.error('❌ --max 는 0 이상의 정수여야 합니다');
3103
+ process.exitCode = 2;
3104
+ return;
3105
+ }
3106
+ try {
3107
+ const signals = readBackpressureSignals(deps.backpressure);
3108
+ const verdict = decideBackpressure(signals, { maxPerCycle: opts.max === undefined ? 6 : Number(opts.max) });
3109
+ debug.log('traffic.backpressure', 'verdict', { launchBudget: verdict.launchBudget, reasons: verdict.reasons, signals: verdict.signals });
3110
+ console.log(opts.json ? JSON.stringify(verdict) : `발사 예산 ${verdict.launchBudget} · 이유 ${verdict.reasons.join(', ') || '없음'}`);
3111
+ } catch (error) {
3112
+ console.error(`❌ backpressure: ${error instanceof Error ? error.message : String(error)}`);
3113
+ process.exitCode = 1;
3114
+ }
3115
+ });
3037
3116
  const queueDeps = deps.queue ?? {};
3038
3117
  let launchedExit: Promise<number> | undefined;
3039
3118
  const immediateLaunch: NonNullable<HarnessQueueDeps['launch']> = queueDeps.launch ?? (async (item: QueueItem, args: string[], root: string) => {
@@ -34,7 +34,8 @@ import { getHarnessSpace, resolveRunIdentity } from './harness-space.js';
34
34
  import type { AutonomyRiskHit, HarnessGroundingRef } from '../self-implement/context-capsule.js';
35
35
  import { AUTO_REVIEW_LABEL, resolveAutoReviewLabels } from '../self-implement/context-capsule.js';
36
36
  import { verbatimOriginalAsk } from '../self-implement/goal-author.js';
37
- import { isSupervisorDecisionSection, splitGoalSections, supervisorGoalDigest } from '../self-implement/goal-digest.js';
37
+ import { extractHarnessReviewAcceptance } from '../self-implement/goal-digest.js';
38
+ export { extractHarnessReviewAcceptance } from '../self-implement/goal-digest.js';
38
39
 
39
40
  const AUTOREVIEW_SENTENCE_LIMIT = 240;
40
41
  const SECURITY_RISK_REASON = '보안/인증 정보';
@@ -222,25 +223,6 @@ async function buildPrBody(
222
223
  } catch { return heuristic(); }
223
224
  }
224
225
 
225
- /** 골 문서에서 `판정 신호` 절만 뽑아 리뷰 acceptance 로 쓴다. 계보 = self-implement seams. */
226
- export function extractHarnessReviewAcceptance(goalDocument: string | undefined): { goal: string | undefined; acceptance: string | undefined } {
227
- let goal: string | undefined;
228
- try {
229
- goal = goalDocument?.trim() || undefined;
230
- } catch {
231
- return { goal: undefined, acceptance: undefined };
232
- }
233
- if (!goal) return { goal: undefined, acceptance: undefined };
234
- try {
235
- const acceptance = splitGoalSections(supervisorGoalDigest(goal, 3000).text)
236
- .find((section) => isSupervisorDecisionSection(section.title) && section.title.includes('판정 신호'))
237
- ?.body.trim() || undefined;
238
- return { goal, acceptance };
239
- } catch {
240
- return { goal, acceptance: undefined };
241
- }
242
- }
243
-
244
226
  function reviewAcceptanceObservation(goal: string | undefined, acceptance: string | undefined): { goalLoaded: boolean; acceptanceChars: number } {
245
227
  return { goalLoaded: Boolean(goal), acceptanceChars: acceptance?.length ?? 0 };
246
228
  }
@@ -1,5 +1,76 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import type { UserConfig } from '../user-config.js';
2
+ import { readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { effectiveInstanceRoot, prodInstanceRoot, treeDerivedRootFor } from '../instance/resolve.js';
5
+ import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
6
+ import { buildUserConfig, getUserConfig, type UserConfig } from '../user-config.js';
7
+ import { resolveCodexQuotaPolicy } from '../oauth/codex-quota-policy.js';
8
+
9
+ /** Key-order-insensitive JSON so equal per-account caps written in another order do not warn. */
10
+ function stableJson(value: unknown): string {
11
+ return JSON.stringify(value, (_key, v: unknown) => v && typeof v === 'object' && !Array.isArray(v)
12
+ ? Object.fromEntries(Object.entries(v as Record<string, unknown>).sort(([a], [b]) => a.localeCompare(b)))
13
+ : v);
14
+ }
15
+
16
+ function readOperationalLaunchConfig(path: string): UserConfig | null {
17
+ let text: string;
18
+ try { text = readFileSync(path, 'utf8'); }
19
+ catch (err) {
20
+ // Only a missing file (fresh install, CI, isolated fixtures) means «no operational policy»; permission or I/O errors refuse.
21
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;
22
+ throw new Error(`launch policy: 운영 config 를 읽을 수 없다 — ${path}`);
23
+ }
24
+ let raw: unknown;
25
+ try { raw = JSON.parse(text); }
26
+ catch { throw new Error(`launch policy: 운영 config 를 읽을 수 없다 — ${path}`); }
27
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error(`launch policy: 운영 config 형식이 잘못됐다 — ${path}`);
28
+ return buildUserConfig(path);
29
+ }
30
+
31
+ /** Launch policy belongs to the host, not to the materialized config in a derived worktree.
32
+ * Explicit test/config universes remain isolated; this only applies to tree-derived launches. */
33
+ export function harnessLaunchPolicyConfig(options: {
34
+ derived?: UserConfig;
35
+ operationalRoot?: string;
36
+ derivedRoot?: string;
37
+ warn?: (line: string) => void;
38
+ /** Reads the operational config at `path`; injected by tests so they never touch the host's real config. */
39
+ readOperational?: (path: string) => UserConfig | null;
40
+ } = {}): UserConfig {
41
+ const derived = options.derived ?? getUserConfig();
42
+ const operationalRoot = options.operationalRoot ?? prodInstanceRoot();
43
+ const derivedRoot = options.derivedRoot ?? effectiveInstanceRoot();
44
+ const isDerived = options.derivedRoot !== undefined
45
+ ? derivedRoot !== operationalRoot
46
+ : derivedRoot !== operationalRoot && !getElanousConfigDirOverride() && (
47
+ process.env.ELANOUS_STATE_DIR_SOURCE === 'derived'
48
+ || derivedRoot === treeDerivedRootFor(process.cwd())
49
+ );
50
+ if (!isDerived) return derived;
51
+ const path = join(operationalRoot, 'config.json');
52
+ const operational = (options.readOperational ?? readOperationalLaunchConfig)(path);
53
+ if (!operational) {
54
+ (options.warn ?? console.error)(`⚠️ launch policy: 운영 config 가 없다 (${path}) — 이 우주의 정책으로 발사`);
55
+ return derived;
56
+ }
57
+ const policy = (config: UserConfig) => ({
58
+ quota: resolveCodexQuotaPolicy(config.llm).policy,
59
+ accountLimits: config.llm?.codexAccountRotationThresholdPercentByAccount,
60
+ fallbackChain: config.llm?.fallbackChain,
61
+ childLlm: config.tools?.selfImplement?.childLlm,
62
+ budgetGate: config.harness?.budgetGate,
63
+ podPool: config.harness?.podPool ?? config.pod?.pool,
64
+ grokApiKeyOptIn: config.harness?.pod?.grokApiKeyOptIn === true,
65
+ });
66
+ const actual = policy(derived);
67
+ const expected = policy(operational);
68
+ if (derived.llm?.codexQuotaPolicy === undefined && derived.llm?.codexCreditsAllowed === undefined
69
+ || stableJson(actual) !== stableJson(expected)) {
70
+ (options.warn ?? console.error)('⚠️ launch policy: 파생 시험 우주 정책이 없거나 운영과 다르다 — 운영 정책으로 발사');
71
+ }
72
+ return operational;
73
+ }
3
74
 
4
75
  export type HarnessSubstrate = 'local' | 'pod';
5
76
  export interface ResolvedHarnessSubstrate {
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // Codex children drop parent env under shell_environment_policy inherit=core, so a
4
4
  // depth marker that only lives in the environment never arrives. Depth is therefore
5
- // carried on the codex argv (`-c shell_environment_policy.set.ELANOUS_NESTED_DEPTH=<n>`).
5
+ // carried on the codex argv (`-c shell_environment_policy.set.ELANOUS_NESTED_DEPTH="<n>"` — TOML 문자열).
6
6
  //
7
7
  // Unset ELANOUS_NESTED_DEPTH is depth 0 (the outer launcher). A missing marker is
8
8
  // not "depth unknown" and does not refuse an ordinary mission spawn.
@@ -50,7 +50,9 @@ export function backendCarriesNestedDepth(backendName: string): boolean {
50
50
  export function nestedDepthCodexArgs(backendName: string, childDepth: number): string[] {
51
51
  if (backendName !== 'codex') return [];
52
52
  if (!Number.isInteger(childDepth) || childDepth < 0) return [];
53
- return ['-c', `${CODEX_NESTED_DEPTH_CONFIG_KEY}=${childDepth}`];
53
+ // 🩸 CODEX-NESTED-DEPTH-QUOTE(2026-10-09): `-c` 값은 TOML 이고 shell_environment_policy.set 은 «문자열» 맵이다.
54
+ // 맨 정수(`=1`)는 codex 0.159.3 에서 «failed to load bootstrap configuration» 으로 자식을 바로 죽인다 → 따옴표로 문자열.
55
+ return ['-c', `${CODEX_NESTED_DEPTH_CONFIG_KEY}="${childDepth}"`];
54
56
  }
55
57
 
56
58
  /**
@@ -69,6 +69,13 @@ if [ $# -lt 1 ] || [ -z "$1" ]; then
69
69
  fi
70
70
  ROLE=$1
71
71
  shift
72
+ # FENCE-LIGHT: only when this host's heartbeat left a lease-cache file and the installed package ships the light fence.
73
+ # No cache file = exactly the CLI path below. The sourced script always exits; returning is a fail-closed error.
74
+ if [ -f "$CONFIG_DIR/hq/lease-cache" ] && [ -f scripts/hq/hq-fence-wrapper.sh ]; then
75
+ . scripts/hq/hq-fence-wrapper.sh
76
+ log_line "light fence returned without a decision (role=$ROLE)"
77
+ exit 1
78
+ fi
72
79
  "$BUN" "$ENTRY" --config-dir "$CONFIG_DIR" hq fence --role "$ROLE" -- /bin/sh -c "$*"
73
80
  rc=$?
74
81
  if [ "$rc" -ne 0 ]; then alert "hq-fence: fence failed (rc=$rc, role=$ROLE)"; fi
package/src/hq/hq.ts CHANGED
@@ -14,8 +14,8 @@ import { fenceOutcomeDir, recordFenceOutcome } from './fence-outcomes.js';
14
14
  import { promoteHq, proposeHqPromotion, writeOpSeatRequest } from './promote.js';
15
15
  import type { HqOpRequestWriter, PromoteResult } from './promote.js';
16
16
  import {
17
- DEFAULT_TTL_SECONDS, decideAcquire, decideArbiterCheck, decideFence, decideRelease, decideRenew, defaultSshRunner,
18
- fileLeaseStore, leaseExpired, parseLease, probeReachable, recordView, serializeLease, sshLeaseStore, sshReachable, localShellRunner,
17
+ DEFAULT_TTL_SECONDS, LOCAL_LEASE_CACHE_SECONDS, decideAcquire, decideArbiterCheck, decideFence, decideRelease, decideRenew, defaultSshRunner,
18
+ fileLeaseStore, leaseExpired, parseLease, probeReachable, recordView, serializeLease, serializeLocalLeaseCache, sshLeaseStore, sshReachable, localShellRunner,
19
19
  type HostProbe, type LeaseRecord, type LeaseStore, type LocalHqState, type SshRunner,
20
20
  } from './lease.js';
21
21
 
@@ -163,6 +163,30 @@ function writeLocal(path: string, state: LocalHqState): void {
163
163
  renameSync(tmp, path);
164
164
  }
165
165
 
166
+ /** FENCE-LIGHT host-local hint (`<config>/hq/lease-cache`), not authority: only a successful holder renewal writes it. */
167
+ const leaseCachePath = (r: Resolved): string => join(dirname(r.localPath), 'lease-cache');
168
+ function dropHeartbeatCache(r: Resolved): void {
169
+ try { rmSync(leaseCachePath(r), { force: true }); }
170
+ catch (error) { observe(r, 'hq.lease', 'cache-invalidate-failed', { error: String(error).slice(0, 200) }); }
171
+ }
172
+ function writeHeartbeatCache(r: Resolved, record: LeaseRecord): void {
173
+ const path = leaseCachePath(r);
174
+ try {
175
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
176
+ const confirmedAt = r.now();
177
+ const expiresAt = Math.min(confirmedAt + LOCAL_LEASE_CACHE_SECONDS, record.renewedAt + record.ttlSeconds);
178
+ if (expiresAt <= confirmedAt) return;
179
+ const tempDir = mkdtempSync(`${path}.`);
180
+ try {
181
+ const tmp = join(tempDir, 'cache');
182
+ writeFileSync(tmp, serializeLocalLeaseCache({ holder: record.holder, generation: record.generation, expiresAt, host: r.me, machine: hostname().replace(/\.local$/, ''), confirmedAt }), { mode: 0o600 });
183
+ renameSync(tmp, path);
184
+ } finally { rmSync(tempDir, { recursive: true, force: true }); }
185
+ } catch (error) {
186
+ observe(r, 'hq.lease', 'cache-write-failed', { error: String(error).slice(0, 200) });
187
+ }
188
+ }
189
+
166
190
  /** Highest lease generation this host ever observed (null = never). */
167
191
  /** The seen-generation marker this host keeps (hq.seenGenerationFile · default ~/.elanous-hq/seen-generation). */
168
192
  export function hqSeenGenerationPath(config: Pick<HqConfig, 'seenGenerationFile'>): string {
@@ -241,6 +265,7 @@ export function hqLease(action: LeaseAction, deps: HqDeps = {}, opts: { host?: s
241
265
  const result = mutate(r, (record, now) => action === 'acquire' ? decideAcquire(record, r.me, now, r.ttl)
242
266
  : action === 'renew' ? decideRenew(record, r.me, local.generation, now) : decideRelease(record, r.me, expected));
243
267
  noteSeen(r, result.record);
268
+ if (result.ok) dropHeartbeatCache(r);
244
269
  if (result.ok && action !== 'release') writeLocal(r.localPath, { holder: result.record.holder, generation: result.record.generation, confirmedAt: r.now(), ttlSeconds: result.record.ttlSeconds });
245
270
  if (result.ok && action === 'release') writeLocal(r.localPath, { ...local, holder: undefined, confirmedAt: undefined });
246
271
  observe(r, 'hq.lease', result.ok ? (action === 'acquire' ? 'acquired' : action === 'renew' ? 'renewed' : 'released') : `${action}-refused`,
@@ -255,6 +280,8 @@ export function hqLease(action: LeaseAction, deps: HqDeps = {}, opts: { host?: s
255
280
  export function hqHeartbeat(deps: HqDeps = {}) {
256
281
  const r = resolve(deps);
257
282
  const local = readLocal(r.localPath);
283
+ // Never extend a prior positive hint through an unreachable/refused heartbeat.
284
+ dropHeartbeatCache(r);
258
285
  let read: { now: number; raw: string | null };
259
286
  try { read = r.store.read(); } catch (error) {
260
287
  const standbyUp = local.holder === r.me ? sshReachable(r.standby, r.ssh) : false;
@@ -273,6 +300,7 @@ export function hqHeartbeat(deps: HqDeps = {}) {
273
300
  if (renewed.ok) {
274
301
  noteSeen(r, renewed.record);
275
302
  writeLocal(r.localPath, { holder: r.me, generation: renewed.record.generation, confirmedAt: r.now(), ttlSeconds: renewed.record.ttlSeconds });
303
+ if (record.renewedAt !== 0 && !leaseExpired(renewed.record, r.now())) writeHeartbeatCache(r, renewed.record);
276
304
  observe(r, 'hq.lease', 'renewed', { generation: renewed.record.generation });
277
305
  return { outcome: 'renewed' as const, generation: renewed.record.generation };
278
306
  }
@@ -282,6 +310,7 @@ export function hqHeartbeat(deps: HqDeps = {}) {
282
310
  // Not the holder: report the view, keep the granted generation, stay standby.
283
311
  const seen = probeReachable(record.holder, r.probe);
284
312
  const reachable = seen.reachable;
313
+ // FENCE-LIGHT: a standby never writes the cache (the shell fence only fast-paths a fresh «this host holds» line).
285
314
  mutate(r, (current) => current ? { ok: true, next: recordView(current, r.me, reachable, read.now) } : { ok: false, reason: 'no lease' });
286
315
  if (leaseExpired(record, read.now)) observe(r, 'hq.lease', 'expired-seen', { holder: record.holder, generation: record.generation });
287
316
  writeLocal(r.localPath, { holder: record.holder, generation: record.generation, ttlSeconds: record.ttlSeconds });
@@ -365,6 +394,8 @@ export function hqFenceDecision(role: HqFenceRole, deps: HqDeps = {}) {
365
394
  failOpen: role !== 'ledger-cli' && r.failOpen.has(role),
366
395
  ...(seenGeneration !== null ? { seenGeneration } : {}),
367
396
  });
397
+ // FENCE-LIGHT: any CLI «do not run» on this host retires a lingering fast-path hint at once.
398
+ if (!decided.run) dropHeartbeatCache(r);
368
399
  if (decided.run && record !== 'unreachable' && record) writeLocal(r.localPath, { holder: r.me, generation: record.generation, confirmedAt: r.now(), ttlSeconds: record.ttlSeconds });
369
400
  observe(r, 'hq.fence', decided.run ? 'allowed' : 'skipped', { role, reason: decided.reason, holder: decided.holder, generation: decided.generation });
370
401
  return decided;
package/src/hq/lease.ts CHANGED
@@ -36,6 +36,19 @@ export function parseLease(raw: string | null): LeaseRecord | null {
36
36
  export const serializeLease = (record: LeaseRecord): string => `${JSON.stringify(record)}\n`;
37
37
  export const leaseExpired = (record: LeaseRecord, now: number): boolean => record.renewedAt + record.ttlSeconds < now;
38
38
 
39
+ /** Host-local, short-lived shell fence snapshot; never the arbiter's CAS lease ledger. */
40
+ export interface LocalLeaseCache { holder: string; generation: number; expiresAt: number; host: string; machine: string; confirmedAt: number }
41
+ export const LOCAL_LEASE_CACHE_SECONDS = 660; // heartbeat cadence 600s + 60s scheduling slack; still below the 1500s lease TTL
42
+ /** A single whitespace-delimited line so /bin/sh can read it without bun or JSON tools. */
43
+ export function serializeLocalLeaseCache(cache: LocalLeaseCache): string {
44
+ if (![cache.holder, cache.host, cache.machine].every(value => /^[A-Za-z0-9_.-]+$/.test(value))
45
+ || !Number.isSafeInteger(cache.generation) || cache.generation < 1
46
+ || !Number.isSafeInteger(cache.expiresAt) || cache.expiresAt < 1
47
+ || !Number.isSafeInteger(cache.confirmedAt) || cache.confirmedAt < 1
48
+ || cache.expiresAt <= cache.confirmedAt || cache.expiresAt - cache.confirmedAt > LOCAL_LEASE_CACHE_SECONDS) throw new Error('invalid local lease cache');
49
+ return `${cache.holder} ${cache.generation} ${cache.expiresAt} ${cache.host} ${cache.machine} ${cache.confirmedAt}\n`;
50
+ }
51
+
39
52
  /** acquire: only when there is no lease or it has expired; a new holder gets the next generation. */
40
53
  export function decideAcquire(record: LeaseRecord | null, me: string, now: number, ttlSeconds = DEFAULT_TTL_SECONDS):
41
54
  { ok: true; next: LeaseRecord } | { ok: false; reason: string } {