elanous 0.2.24 → 0.2.25

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 (551) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +36 -0
  8. package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +148 -0
  10. package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1454-37fd16f479f5554a.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/{8532.a86e99acf9b761cb.js → 1516.83dd2c1b86b4e507.js} +2 -2
  16. package/apps/pwa/out/_next/static/chunks/{89849432.9eaa2f4c9c010965.js → 16e57f67.3ea19e893461e611.js} +3 -3
  17. package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{1505.5826671109111e75.js → 1743.563d3168e95825ef.js} +2 -2
  19. package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +27 -0
  20. package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +24 -0
  25. package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +32 -0
  28. package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2846.d6a433b8663819a5.js +309 -0
  30. package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +34 -0
  31. package/apps/pwa/out/_next/static/chunks/{5967-c0a80f8ffe5d4050.js → 3259-86f3be56e43eaf6a.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +287 -0
  36. package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/{5578.ac963634373b28c6.js → 4084.15ecaf4240bd9e77.js} +2 -2
  41. package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{8438.ee7f0df3b3f6fcb4.js → 4204.a409ab6250c0f6a8.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +8 -0
  47. package/apps/pwa/out/_next/static/chunks/4565-67e4c620597965c8.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/{7905.b230b9d06cb4ad5d.js → 4593.10f5b9bd702d4a6c.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +104 -0
  51. package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +149 -0
  53. package/apps/pwa/out/_next/static/chunks/{8569.b853a8daa8f31d12.js → 5081.a240b63fad28663a.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{2528.0af5c0e1fad88df6.js → 5408.377c8c543635b81f.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/{9502-32c5dc22e8f120f5.js → 5492-e05e26a033ba80d2.js} +3 -3
  61. package/apps/pwa/out/_next/static/chunks/5785-ea8d2c633b6688e3.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/599-a914cc0468f56143.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +23 -0
  67. package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{5974.360f8441eb0ac1ec.js → 6196.34d6b229079e9e28.js} +1 -1
  70. package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +77 -0
  72. package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +64 -0
  74. package/apps/pwa/out/_next/static/chunks/{ce383d63.d2ede338788ed18e.js → 65ebff95.081daeff622d238e.js} +1 -1
  75. package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +2 -0
  77. package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/{83cfc5c8.349535543c1548b6.js → 6def8a8e.c81f9ca41028eccf.js} +1 -1
  79. package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/{2721.bc9a8f36bd85c07a.js → 7483.ba01c6c209b81bba.js} +1 -1
  84. package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +62 -0
  87. package/apps/pwa/out/_next/static/chunks/{6702.ebbd165d5e4a4a14.js → 7752.5cbdd0b433c54af9.js} +1 -1
  88. package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/{8925-2abfb48af477fb7f.js → 8085-1e5fce59500a2cc2.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +226 -0
  96. package/apps/pwa/out/_next/static/chunks/{b4e12462-5fab4a813a63dadd.js → 83a80514-b897b64df43ce108.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +93 -0
  98. package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +24 -0
  99. package/apps/pwa/out/_next/static/chunks/{8264.00e434fbd02e9311.js → 8578.dff22d988cc2b106.js} +3 -3
  100. package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +115 -0
  103. package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +41 -0
  105. package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +74 -0
  106. package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +94 -0
  107. package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{7518.49161e8f5814abdb.js → 9311.24c8f5ea793253dd.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/{9976.8f28864317639fe6.js → 94.4cfed21c0b781a06.js} +3 -3
  111. package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +90 -0
  113. package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{0e3acd34.d42b2ef87fdf4234.js → 973cbf1b.3bbcf2b41548eca7.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/{6571-926ddf024a6ad5df.js → 9917-9e26abc5f7772735.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +79 -0
  119. package/apps/pwa/out/_next/static/chunks/{740.90b31555290236a9.js → 9974.e77b4ff4884557b3.js} +2 -2
  120. package/apps/pwa/out/_next/static/chunks/{4c5e95ce.83e9b16add6fcd8c.js → ab4d57c2.e90bc2cb31949045.js} +7 -7
  121. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/approvals/page-9360b1285b2a346e.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f08f6529d09ffae1.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/board/page-f000d54d258f9ef6.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-24282bf9f90031a5.js → page-b12149c51f7d04b1.js} +1 -1
  126. package/apps/pwa/out/_next/static/chunks/app/bots/page-22f674e7e4c2c9d5.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8888733e40cea6d1.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/chat/page-9717ec6964b92276.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/consult/page-44eaad486bc98a45.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/control/page-97fa6cf3d34c7eb9.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/decisions/page-305cd294e754906e.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/design-check/page-dea4b795741126fd.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/editor/page-35e05d7450461a67.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/exec/page-45889e7070d11126.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/field/page-16a2e893f83ae4d0.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2638013c0bf7dfd.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/intake/page-56888bc744e08dac.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/layout-c44f93a41167536f.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/live/page-952c6ceec6d9de38.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live-run/page-6d0202af568f4c63.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/loops/page-1b810474507f3702.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/market/page-74366ae2693a7d95.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4fb6fc34e20c07b7.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/morning/page-e9502921f4f01b1f.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/not-found-b6169ea2f09cf287.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6a14333d1b1b3967.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8c91a9a66c9ec90a.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-1d809a87139dd024.js → page-4e634c5b98fd4e93.js} +1 -1
  150. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ed3070d637850548.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/outputs/{page-b92caddb5c715f30.js → page-b9cc8a10bc6078b4.js} +1 -1
  152. package/apps/pwa/out/_next/static/chunks/app/page-3d3fc73dd187ed52.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/reflection/page-128458c8d86fbb5f.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9c04dac0831c2bbb.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/sessions/page-cf0c2b0183991d09.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-04de9ca6d52a3893.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/page-62527677bbc2fdc4.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9a2e09c4a311764c.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/page-bfeb35d69e8b24bb.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/share/page-89cb33bced824e4a.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/showroom/page-b008aff96be56654.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/tasks/page-814394dcbae789b1.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/term/page-6a87325c87f09dd2.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/today/page-6445ac4cbb8dd869.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/trace/page-852170303c6cd755.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/vault/page-087ceeb975ef272b.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-97c7361cc2a19319.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/page-20162174b77f96cf.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8c6901833f897496.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-05a4b2c9b91034aa.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{53746282.1be36038d1abd949.js → e117f801.e92bf10242653497.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +122 -0
  175. package/apps/pwa/out/_next/static/chunks/{0673cc54.8e2ef1c23e49e190.js → f4dfbfc0.a69fb12f854882aa.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +1 -0
  182. package/apps/pwa/out/_next/static/{Q-7iofoxOEv1WX18S35of → dRS6lEhSRRBr1abbzp7fJ}/_buildManifest.js +1 -1
  183. package/apps/pwa/out/approvals/index.html +1 -1
  184. package/apps/pwa/out/approvals/index.txt +22 -22
  185. package/apps/pwa/out/autopilot/index.html +1 -1
  186. package/apps/pwa/out/autopilot/index.txt +22 -22
  187. package/apps/pwa/out/board/index.html +1 -1
  188. package/apps/pwa/out/board/index.txt +22 -22
  189. package/apps/pwa/out/botlab/index.html +1 -1
  190. package/apps/pwa/out/botlab/index.txt +21 -21
  191. package/apps/pwa/out/bots/index.html +1 -1
  192. package/apps/pwa/out/bots/index.txt +21 -21
  193. package/apps/pwa/out/ceo/index.html +1 -1
  194. package/apps/pwa/out/ceo/index.txt +22 -22
  195. package/apps/pwa/out/chat/index.html +1 -1
  196. package/apps/pwa/out/chat/index.txt +21 -21
  197. package/apps/pwa/out/consult/index.html +1 -1
  198. package/apps/pwa/out/consult/index.txt +22 -22
  199. package/apps/pwa/out/control/index.html +1 -1
  200. package/apps/pwa/out/control/index.txt +22 -22
  201. package/apps/pwa/out/decisions/index.html +1 -1
  202. package/apps/pwa/out/decisions/index.txt +21 -21
  203. package/apps/pwa/out/design-check/index.html +1 -1
  204. package/apps/pwa/out/design-check/index.txt +22 -22
  205. package/apps/pwa/out/editor/index.html +1 -1
  206. package/apps/pwa/out/editor/index.txt +22 -22
  207. package/apps/pwa/out/exec/index.html +1 -1
  208. package/apps/pwa/out/exec/index.txt +22 -22
  209. package/apps/pwa/out/field/index.html +1 -1
  210. package/apps/pwa/out/field/index.txt +22 -22
  211. package/apps/pwa/out/healthz +1 -1
  212. package/apps/pwa/out/index.html +1 -1
  213. package/apps/pwa/out/index.txt +21 -21
  214. package/apps/pwa/out/inside/index.html +1 -1
  215. package/apps/pwa/out/inside/index.txt +21 -21
  216. package/apps/pwa/out/intake/index.html +1 -1
  217. package/apps/pwa/out/intake/index.txt +22 -22
  218. package/apps/pwa/out/live/index.html +1 -1
  219. package/apps/pwa/out/live/index.txt +22 -22
  220. package/apps/pwa/out/live-run/index.html +1 -1
  221. package/apps/pwa/out/live-run/index.txt +22 -22
  222. package/apps/pwa/out/loops/index.html +1 -1
  223. package/apps/pwa/out/loops/index.txt +21 -21
  224. package/apps/pwa/out/market/index.html +1 -1
  225. package/apps/pwa/out/market/index.txt +21 -21
  226. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  227. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  228. package/apps/pwa/out/morning/index.html +1 -1
  229. package/apps/pwa/out/morning/index.txt +22 -22
  230. package/apps/pwa/out/observatory/index.html +1 -1
  231. package/apps/pwa/out/observatory/index.txt +22 -22
  232. package/apps/pwa/out/ops/checklist/index.html +1 -1
  233. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  234. package/apps/pwa/out/ops/release/index.html +1 -1
  235. package/apps/pwa/out/ops/release/index.txt +21 -21
  236. package/apps/pwa/out/ops/seats/index.html +1 -1
  237. package/apps/pwa/out/ops/seats/index.txt +21 -21
  238. package/apps/pwa/out/outputs/index.html +1 -1
  239. package/apps/pwa/out/outputs/index.txt +21 -21
  240. package/apps/pwa/out/reflection/index.html +1 -1
  241. package/apps/pwa/out/reflection/index.txt +22 -22
  242. package/apps/pwa/out/scheduler/index.html +1 -1
  243. package/apps/pwa/out/scheduler/index.txt +22 -22
  244. package/apps/pwa/out/sessions/index.html +1 -1
  245. package/apps/pwa/out/sessions/index.txt +21 -21
  246. package/apps/pwa/out/settings/devices/index.html +1 -1
  247. package/apps/pwa/out/settings/devices/index.txt +22 -22
  248. package/apps/pwa/out/settings/index.html +1 -1
  249. package/apps/pwa/out/settings/index.txt +22 -22
  250. package/apps/pwa/out/setup/done/index.html +1 -1
  251. package/apps/pwa/out/setup/done/index.txt +22 -22
  252. package/apps/pwa/out/setup/index.html +1 -1
  253. package/apps/pwa/out/setup/index.txt +22 -22
  254. package/apps/pwa/out/share/index.html +1 -1
  255. package/apps/pwa/out/share/index.txt +22 -22
  256. package/apps/pwa/out/showroom/index.html +1 -1
  257. package/apps/pwa/out/showroom/index.txt +21 -21
  258. package/apps/pwa/out/tasks/index.html +1 -1
  259. package/apps/pwa/out/tasks/index.txt +22 -22
  260. package/apps/pwa/out/term/index.html +1 -1
  261. package/apps/pwa/out/term/index.txt +22 -22
  262. package/apps/pwa/out/today/index.html +1 -1
  263. package/apps/pwa/out/today/index.txt +22 -22
  264. package/apps/pwa/out/trace/index.html +1 -1
  265. package/apps/pwa/out/trace/index.txt +22 -22
  266. package/apps/pwa/out/vault/index.html +1 -1
  267. package/apps/pwa/out/vault/index.txt +22 -22
  268. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  269. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  270. package/apps/pwa/out/workflows/index.html +1 -1
  271. package/apps/pwa/out/workflows/index.txt +22 -22
  272. package/apps/pwa/out/workspace/index.html +1 -1
  273. package/apps/pwa/out/workspace/index.txt +22 -22
  274. package/apps/pwa/out/worktrees/index.html +1 -1
  275. package/apps/pwa/out/worktrees/index.txt +22 -22
  276. package/graphs/release/release-loop.yaml +5 -5
  277. package/graphs/steward/recipes.yaml +4 -0
  278. package/graphs/steward/steward.yaml +10 -1
  279. package/package.json +1 -1
  280. package/scripts/bench-report.ts +46 -1
  281. package/scripts/ci-typecheck-changed.ts +7 -5
  282. package/scripts/release-loop/auto-approve-node.ts +6 -0
  283. package/scripts/release-loop/gate-closure.ts +286 -0
  284. package/scripts/release-loop/gate-node.ts +73 -13
  285. package/scripts/release-loop/gate-partial.ts +34 -6
  286. package/scripts/release-loop/ops-upgrade-node.ts +63 -42
  287. package/scripts/release-loop/publish-node.ts +6 -0
  288. package/scripts/release-loop/resume-release.ts +37 -10
  289. package/scripts/release-loop/resume.ts +69 -4
  290. package/scripts/tsc-baseline-cache.ts +28 -3
  291. package/scripts/usage-rollup.ts +27 -13
  292. package/scripts/ux-sim.ts +30 -1
  293. package/skills/youtube-master/scripts/main.ts +4 -1
  294. package/skills/youtube-master/src/obsidian.ts +9 -0
  295. package/src/agent-substrate/acp-implementer.ts +14 -7
  296. package/src/agent-substrate/pr-reviewer.ts +30 -10
  297. package/src/agent-substrate/self-review-cli.ts +126 -10
  298. package/src/budget/cost-tier-advisor.ts +91 -0
  299. package/src/budget/shadow-arms.ts +77 -0
  300. package/src/budget/types.ts +5 -3
  301. package/src/budget/unified-usage.ts +172 -8
  302. package/src/cli/doctor-cli.ts +21 -0
  303. package/src/cli/friendly-errors.ts +113 -0
  304. package/src/cli/intake-cli.ts +3 -1
  305. package/src/cli/memory-cli.ts +182 -0
  306. package/src/cli/model-watch-cli.ts +4 -1
  307. package/src/cli/pr-land-pod-shadow.ts +54 -0
  308. package/src/cli/release-cli.ts +9 -7
  309. package/src/cli/release-run-if-ready.ts +11 -0
  310. package/src/cli/resource-cli.ts +48 -0
  311. package/src/cli/retro-cli.ts +12 -3
  312. package/src/cli/seat-requests-cli.ts +25 -0
  313. package/src/cli/tasks-cli.ts +31 -7
  314. package/src/cli/usage-cli.ts +3 -1
  315. package/src/compact/verify-probe.ts +23 -3
  316. package/src/context-card/index.ts +50 -0
  317. package/src/control/control-status.ts +30 -1
  318. package/src/dashboard/slash-runtime/dashboard-handlers.ts +4 -138
  319. package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
  320. package/src/debug/log-diet.ts +16 -4
  321. package/src/domains/morning-essential.ts +18 -3
  322. package/src/domains/release-tool.ts +4 -0
  323. package/src/execution-loop/launch-gate.ts +158 -2
  324. package/src/fleet/host-doctor.ts +375 -0
  325. package/src/goals/judge.ts +20 -6
  326. package/src/graph-runner/runner.ts +9 -5
  327. package/src/graph-wizard/archetypes.ts +14 -8
  328. package/src/graph-wizard/generate.ts +77 -1
  329. package/src/grok.ts +13 -7
  330. package/src/harness/harness-cli-command.ts +56 -47
  331. package/src/harness/harness-stop.ts +82 -12
  332. package/src/index.ts +17 -175
  333. package/src/intake-plane/collect-github.ts +7 -2
  334. package/src/intake-plane/lens.ts +46 -4
  335. package/src/intake-plane/requirement-funnel.ts +53 -1
  336. package/src/intelligence-map/catalog-feed.ts +119 -0
  337. package/src/intelligence-map/model-watch-intake.ts +40 -0
  338. package/src/intelligence-map/model-watch-mission.ts +14 -1
  339. package/src/llm/open-weight-discipline.ts +21 -0
  340. package/src/llm.ts +4 -8
  341. package/src/maturity/feature-maturity.ts +1 -1
  342. package/src/nexus/api/http-server.ts +22 -0
  343. package/src/oauth/codex-account-rotation.ts +4 -1
  344. package/src/oauth/codex-account-store.ts +20 -7
  345. package/src/oauth/codex-quota-policy.ts +33 -4
  346. package/src/preview/terminal.ts +15 -5
  347. package/src/project/project-store.ts +20 -0
  348. package/src/release-loop/auto-start.ts +7 -5
  349. package/src/release-loop/checklist.ts +11 -1
  350. package/src/release-loop/gate-shards.ts +4 -0
  351. package/src/release-loop/light-rc.ts +84 -13
  352. package/src/release-loop/merged-pr-checklist.ts +35 -5
  353. package/src/release-loop/rehearsal.ts +1 -1
  354. package/src/seat-loop/duty-ledger.ts +64 -0
  355. package/src/self-dev/decompose.ts +37 -3
  356. package/src/self-dev/dev-pipeline.ts +32 -7
  357. package/src/self-dev/draft-residue.ts +16 -6
  358. package/src/self-dev/draft-sweep.ts +52 -4
  359. package/src/self-dev/fabric-decompose-adapter.ts +9 -2
  360. package/src/self-dev/run-supervisor.ts +37 -7
  361. package/src/self-implement/gate-cli.ts +29 -10
  362. package/src/self-implement/gate-remote.ts +4 -1
  363. package/src/self-implement/goal-author.ts +12 -2
  364. package/src/self-implement/goal-new-paths.ts +42 -0
  365. package/src/self-implement/host-regate.ts +124 -30
  366. package/src/self-implement/importer-test-index.ts +3 -1
  367. package/src/self-implement/l8-merge-queue.ts +80 -2
  368. package/src/self-implement/merge-train.ts +19 -0
  369. package/src/self-implement/off-diff-evidence.ts +40 -1
  370. package/src/self-implement/orchestrator.ts +88 -19
  371. package/src/self-implement/premise-review.ts +159 -0
  372. package/src/self-implement/regate-detail.ts +79 -0
  373. package/src/self-implement/review-deferred-to-host.ts +21 -0
  374. package/src/self-implement/rework-budget-judgment.ts +23 -3
  375. package/src/self-implement/running-runs.ts +2 -2
  376. package/src/self-implement/scope-adjacency.ts +23 -0
  377. package/src/self-implement/seams.ts +42 -7
  378. package/src/skills/tools/agent.ts +16 -1
  379. package/src/skills/tools/persistent-grounding.ts +11 -1
  380. package/src/skills/tools/shell.ts +33 -1
  381. package/src/steward/rejudge-tick.ts +142 -0
  382. package/src/task-agent/board.ts +92 -3
  383. package/src/task-agent/card-evidence.ts +88 -1
  384. package/src/task-agent/cover.ts +65 -0
  385. package/src/task-agent/parent-host.ts +27 -3
  386. package/src/task-agent/rejudge-on-head.ts +151 -7
  387. package/src/task-agent/review-result-capture.ts +3 -1
  388. package/src/task-agent/shadow.ts +12 -0
  389. package/src/task-agent/task-hand.ts +4 -1
  390. package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -0
  391. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +122 -0
  392. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +23 -0
  393. package/src/task-orchestrator/surfaces/pod-pool.ts +53 -0
  394. package/src/task-orchestrator/surfaces/self-implement-pod.ts +235 -28
  395. package/src/user-config.ts +18 -4
  396. package/src/ux-sim/fault-cred-expiry.ts +100 -0
  397. package/src/ux-sim/fault-pod-death.ts +74 -0
  398. package/src/ux-sim/fault-pool-cap.ts +81 -0
  399. package/src/version/packed-revision.json +1 -1
  400. package/src/webclone/qa-table.ts +22 -0
  401. package/apps/pwa/out/_next/static/chunks/0a09e062-34f747a17d8d8c2e.js +0 -1
  402. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +0 -77
  403. package/apps/pwa/out/_next/static/chunks/1325-dc3f3c21eb181cb4.js +0 -1
  404. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +0 -34
  405. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +0 -24
  406. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +0 -1
  407. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +0 -1
  408. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +0 -1
  409. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/1669-da843ed73aa301f5.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +0 -36
  416. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +0 -122
  417. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +0 -62
  419. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/272-0eed0fb0aab716b6.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +0 -1
  422. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +0 -149
  426. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/3961-aaae04ed1d32622f.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +0 -309
  430. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/5313.1697309c532b9856.js +0 -2
  442. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +0 -74
  450. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +0 -64
  454. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +0 -32
  457. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +0 -24
  458. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +0 -93
  462. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +0 -148
  467. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +0 -226
  468. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +0 -27
  469. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +0 -115
  472. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +0 -8
  479. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +0 -23
  480. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +0 -90
  485. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +0 -94
  486. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +0 -41
  488. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +0 -287
  490. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +0 -79
  491. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +0 -104
  496. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3b9fc39362473ae7.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/app/consult/page-c0ab229673a8b0eb.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/app/inside/page-22725e2570f1126b.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/framework-b2763b10dc6b3836.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +0 -1
  551. /package/apps/pwa/out/_next/static/{Q-7iofoxOEv1WX18S35of → dRS6lEhSRRBr1abbzp7fJ}/_ssgManifest.js +0 -0
@@ -2,9 +2,13 @@
2
2
  // changed — not the whole 24-shard sweep again (0.2.18: two timeout fixes on top of an 84-minute gate meant another full
3
3
  // gate). The plan is opt-in (`release resume --from gate --partial`) and fail-closed: any non-test source change, a prior
4
4
  // gate record for another commit, or a missing record means «full gate», never a guess.
5
+ // GATE-REUSE-BY-DIFF (0.2.25): a code change no longer forces the full sweep — with the tip's import closure
6
+ // (gate-closure.ts) the plan adds every test that can reach a changed file, and every test whose closure is opaque.
7
+ // `release resume --from gate` now plans this by default when the tip moved (`--no-partial` = full gate).
5
8
  import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
6
9
  import { spawnSync } from 'node:child_process';
7
10
  import { dirname, join } from 'node:path';
11
+ import { CODE_FILE, type ClosureVerdict } from './gate-closure';
8
12
 
9
13
  export interface PartialPlan {
10
14
  version: string;
@@ -12,7 +16,7 @@ export interface PartialPlan {
12
16
  priorCommit: string;
13
17
  /** The commit this plan is for — a gate on any other commit ignores it. */
14
18
  forCommit: string;
15
- /** Test files re-run: changed test files ⊕ files of the prior failures. */
19
+ /** Test files re-run: changed test files ⊕ files of the prior failures ⊕ tests reaching a changed code file. */
16
20
  files: string[];
17
21
  priorFailures: string[];
18
22
  priorErrors: string[];
@@ -37,19 +41,43 @@ export function testFileOfId(id: string): string {
37
41
 
38
42
  /** Decide whether a partial re-gate is safe for `changedFiles` (prior → for). Never guesses: any doubt is a full gate. */
39
43
  export function planPartialRegate(input: { version: string; priorCommit: string; forCommit: string; changedFiles: readonly string[];
40
- priorFailures: readonly string[]; priorErrors: readonly string[] }):
41
- { ok: true; plan: PartialPlan } | { ok: false; reason: string } {
44
+ priorFailures: readonly string[]; priorErrors: readonly string[];
45
+ /** GATE-REUSE-BY-DIFF: the tests reaching these changed code files (seeds include changed tests). Without it any
46
+ * non-test change is a full gate. */
47
+ closure?: (changedCode: string[]) => ClosureVerdict;
48
+ /** Tracked at the tip — a deleted changed test is not re-run (nothing to run); a deleted prior-failure file is a full
49
+ * gate (its failure can be neither re-measured nor carried). Without it every changed test is planned. */
50
+ existsAtTip?: (file: string) => boolean }):
51
+ { ok: true; plan: PartialPlan; closure?: { reached: number; opaque: number } } | { ok: false; reason: string } {
42
52
  if (!/^[0-9a-f]{40}$/i.test(input.priorCommit) || !/^[0-9a-f]{40}$/i.test(input.forCommit)) return { ok: false, reason: 'commit is not a full sha' };
43
53
  if (input.priorCommit === input.forCommit) return { ok: false, reason: 'no new commit since the prior gate' };
44
54
  const source = input.changedFiles.filter((file) => !TEST_FILE.test(file) && !isInert(file));
45
- if (source.length) return { ok: false, reason: `non-test change → full gate: ${source.slice(0, 5).join(', ')}${source.length > 5 ? ` (+${source.length - 5})` : ''}` };
55
+ const list = (files: string[]) => `${files.slice(0, 5).join(', ')}${files.length > 5 ? ` (+${files.length - 5})` : ''}`;
56
+ // Only code is followed through the closure: a changed fixture, JSON, lockfile, config or script is a full gate.
57
+ const notCode = source.filter((file) => !CODE_FILE.test(file));
58
+ if (source.length && (!input.closure || notCode.length)) return { ok: false, reason: `non-test change → full gate: ${list(notCode.length ? notCode : source)}` };
59
+ let reaching: string[] = [];
60
+ let closure: { reached: number; opaque: number } | undefined;
61
+ if (source.length) {
62
+ let verdict: ClosureVerdict;
63
+ try { verdict = input.closure!(input.changedFiles.filter((file) => CODE_FILE.test(file))); }
64
+ catch (error) { return { ok: false, reason: `import closure unreadable → full gate: ${String(error instanceof Error ? error.message : error).slice(0, 200)}` }; }
65
+ if (!verdict.ok) return { ok: false, reason: verdict.reason };
66
+ const unsafe = verdict.tests.filter((file) => !TEST_FILE.test(file) || file.split('/').includes('..'));
67
+ if (unsafe.length) return { ok: false, reason: `closure selected a test path the plan cannot carry → full gate: ${list(unsafe)}` };
68
+ reaching = verdict.tests;
69
+ closure = { reached: verdict.reached, opaque: verdict.opaque };
70
+ }
46
71
  let failureFiles: string[];
47
72
  try { failureFiles = [...input.priorFailures, ...input.priorErrors].map(testFileOfId); }
48
73
  catch (error) { return { ok: false, reason: String(error instanceof Error ? error.message : error) }; }
49
- const files = [...new Set([...input.changedFiles.filter((file) => TEST_FILE.test(file)), ...failureFiles])].sort();
74
+ const exists = input.existsAtTip ?? (() => true);
75
+ const gone = failureFiles.filter((file) => !exists(file));
76
+ if (gone.length) return { ok: false, reason: `prior failure file deleted at the tip → full gate: ${list(gone)}` };
77
+ const files = [...new Set([...input.changedFiles.filter((file) => TEST_FILE.test(file) && exists(file)), ...failureFiles, ...reaching])].sort();
50
78
  if (!files.length) return { ok: false, reason: 'nothing to re-run' };
51
79
  return { ok: true, plan: { version: input.version, priorCommit: input.priorCommit, forCommit: input.forCommit, files,
52
- priorFailures: [...input.priorFailures], priorErrors: [...input.priorErrors] } };
80
+ priorFailures: [...input.priorFailures], priorErrors: [...input.priorErrors] }, ...(closure ? { closure } : {}) };
53
81
  }
54
82
 
55
83
  export function writePartialPlan(root: string, plan: PartialPlan): string {
@@ -9,7 +9,7 @@ import { prereleaseKind } from './release-version.js';
9
9
  interface HostResult { host: string; ok: boolean; before: string; after: string; error?: string; skipped?: string; hooks?: string; restart?: 'no-service' }
10
10
  /** Where the internal feed is packed from: a checkout of the release tag, never the run's working tree. */
11
11
  export interface FeedSource { checkout: string; commit: string; deps: 'linked' | 'installed'; cleanup: () => void }
12
- interface OpsUpgradeDeps { exists?: (path: string) => boolean; installSource?: () => string | null; feedSource?: (version: string) => FeedSource }
12
+ interface OpsUpgradeDeps { exists?: (path: string) => boolean; installSource?: () => string | null; installCommit?: () => string | null; feedSource?: (version: string) => FeedSource }
13
13
 
14
14
  /** Detached worktree at refs/tags/v<version> with the PWA built — the feed ships what was released (10-04 0.2.11:
15
15
  * packing process.cwd() shipped main HEAD ee689ad2 as «0.2.11» to node-b·cloud-vm instead of the cut 31129c91). */
@@ -52,16 +52,24 @@ export function tagFeedSource(run: CommandRunner, repo: string = process.cwd()):
52
52
  };
53
53
  }
54
54
 
55
- function localInstallSource(): string | null {
55
+ function installMetadata(text: string): { source: string | null; commit: string | null } {
56
56
  try {
57
- const data: unknown = JSON.parse(readFileSync(join(homedir(), '.local/share/elanous/install.json'), 'utf8'));
58
- return data && typeof data === 'object' && 'source' in data && typeof data.source === 'string' ? data.source : null;
59
- } catch { return null; }
57
+ const data: unknown = JSON.parse(text);
58
+ if (!data || typeof data !== 'object') return { source: null, commit: null };
59
+ return {
60
+ source: 'source' in data && typeof data.source === 'string' ? data.source : null,
61
+ commit: 'commit' in data && typeof data.commit === 'string' ? data.commit : null,
62
+ };
63
+ } catch { return { source: null, commit: null }; }
64
+ }
65
+
66
+ function localInstallMetadata(): { source: string | null; commit: string | null } {
67
+ try { return installMetadata(readFileSync(join(homedir(), '.local/share/elanous/install.json'), 'utf8')); }
68
+ catch { return { source: null, commit: null }; }
60
69
  }
61
70
 
62
- function installedMatches(installed: unknown, version: string, checkout: boolean): boolean {
63
- return installed === version || checkout && typeof installed === 'string'
64
- && installed.startsWith(`${version}-`) && /^[0-9a-f]{12}$/.test(installed.slice(version.length + 1));
71
+ function installedMatches(installed: unknown, version: string): boolean {
72
+ return installed === version;
65
73
  }
66
74
 
67
75
  function missingService(data: Record<string, unknown> | undefined): boolean {
@@ -116,17 +124,21 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
116
124
  }
117
125
  const results: HostResult[] = [];
118
126
  for (const host of hosts as string[]) {
119
- const source = host === 'local' ? (deps.installSource ?? localInstallSource)() : null;
120
- const checkout = host === 'local' && source !== null && isAbsolute(source);
121
- const path = checkout ? 'checkout' as const : 'release' as const;
127
+ // Injected install metadata replaces the machine's install.json entirely — a test that injects only the source
128
+ // must not inherit this machine's real commit (that turned update cases into kept-ahead skips).
129
+ const injected = deps.installSource !== undefined || deps.installCommit !== undefined;
130
+ let metadata: { source: string | null; commit: string | null } = host !== 'local'
131
+ ? { source: null, commit: null }
132
+ : injected
133
+ ? { source: deps.installSource?.() ?? null, commit: deps.installCommit?.() ?? null }
134
+ : localInstallMetadata();
135
+ let source = metadata.source;
136
+ let railSource = false;
137
+ let path: 'checkout' | 'release' = 'release';
122
138
  const record = (result: HostResult) => {
123
139
  results.push(result);
124
140
  debug.log('release-loop.ops-upgrade', 'host', { host, path, restart: result.restart ?? (context.input.opsRestart === true ? result.ok ? 'ok' : 'failed' : 'skipped'), ok: result.ok });
125
141
  };
126
- if (host !== 'local' && feedError) {
127
- record({ host, ok: false, before: '', after: '', skipped: '내부 피드 발행 실패', error: feedError });
128
- continue;
129
- }
130
142
  const command = (args: string[]): CommandResult => host === 'local'
131
143
  ? run('elanous', args)
132
144
  // The installer's own bin dir comes first — a --no-modify-path install (the bot VM) has elanous only there.
@@ -134,35 +146,41 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
134
146
  let before = '';
135
147
  let after = '';
136
148
  try {
149
+ if (host !== 'local') {
150
+ const installed = run('ssh', [host, `cat "$HOME/.local/share/elanous/install.json" 2>/dev/null || true`]);
151
+ if (installed.status === 0) metadata = installMetadata(installed.stdout);
152
+ }
153
+ source = metadata.source;
154
+ if (source !== null && isAbsolute(source)) {
155
+ const repository = host === 'local'
156
+ ? run('git', ['rev-parse', '--is-inside-work-tree'], source)
157
+ : run('ssh', [host, `git -C ${quote(source)} rev-parse --is-inside-work-tree`]);
158
+ railSource = repository.status === 0 && firstLine(repository.stdout) === 'true';
159
+ }
160
+ path = railSource ? 'checkout' : 'release';
137
161
  const previous = command(['--version']);
138
162
  if (previous.status === 0) before = firstLine(previous.stdout);
139
- if (checkout) {
140
- const git = (args: string[]) => run('git', args, source!);
141
- const dirty = git(['status', '--porcelain', '--untracked-files=all']);
142
- if (dirty.status !== 0 || dirty.stdout.trim()) {
143
- record({ host, ok: false, before, after, error: dirty.status === 0 ? '체크아웃 변경 있음' : `체크아웃 상태 확인 실패: ${reason(dirty)}` });
144
- continue;
145
- }
146
- const fetched = git(['fetch', '--tags']);
147
- if (fetched.status !== 0) {
148
- record({ host, ok: false, before, after, error: `태그 가져오기 실패: ${reason(fetched)}` });
149
- continue;
150
- }
151
- const tag = git(['rev-parse', '--verify', `refs/tags/v${version}^{commit}`]);
152
- if (tag.status !== 0 || !tag.stdout.trim()) {
153
- record({ host, ok: false, before, after, error: `태그 없음: v${version}` });
154
- continue;
155
- }
156
- const moved = git(['checkout', '--detach', `v${version}`]);
157
- if (moved.status !== 0) {
158
- record({ host, ok: false, before, after, error: `체크아웃 전환 실패: ${reason(moved)}` });
163
+ if (railSource) {
164
+ record({ host, ok: true, before, after: before, skipped: 'rail-source' });
165
+ continue;
166
+ }
167
+ const installedCommit = metadata.commit;
168
+ if (installedCommit && /^[0-9a-f]{40,64}$/.test(installedCommit)) {
169
+ const ahead = run('git', ['merge-base', '--is-ancestor', `refs/tags/v${version}`, installedCommit]);
170
+ // Only exit 1 proves non-ancestry; missing local objects must not permit a potentially destructive downgrade.
171
+ if (ahead.status !== 1) {
172
+ record({ host, ok: true, before, after: before, skipped: 'kept-ahead' });
159
173
  continue;
160
174
  }
161
175
  }
162
- const updated = command(['update', ...(checkout || host !== 'local' && feedPath !== undefined ? [] : ['--version', version]), '--json', ...(context.input.opsRestart === true ? ['--restart'] : [])]);
176
+ if (host !== 'local' && feedError) {
177
+ record({ host, ok: false, before, after: '', skipped: '내부 피드 발행 실패', error: feedError });
178
+ continue;
179
+ }
180
+ const updated = command(['update', ...(host !== 'local' && feedPath !== undefined ? [] : ['--version', version]), '--json', ...(context.input.opsRestart === true ? ['--restart'] : [])]);
163
181
  const updateResult = lastResult(updated);
164
182
  const noService = host !== 'local' && context.input.opsRestart === true && updateResult?.exitCode === 1 && missingService(updateResult);
165
- if ((!noService && (updated.status !== 0 || updateResult?.exitCode !== 0)) || !installedMatches(updateResult?.installedVersion, version, checkout)) {
183
+ if ((!noService && (updated.status !== 0 || updateResult?.exitCode !== 0)) || !installedMatches(updateResult?.installedVersion, version)) {
166
184
  const error = (updated.status === 0 && updateResult?.exitCode === 0 || noService)
167
185
  ? `설치판 불일치 (기대 ${version}, 실제 ${String(updateResult?.installedVersion)})` : reason(updated);
168
186
  record({ host, ok: false, before, after, error });
@@ -174,7 +192,7 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
174
192
  continue;
175
193
  }
176
194
  after = firstLine(current.stdout);
177
- if (!installedMatches(after.split(/\s+/)[0], version, checkout)) {
195
+ if (!installedMatches(after.split(/\s+/)[0], version)) {
178
196
  record({ host, ok: false, before, after, error: `올렸는데 판이 그대로 (기대 ${version}, 실제 ${after || '없음'})` });
179
197
  continue;
180
198
  }
@@ -198,14 +216,17 @@ export function runOpsUpgrade(run: CommandRunner = runCommand, deps: OpsUpgradeD
198
216
  feed: feedError ? 'failed' as const : feedPath === undefined ? 'skipped-no-path' as const : 'published' as const, hosts: results };
199
217
  }
200
218
 
201
- if (import.meta.main) {
219
+ function main(): void {
202
220
  let version = '';
203
221
  try {
204
222
  version = readGraphContext().input.version;
205
223
  // RELEASE-REHEARSAL-RC: a prerelease never lands docs on main or upgrades the operating hosts.
206
- process.exitCode = finishNode('ops-upgrade', version, prereleaseKind(version) !== null
207
- ? { outcome: 'ok', verdict: 'pass', summary: `ops-upgrade skipped — ${version} is a prerelease`, skipped: 'prerelease' }
208
- : runOpsUpgrade());
224
+ const result = prereleaseKind(version) !== null
225
+ ? { outcome: 'ok' as const, verdict: 'pass' as const, summary: `ops-upgrade skipped — ${version} is a prerelease`, skipped: 'prerelease' }
226
+ : runOpsUpgrade(runCommand);
227
+ process.exitCode = finishNode('ops-upgrade', version, result);
209
228
  }
210
229
  catch (error) { process.exitCode = finishNode('ops-upgrade', version, errorResult(error)); }
211
230
  }
231
+
232
+ if (import.meta.main) main();
@@ -5,6 +5,7 @@ import { join } from 'node:path';
5
5
  import { WARNING_ONLY } from './auto-approve-node.js';
6
6
  import { beginLandingMerge, landingFreezeMessage } from '../../src/release-loop/landing-freeze.js';
7
7
  import { debug } from '../../src/debug/log.js';
8
+ import { registerStandaloneLogSink } from '../../src/domains/standalone-log-sink.js';
8
9
  import { prereleaseKind } from './release-version.js';
9
10
  import { publishAtError } from './publish-at.js';
10
11
  import { errorResult, finishNode, lastResult, nodeOutput, readGraphContext, runCommand, type CommandRunner } from './node-verdict.js';
@@ -115,6 +116,11 @@ export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: str
115
116
  }
116
117
 
117
118
  if (import.meta.main) {
119
+ // GATE-OBS2-2 — the release graph spawns this node as its own process, which inherits no daemon sink. Without this the
120
+ // `release-loop.publish / result` event (the one that says whether the irreversible publication actually happened) stayed
121
+ // in the file trail and `elanous logs` read 0 rows. Same pattern as gate-node.ts and auto-approve-node.ts (GATE-OBS2-1).
122
+ // Observability must never stop the publication node — a failed sink registration is skipped (fail-soft).
123
+ try { await registerStandaloneLogSink('release-loop'); } catch { /* fail-soft: the verdict still goes to stdout */ }
118
124
  let version = '';
119
125
  try { version = readGraphContext().input.version; process.exitCode = finishNode('publish', version, runPublish()); }
120
126
  catch (error) { process.exitCode = finishNode('publish', version, errorResult(error)); }
@@ -10,6 +10,7 @@ import { lastJsonObject, runGraph, type GraphRunState } from '../../src/graph-ru
10
10
  import { releaseRunUniverse } from './release-universe.js';
11
11
  import { isReleaseVersion } from './release-version.js';
12
12
  import { changedFilesBetween, clearPartialPlan, planPartialRegate, writePartialPlan } from './gate-partial.js';
13
+ import { gitClosureTree, testsReachingChanged, type ClosureTree } from './gate-closure.js';
13
14
  import { releaseResumeAcceptedRegressions, releaseResumeGateExecutor, releaseResumeWaiver, type AcceptedRegression } from './resume.js';
14
15
 
15
16
  const GRAPH = join(import.meta.dir, '../../graphs/release/release-loop.yaml');
@@ -29,8 +30,15 @@ export interface ResumeReleaseDeps {
29
30
  now?: () => Date;
30
31
  /** Machine release ledger (gate-failures.json of the prior gate) — default releaseLedgerRoot(). */
31
32
  ledgerRoot?: string;
33
+ /** GATE-REUSE-BY-DIFF: the tip tree for the import closure — default read from git objects of the tip commit. */
34
+ closureTree?: (commit: string) => ClosureTree;
32
35
  }
33
36
 
37
+ /** CLI entry files: a production file that only names one (help text, a goal's command line) does not run it. */
38
+ const CLI_ENTRIES = ['bin/elanous.mjs', 'src/index.ts'] as const;
39
+ /** The gate's own test-file set (gate-node sweep: `git ls-files '*.test.*'` filtered by this). */
40
+ const GATE_TEST = /\.test\.(?:tsx?|jsx?|mts|cts)$/;
41
+
34
42
  export interface TipRefresh { version: string; branch: string; from: string; to: string; changed: boolean; statePath: string; backup?: string }
35
43
 
36
44
  function gitRunner(repo: string) {
@@ -114,18 +122,25 @@ export function refreshReleaseBranchTip(runId: string, deps: ResumeReleaseDeps =
114
122
  return { version, branch, from: recorded, to, changed: true, statePath, backup };
115
123
  }
116
124
 
117
- /** GATE-PARTIAL outcome of a resume — applied (plan written) or the reason it fell back to a full gate. */
118
- export type PartialOutcome = { requested: false } | { requested: true; applied: true; files: number; priorCommit: string } | { requested: true; applied: false; reason: string };
125
+ /** GATE-PARTIAL outcome of a resume — applied (plan written) or the reason it fell back to a full gate. `auto` marks the
126
+ * default plan of `--from gate` (GATE-REUSE-BY-DIFF); `closure` is set when code changes were followed. */
127
+ export type PartialOutcome = { requested: false }
128
+ | { requested: true; applied: true; files: number; priorCommit: string; auto?: true; closure?: { reached: number; opaque: number } }
129
+ | { requested: true; applied: false; reason: string; auto?: true };
119
130
 
120
- /** Build (or clear) the partial re-gate plan for the new tip. Fail-closed: any doubt leaves a full gate. */
131
+ /** Build (or clear) the partial re-gate plan for the new tip. Fail-closed: any doubt leaves a full gate.
132
+ * GATE-REUSE-BY-DIFF: `--from gate` on a moved tip plans by default (`partial: undefined`); `partial: false` opts out. */
121
133
  function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean }, deps: ResumeReleaseDeps): PartialOutcome {
122
134
  const root = deps.root ?? effectiveInstanceRoot();
123
- // Any resume starts from no plan: one without --partial (from whatever node) never inherits an older plan.
135
+ // Any resume starts from no plan: one without a partial plan (from whatever node) never inherits an older plan.
124
136
  clearPartialPlan(root, tip.version);
125
- if (!opts.partial) return { requested: false };
137
+ const auto = opts.partial === undefined;
138
+ // The default applies only where it can help: a gate re-run on a tip that moved. An unchanged tip re-uses its own
139
+ // shard results by commit already.
140
+ if (opts.partial === false || (auto && (opts.from !== 'gate' || !tip.changed))) return { requested: false };
126
141
  const fallback = (reason: string): PartialOutcome => {
127
- debug.log('release-loop.resume', 'partial-fallback', { version: tip.version, reason });
128
- return { requested: true, applied: false, reason };
142
+ debug.log('release-loop.resume', 'partial-fallback', { version: tip.version, reason, auto });
143
+ return { requested: true, applied: false, reason, ...(auto ? { auto: true as const } : {}) };
129
144
  };
130
145
  if (opts.from !== 'gate') return fallback('--partial only applies to --from gate');
131
146
  if (!tip.changed) return fallback('release branch tip unchanged — nothing new to re-check');
@@ -151,12 +166,23 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
151
166
  // The tip is already refreshed — a failed diff must not strand the resume: run the full gate and say why.
152
167
  return fallback(`changed files unreadable: ${String(error instanceof Error ? error.message : error).slice(0, 200)}`);
153
168
  }
169
+ // The tip tree (git objects of tip.to, never the working tree): existence of planned tests ⊕ the import closure.
170
+ let tree: ClosureTree;
171
+ try { tree = (deps.closureTree ?? ((commit: string) => gitClosureTree(deps.repo ?? process.cwd(), commit)))(tip.to); }
172
+ catch (error) { return fallback(`tip tree unreadable: ${String(error instanceof Error ? error.message : error).slice(0, 200)}`); }
173
+ const tracked = new Set(tree.files);
174
+ const tests = tree.files.filter((file) => GATE_TEST.test(file));
154
175
  const planned = planPartialRegate({ version: tip.version, priorCommit: tip.from, forCommit: tip.to, changedFiles: changed,
155
- priorFailures: prior.failures as string[], priorErrors: (prior.errors ?? []) as string[] });
176
+ priorFailures: prior.failures as string[], priorErrors: (prior.errors ?? []) as string[],
177
+ existsAtTip: (file) => tracked.has(file),
178
+ closure: (changedCode) => testsReachingChanged(tree, changedCode, tests, { cliEntries: CLI_ENTRIES }) });
156
179
  if (!planned.ok) return fallback(planned.reason);
180
+ if (planned.plan.files.length >= tests.length) return fallback(`every test is re-run (${tests.length}) — full gate`);
157
181
  const path = writePartialPlan(root, planned.plan);
158
- debug.log('release-loop.resume', 'partial-planned', { version: tip.version, priorCommit: tip.from, commit: tip.to, files: planned.plan.files.length, path });
159
- return { requested: true, applied: true, files: planned.plan.files.length, priorCommit: tip.from };
182
+ debug.log('release-loop.resume', 'partial-planned', { version: tip.version, priorCommit: tip.from, commit: tip.to, files: planned.plan.files.length,
183
+ tests: tests.length, auto, path, ...(planned.closure ? { reached: planned.closure.reached, opaque: planned.closure.opaque } : {}) });
184
+ return { requested: true, applied: true, files: planned.plan.files.length, priorCommit: tip.from,
185
+ ...(auto ? { auto: true as const } : {}), ...(planned.closure ? { closure: planned.closure } : {}) };
160
186
  }
161
187
 
162
188
  /** The graph file the run started from — a snapshot run refuses any other path (the installed CLI's own copy differs). */
@@ -183,6 +209,7 @@ export async function resumeReleaseRun(opts: { runId: string; from: string; part
183
209
  if (gateExecutor) debug.log('release-loop.resume', 'gate-executor', { runId: opts.runId, from: opts.from, executor: gateExecutor.set.gateExecutor, host: gateExecutor.set.gateRemote ?? null, previous: gateExecutor.previous });
184
210
  const waiver = original && (opts.waive !== undefined || opts.reason !== undefined)
185
211
  ? releaseResumeWaiver(original, opts) : undefined;
212
+ if (waiver) debug.log('release-loop.resume', 'waiver', { runId: opts.runId, node: waiver.nodeId, reason: waiver.reason, unmeasured: waiver.unmeasured ?? null });
186
213
  const acceptedRegressions = original && opts.acceptedRegressions !== undefined && !waiver
187
214
  ? releaseResumeAcceptedRegressions(original, opts.acceptedRegressions, opts.from) : undefined;
188
215
  // A waived verdict may reuse its original commit. A moved tip still requires a full re-gate.
@@ -1,4 +1,4 @@
1
- import type { GraphRunState } from '../../src/graph-runner/runner.js';
1
+ import { lastJsonObject, STOPPED_NODE_ERROR, type GraphRunState } from '../../src/graph-runner/runner.js';
2
2
  import { publicWaiverReason } from './known-issues-node.js';
3
3
  import { checkGateExecutorChoice, type GateExecutor } from './gate-executor.js';
4
4
 
@@ -28,11 +28,66 @@ export function releaseResumeAcceptedRegressions(state: GraphRunState, additions
28
28
  return combined;
29
29
  }
30
30
 
31
+ const SWEEP_INCOMPLETE = /^(?:pod sweep incomplete|sweep incomplete|[\w-]+ shard incomplete)\b/;
32
+
33
+ /**
34
+ * RELEASE-WAIVE-UNMEASURED — why the saved gate record at `index` carries no verdict, or undefined when it does (or may).
35
+ * Fail-closed: only three shapes count, each read from what the runner and gate-node actually write:
36
+ * ① stopped — `graph runs stop` wrote {ok:false, executed:false, exit:null, error:STOPPED_NODE_ERROR} as the run's last record;
37
+ * ② no verdict — the gate process ended with exit null (signal, idle timeout, or a spawn that failed) and printed no result line at
38
+ * all (no output line is a JSON object with an `outcome`), so the run went gate → failed. A verdict followed by more
39
+ * log lines and then a kill is still a verdict: refused;
40
+ * ③ sweep incomplete — gate-node printed outcome `error` (no verdict: the baseline comparison never ran, so `introduced`
41
+ * is still the empty initial list) and the error is an incomplete sweep (stalled shards / no tests ran). The finished
42
+ * shards' counts go into the detail. Any other error (cleanup, baseline persistence, …) may follow a verdict: refused.
43
+ * An `outcome: fail` (introduced > 0), an introduced list that is not empty, or an already-waived record is never unmeasured.
44
+ */
45
+ /** Any output line that is a JSON object naming an `outcome` — a verdict was printed, whatever came after it. */
46
+ function printedVerdict(output: unknown): boolean {
47
+ if (typeof output !== 'string') return false;
48
+ return output.split('\n').some((line) => {
49
+ const text = line.trim();
50
+ if (!text.startsWith('{')) return false;
51
+ try { const value = JSON.parse(text) as unknown; return !!value && typeof value === 'object' && 'outcome' in value; } catch { return false; }
52
+ });
53
+ }
54
+
55
+ export function gateUnmeasuredDetail(state: GraphRunState, index: number): string | undefined {
56
+ const record = state.nodes[index];
57
+ if (!record || record.nodeId !== 'gate' || state.path[index] !== 'gate' || record.ok !== false || record.waiver !== undefined) return undefined;
58
+ if (state.nodes.some((saved) => saved.nodeId === 'gate' && saved !== record)) return undefined;
59
+ const last = index === state.path.length - 1 && index === state.nodes.length - 1;
60
+ if (last && record.executed === false && record.exit === null && record.error === STOPPED_NODE_ERROR && record.output === undefined) {
61
+ return `stopped: ${STOPPED_NODE_ERROR}${typeof record.seconds === 'number' ? ` after ${record.seconds}s` : ''}`;
62
+ }
63
+ const failedAfter = index === state.path.length - 2 && state.path.at(-1) === 'failed' && state.nodes.at(-1)?.nodeId === 'failed'
64
+ && state.nodes.length === state.path.length;
65
+ if (!failedAfter || record.executed !== true) return undefined;
66
+ const result = lastJsonObject(record.output);
67
+ if (result === undefined) {
68
+ if (record.exit !== null || printedVerdict(record.output)) return undefined;
69
+ return `no-verdict: gate process ended with exit null and no result line${record.error ? ` — ${record.error.split('\n')[0]!.slice(0, 120)}` : ''}`;
70
+ }
71
+ if (result.outcome !== 'error' || !Array.isArray(result.introduced) || result.introduced.length !== 0) return undefined;
72
+ const error = typeof result.error === 'string' ? result.error : '';
73
+ if (!SWEEP_INCOMPLETE.test(error)) return undefined;
74
+ // The detail keeps what WAS measured: each stalled shard's reason and the finished shards' counts (failures there are
75
+ // not yet split into introduced vs pre-existing — the baseline comparison never ran).
76
+ const stalled = Array.isArray(result.stalledShards) ? result.stalledShards as Array<{ reason?: unknown }> : [];
77
+ const reasons = new Map<string, number>();
78
+ for (const shard of stalled) reasons.set(String(shard?.reason ?? 'unknown'), (reasons.get(String(shard?.reason ?? 'unknown')) ?? 0) + 1);
79
+ const summary = result.partialSummary as { pass?: unknown; fail?: unknown; errors?: unknown; ran?: unknown } | undefined;
80
+ const measured = summary && typeof summary === 'object'
81
+ ? ` · finished shards measured pass ${String(summary.pass)} fail ${String(summary.fail)} errors ${String(summary.errors)} ran ${String(summary.ran)}` : '';
82
+ return `sweep incomplete: ${error.split('\n')[0]!.slice(0, 200)}`
83
+ + (stalled.length ? ` · stalled shards ${stalled.length} (${[...reasons].map(([reason, count]) => `${reason}×${count}`).join(', ')})` : '') + measured;
84
+ }
85
+
31
86
  /** Only the recorded failure at the restart boundary may be waived. `--from` is never a waiver. */
32
87
  export function releaseResumeWaiver(
33
88
  state: GraphRunState,
34
89
  opts: { from: string; waive?: string; reason?: string; acceptedRegressions?: AcceptedRegression[] },
35
- ): { nodeId: string; reason: string; acceptedRegressions: AcceptedRegression[] } | undefined {
90
+ ): { nodeId: string; reason: string; acceptedRegressions: AcceptedRegression[]; unmeasured?: string } | undefined {
36
91
  if ((opts.waive === undefined) !== (opts.reason === undefined)) throw new Error('--waive <node> and --reason <text> must be supplied together');
37
92
  if (opts.waive !== undefined && !opts.waive.trim()) throw new Error('--waive must not be empty');
38
93
  if (opts.waive === undefined) return undefined;
@@ -41,13 +96,23 @@ export function releaseResumeWaiver(
41
96
  publicWaiverReason(reason);
42
97
  if (opts.from !== opts.waive) throw new Error('--from must name the waived node; --from alone does not waive a failure');
43
98
  const index = state.path.indexOf(opts.waive);
44
- if (index < 0 || state.path.lastIndexOf(opts.waive) !== index || state.nodes[index]?.nodeId !== opts.waive || state.nodes[index]?.ok !== false ||
99
+ const unique = index >= 0 && state.path.lastIndexOf(opts.waive) === index;
100
+ // RELEASE-WAIVE-UNMEASURED (OP 10-12): a gate cut before any verdict is the only gate that may be waived — a measured gate
101
+ // failure or an already-waived gate stays refused (fail-closed below), and the ledger records why it was unmeasured.
102
+ const unmeasured = opts.waive === 'gate' && unique ? gateUnmeasuredDetail(state, index) : undefined;
103
+ if (unmeasured !== undefined) {
104
+ return { nodeId: opts.waive, reason, unmeasured, acceptedRegressions: releaseResumeAcceptedRegressions(state,
105
+ [...(opts.acceptedRegressions ?? []), { id: `waive:${opts.waive}`, note: reason }]) };
106
+ }
107
+ if (!unique || state.path.lastIndexOf(opts.waive) !== index || state.nodes[index]?.nodeId !== opts.waive || state.nodes[index]?.ok !== false ||
45
108
  state.nodes[index]?.executed !== true || state.path.at(-2) !== opts.waive || state.path.at(-1) !== 'failed' || state.nodes.at(-1)?.nodeId !== 'failed') {
46
109
  throw new Error(`--waive ${opts.waive} requires the failed executable node on the saved path`);
47
110
  }
48
111
  // Only user-visible, non-publication checks can become accepted regressions; build, safety and approval gates stay blocking.
112
+ // A measured gate failure (outcome fail / introduced > 0, or any error that is not an incomplete sweep) lands here too.
49
113
  if (!['mac-smoke', 'tui'].includes(opts.waive)) {
50
- throw new Error(`--waive ${opts.waive} cannot waive a safety, side-effect or approval node`);
114
+ throw new Error(`--waive ${opts.waive} cannot waive a safety, side-effect or approval node`
115
+ + (opts.waive === 'gate' ? ' (only an unmeasured gate — stopped, killed or sweep incomplete — may be waived)' : ''));
51
116
  }
52
117
  return { nodeId: opts.waive, reason, acceptedRegressions: releaseResumeAcceptedRegressions(state,
53
118
  [...(opts.acceptedRegressions ?? []), { id: `waive:${opts.waive}`, note: reason }]) };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * 승격 착지의 base 쪽 tsc 진단을 «main 커밋별로 한 번만» 재고 재사용하는 캐시.
3
- * 키 = base sha ⊕ tsc 명령 ⊕ 설정 파일(base 커밋에서 git show 로 읽은 내용) 해시 ⊕ tsc 판.
3
+ * 키 = base sha ⊕ tsc 명령 ⊕ 설정 파일(base 커밋에서 git show 로 읽은 내용) 해시 ⊕ 작업 트리 설치 키(bun.lock 실물) ⊕ tsc 판.
4
4
  * 값 = rebase 전 정규화 진단(워크트리 절대 경로는 «<ROOT>» 자리표로 저장).
5
5
  * ⛔ 캐시 실패는 호출자에게 던지지 않는다 — 읽기·쓰기 모두 miss 로 떨어진다.
6
6
  */
@@ -13,7 +13,7 @@ import type { TypecheckError } from '../src/typecheck-ratchet.js';
13
13
 
14
14
  export const ROOT_PLACEHOLDER = '<ROOT>';
15
15
  export const BASELINE_CACHE_MAX_ENTRIES = 50;
16
- const CACHE_FORMAT = 1;
16
+ const CACHE_FORMAT = 2;
17
17
 
18
18
  /** 키에 들어가는 «기준 커밋의 설정 파일» — 이 중 하나라도 달라지면 같은 sha 라도 다른 진단이다. */
19
19
  export const BASELINE_CACHE_CONFIG_FILES = ['tsconfig.gate.json', 'apps/pwa/tsconfig.json', 'tsconfig.pwa-env.json', 'tsconfig.json', 'bun.lock'] as const;
@@ -24,6 +24,8 @@ export interface BaselineCacheOptions {
24
24
  env?: NodeJS.ProcessEnv;
25
25
  /** git 실행 심 — 출력 바이트를 돌려주고 실패하면 던진다. */
26
26
  git?: (args: string[], cwd: string) => Buffer;
27
+ /** 작업 트리 설치 파일 읽기 심 — 파일 바이트를 돌려주고 읽을 수 없으면 던진다. */
28
+ readInstallFile?: (path: string) => Buffer;
27
29
  /** tsc 판 조회 심. */
28
30
  tscVersion?: (cwd: string) => string;
29
31
  maxEntries?: number;
@@ -59,6 +61,27 @@ function defaultTscVersion(cwd: string): string {
59
61
  }
60
62
  }
61
63
 
64
+ /** 키에 들어가는 «작업 트리에 실제로 깔린 판» — base 쪽 bun.lock 이 같아도 설치가 다르면 진단이 다르다. */
65
+ const BASELINE_CACHE_INSTALL_FILES = ['bun.lock', 'apps/pwa/bun.lock'] as const;
66
+
67
+ /**
68
+ * 지금 트리에 실제로 깔린 판의 키 — 작업 트리 루트 `bun.lock`(⊕ 있으면 `apps/pwa/bun.lock`) 파일 해시.
69
+ * 루트 `bun.lock` 을 못 읽으면 undefined(호출자는 캐시 없이 잰다 — base 키 규율과 같다) · `apps/pwa/bun.lock` 은 못 읽으면 absent.
70
+ */
71
+ export function workingTreeInstallKey(cwd: string, options: Pick<BaselineCacheOptions, 'readInstallFile'> = {}): string | undefined {
72
+ const read = options.readInstallFile ?? ((path: string) => readFileSync(path));
73
+ const files: Record<string, string> = {};
74
+ for (const file of BASELINE_CACHE_INSTALL_FILES) {
75
+ try {
76
+ files[file] = createHash('sha256').update(read(join(cwd, file))).digest('hex');
77
+ } catch {
78
+ if (file === 'bun.lock') return undefined;
79
+ files[file] = 'absent';
80
+ }
81
+ }
82
+ return createHash('sha256').update(JSON.stringify(files)).digest('hex');
83
+ }
84
+
62
85
  /** 키를 못 만들면(base 를 sha 로 풀 수 없음 등) undefined — 호출자는 캐시 없이 잰다. */
63
86
  export function computeBaselineCacheKey(base: string, command: string, cwd: string, options: BaselineCacheOptions = {}): string | undefined {
64
87
  try {
@@ -73,8 +96,10 @@ export function computeBaselineCacheKey(base: string, command: string, cwd: stri
73
96
  files[file] = 'absent';
74
97
  }
75
98
  }
99
+ const install = workingTreeInstallKey(cwd, options);
100
+ if (install === undefined) return undefined;
76
101
  const tsc = (options.tscVersion ?? defaultTscVersion)(cwd);
77
- return createHash('sha256').update(JSON.stringify({ format: CACHE_FORMAT, sha, command, files, tsc })).digest('hex');
102
+ return createHash('sha256').update(JSON.stringify({ format: CACHE_FORMAT, sha, command, files, install, tsc })).digest('hex');
78
103
  } catch {
79
104
  return undefined;
80
105
  }
@@ -15,8 +15,11 @@ export interface UsageRow { site: string; provider: string; model: string; calls
15
15
 
16
16
  type UsageData = { site?: string; provider?: string; billingProvider?: string; model?: string; inputTokens?: number; outputTokens?: number; cacheReadInputTokens?: number; cacheCreationInputTokens?: number; cost?: { kind?: string; usd?: number }; podRollupKey?: string; partial?: boolean; partialSeq?: number; partialAt?: string };
17
17
 
18
+ /** 재방출 행 dedup 에 필요한 칸만 — 호스트 소비처(bench-report · `elanous usage`)도 같은 규칙을 쓴다. */
19
+ export type PodRollupKeyed = { podRollupKey?: unknown; partial?: unknown; partialSeq?: unknown; partialAt?: unknown };
20
+
18
21
  /** 같은 podRollupKey 두 행 중 어느 쪽이 더 완전한가 — 최종 > 부분 · 부분끼리는 seq 큰 쪽 · 같으면 at 늦은 쪽. 완전히 같으면 앞 행을 둔다. */
19
- function rollupRowBeats(next: UsageData, kept: UsageData): boolean {
22
+ function rollupRowBeats(next: PodRollupKeyed, kept: PodRollupKeyed): boolean {
20
23
  const nextFinal = next.partial !== true;
21
24
  const keptFinal = kept.partial !== true;
22
25
  if (nextFinal !== keptFinal) return nextFinal;
@@ -27,31 +30,42 @@ function rollupRowBeats(next: UsageData, kept: UsageData): boolean {
27
30
  return String(next.partialAt ?? '') > String(kept.partialAt ?? '');
28
31
  }
29
32
 
33
+ /** ⭐ METER-POD-ROLLUP-GAP-2 — 같은 Pod 사용량의 재방출(부분 ⊕ 최종 · abort ⊕ resume)을 podRollupKey 로 한 번만 남긴다.
34
+ * 들어온 순서가 아니라 «더 완전한 행»을 남기고(rollupRowBeats), 키 없는 행은 그대로 다 둔다(순서 보존). */
35
+ export function dedupePodRollupRows<T>(rows: readonly T[], dataOf: (row: T) => PodRollupKeyed = (row) => row as PodRollupKeyed): T[] {
36
+ const kept: T[] = [];
37
+ const keptIndexByKey = new Map<string, number>();
38
+ for (const row of rows) {
39
+ const d = dataOf(row);
40
+ if (typeof d.podRollupKey === 'string') {
41
+ const at = keptIndexByKey.get(d.podRollupKey);
42
+ if (at !== undefined) {
43
+ if (rollupRowBeats(d, dataOf(kept[at]!))) kept[at] = row;
44
+ continue;
45
+ }
46
+ keptIndexByKey.set(d.podRollupKey, kept.length);
47
+ }
48
+ kept.push(row);
49
+ }
50
+ return kept;
51
+ }
52
+
30
53
  export function rollup(lines: readonly string[]): { rows: UsageRow[]; truncated: boolean } {
31
54
  const by = new Map<string, UsageRow>();
32
55
  // ⭐ MF-3c0d253e — 같은 Pod 사용량의 재방출(부분 ⊕ 최종 · abort ⊕ resume)은 podRollupKey 로 한 번만 센다(이중계상 방지).
33
56
  // 들어온 순서가 아니라 «더 완전한 행»을 남긴다(최종 > 부분 · seq · at — rollupRowBeats).
34
57
  // 키가 없는 행(기존 경로 전부)은 종전과 동작·바이트 그대로다.
35
58
  let truncated = false;
36
- const entries: UsageData[] = [];
37
- const keptIndexByPodRollupKey = new Map<string, number>();
59
+ const parsed: UsageData[] = [];
38
60
  for (const line of lines) {
39
61
  if (/limitReached=true|truncated/.test(line) && !line.startsWith('{')) truncated = true;
40
62
  if (!line.startsWith('{')) continue;
41
63
  let r: { event?: string; data?: Record<string, unknown> };
42
64
  try { r = JSON.parse(line); } catch { continue; }
43
65
  if (r.event !== 'llm-usage' || !r.data) continue;
44
- const d = r.data as UsageData;
45
- if (typeof d.podRollupKey === 'string') {
46
- const keptIndex = keptIndexByPodRollupKey.get(d.podRollupKey);
47
- if (keptIndex !== undefined) {
48
- if (rollupRowBeats(d, entries[keptIndex]!)) entries[keptIndex] = d;
49
- continue;
50
- }
51
- keptIndexByPodRollupKey.set(d.podRollupKey, entries.length);
52
- }
53
- entries.push(d);
66
+ parsed.push(r.data as UsageData);
54
67
  }
68
+ const entries = dedupePodRollupRows(parsed);
55
69
  for (const d of entries) {
56
70
  const provider = d.billingProvider ?? d.provider ?? '?'; // ⭐ 과금 주체 우선(B10)
57
71
  const key = `${d.site ?? '?'}|${provider}|${d.model ?? '?'}`;