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
@@ -28,6 +28,8 @@ import { TA_LAND_ENV } from '../../task-agent/task-hand.js';
28
28
  import { appendRunLedgerEntry, loadRunLedger, runLedgerDir, runLedgerPath } from '../../self-implement/run-ledger.js';
29
29
  import type { GoalExecutionRecord } from '../../self-implement/orchestrator.js';
30
30
  import { runHostRegate, type HostRegateResult } from '../../self-implement/host-regate.js';
31
+ import { resolvePodHostAcpReview, runPodHostAcpReview, type PodHostAcpReviewOutcome } from './pod-host-acp-review.js';
32
+ import { REVIEW_DEFERRED_TO_HOST_ENV, REVIEW_DEFERRED_TO_HOST_MERGE_REASON } from '../../self-implement/review-deferred-to-host.js';
31
33
  import { classifyPodTerminal, applyPodTerminal, podTerminalPrBody, type PrTerminalRecord, type DraftResidueContext } from '../../self-dev/draft-residue.js';
32
34
 
33
35
  export const POD_CONTROL_INBOX_DIR = '/tmp/elanous-control.inbox';
@@ -50,7 +52,7 @@ export const POD_JOB_DEADLINE_SECONDS = 10_800;
50
52
  // POD-DIET (10-06 03:47~05:18 · node-b goal Pods · 89 one-minute samples · 42 Pods): per-Pod observed max median 4.6Gi ·
51
53
  // p75 6.2Gi · p90 11.7Gi — 23/42 went above the old 4Gi request, so the scheduler over-packed. 6Gi ≈ p75; limits stay.
52
54
  // Node allocatable ≈ 343Gi ≫ 25 × 6Gi. One-minute samples can miss the true peak (lower bound).
53
- import type { PodPlacement, PodPlacementKind, PodPoolMember, PodPoolScheduler } from './pod-pool.js';
55
+ import { podWorkLabels, type PodWorkIdentity, type PodPlacement, type PodPlacementKind, type PodPoolMember, type PodPoolScheduler } from './pod-pool.js';
54
56
  export { POD_CHILD_REQUESTS } from './pod-lease.js';
55
57
  import { measurePoolLease, recommendConcurrency, POD_CHILD_REQUESTS, POD_HOST_LEASE_ANNOTATION, POD_JOB_TTL_AFTER_FINISHED_SECONDS, LEASE_KUBECTL_MAX_BUFFER, memoryQuantityBytes } from './pod-lease.js';
56
58
  import { ACTUAL_SUBSTRATE_ENV, RUN_CONTRACT_ENV, carryRunContract, completionFloorFor } from '../../self-implement/graph-run-contract.js';
@@ -67,9 +69,11 @@ import { enterJourneyNode, exitJourneyNode, passJourneyNode } from '../../self-d
67
69
  import { routeJourneyEdge } from '../../self-dev/graph-journey-route.js';
68
70
  import { selectLiveDetail } from '../../live/detail-switch.js';
69
71
  import { authStorePath } from '../../oauth/store.js';
70
- import { grokAuthFilePath, isGrokSubscriptionExpiring, refreshGrokSubscriptionToken, resolveGrokCredential } from '../../grok/credential.js';
72
+ import { grokAuthFilePath, isGrokSubscriptionExpiring, refreshGrokSubscriptionToken, resolveGrokCredential, type GrokRefreshOutcome } from '../../grok/credential.js';
71
73
  import { defaultGrokModel } from '../../grok/models.js';
72
74
  import { resolveHostId } from '../../platform/host-id.js';
75
+ import { BUDGET_SNAPSHOT_ENV, encodeBudgetSnapshot, harnessLaunchBudgetDecision, type BudgetSnapshot } from '../../execution-loop/launch-gate.js';
76
+ import type { ReadBudgetInputsDeps } from '../../self-implement/budget-gate.js';
73
77
  import { envLiteral } from '../../platform/env-literal.js';
74
78
  import { LLM_TIER_MAP_BY_PROVIDER, lookupLlmTierSpec, type LlmTierProvider } from '../../model-tier/llm-tier-map.js';
75
79
  import { parseSelfImplementJson, type SelfImplementJobDone, type SelfImplementJobSpawn } from './self-implement.js';
@@ -84,7 +88,7 @@ import { resolveBedrockRegion, validBedrockRegion } from '../../llm/bedrock.js';
84
88
  import { ZAI_POD_EGRESS_LABEL, checkZaiPodSecret, countActiveZaiJobs, decideZaiPodSlot, zaiOverflowChildArgs, zaiPodEnv, type ZaiPodSpec } from './pod-zai-child.js';
85
89
  import { ZAI_CODING_DEFAULT_MODEL, ZAI_OPENROUTER_FALLBACK_MODEL, zaiSettingsFromConfig, type ZaiCodingPlanSettings } from '../../llm/zai-coding-plan.js';
86
90
  import { selectEnhanceLlm } from '../../prompt-enhance/enhance.js';
87
- import { extractPodFailureReason, podTerminalRow } from './pod-failure-reason.js';
91
+ import { classifyPodExit, extractPodFailureReason, podTerminalRow, type PodExitClass } from './pod-failure-reason.js';
88
92
  import { OLD_DOOR_STAMP_ENV } from '../../self-dev/old-door.js';
89
93
 
90
94
  export type Kubectl = (args: readonly string[], input?: string) => { status: number | null; stdout: string; stderr: string };
@@ -110,6 +114,10 @@ export interface PodSpawnOptions {
110
114
  rotationAccounts?: readonly string[];
111
115
  /** 미지정이면 종전 Codex Job. */
112
116
  provider?: PodChildProvider;
117
+ /** Host launch-gate verdict for this Job's child LLM (test seam) — the Pod gate follows it instead of judging again. Default: the host's own `harness` launch-gate decision (chain ⊕ user caps). */
118
+ budgetSnapshot?: (childLlm: PodBudgetChildLlm) => Promise<BudgetSnapshot | undefined> | BudgetSnapshot | undefined;
119
+ /** Input reader seam; the host still runs its normal budget decision and Job propagation. */
120
+ budgetInputDeps?: ReadBudgetInputsDeps & { readLiveGrok?: () => Promise<number | undefined> };
113
121
  /** Child model/effort chosen at launch (`--child-llm-model/--child-llm-effort`) — carried into the Pod child. */
114
122
  childModel?: string;
115
123
  childEffort?: string;
@@ -142,11 +150,17 @@ export interface PodSpawnOptions {
142
150
  /** Job 수명 상한(초). */
143
151
  deadlineSeconds?: number;
144
152
  pollMs?: number;
153
+ /** METER-POD-ROLLUP-GAP-3 — 런 도중 PARTIAL 표본을 거두는 폴 간격 수(시험 seam · 기본 POD_USAGE_PARTIAL_CAPTURE_MS ÷ pollMs). */
154
+ usagePartialCapturePolls?: number;
145
155
  /** LAUNCH-STALL: ms a launch may wait in one stage before `launch-stalled` (test seam; default harness.launchStallMinutes · 15 min). */
146
156
  launchStallMs?: number;
147
157
  kubectl?: Kubectl;
148
158
  /** Host-side regate (injected for Pod tests). */
149
159
  hostRegate?: (input: { prNumber: number; headCommit: string; repoRoot: string; goalFile?: string; noMerge?: true }) => Promise<HostRegateResult>;
160
+ /** REVIEW-ACP-POD — Pod merge-ready PR 을 호스트 Claude ACP 로 리뷰한 뒤 재게이트(opt-in · 옵션 → env `ELANOUS_POD_HOST_ACP_REVIEW` → config `llm.podHostAcpReview`). */
161
+ hostAcpReview?: boolean;
162
+ /** REVIEW-ACP-POD — 호스트 ACP 리뷰 seam(시험 주입 · 기본 `runPodHostAcpReview`). */
163
+ podHostAcpReview?: (input: { prNumber: number; headCommit: string; repoRoot: string; job?: string }) => Promise<PodHostAcpReviewOutcome>;
150
164
  /**
151
165
  * TA-LIVE-LAND-2 — `taskAgent.liveMoves` (test seam; default reads the user config). Consulted only when the run carries
152
166
  * the `ELANOUS_TA_LAND=1` marker (`tasks hand --ta-land`): with `propose-land` the host re-gates but leaves the merge to
@@ -221,6 +235,52 @@ export function podJobName(spaceId: string): string {
221
235
  return `si-${slug || 'job'}-${hash}`.replace(/-+/g, '-').slice(0, 58);
222
236
  }
223
237
 
238
+ /** The child LLM the Pod's delegated `harness say/ask` will be launched with — the question the host verdict answers. */
239
+ export interface PodBudgetChildLlm { provider?: string; model?: string }
240
+
241
+ /** The one host-side budget verdict a Pod Job carries (BUDGET-SNAPSHOT-TO-POD). Fail-soft: no snapshot means the Pod marks the budget unmeasured. */
242
+ function hostBudgetSnapshot(childLlm: PodBudgetChildLlm, options: PodSpawnOptions, env: NodeJS.ProcessEnv, job: string): Promise<BudgetSnapshot | undefined> | BudgetSnapshot | undefined {
243
+ const unavailable = (error: unknown): undefined => {
244
+ try { debug.log('self-implement.pod', 'budget-snapshot-unavailable', { job, provider: childLlm.provider ?? null, reason: error instanceof Error ? error.message : String(error) }, { level: 'warn' }); } catch { /* observation is fail-soft */ }
245
+ return undefined;
246
+ };
247
+ let measurement: Promise<BudgetSnapshot | undefined> | BudgetSnapshot | undefined;
248
+ try {
249
+ measurement = options.budgetSnapshot ? options.budgetSnapshot(childLlm) : measureHostBudgetSnapshot(childLlm, env, options.budgetInputDeps);
250
+ } catch (error) { return unavailable(error); }
251
+ if (!(measurement instanceof Promise)) return measurement;
252
+ let timer: ReturnType<typeof setTimeout> | undefined;
253
+ const deadline = new Promise<undefined>((resolve) => {
254
+ timer = setTimeout(() => resolve(unavailable(new Error('host budget snapshot timed out after 10s'))), 10_000);
255
+ });
256
+ return Promise.race([measurement, deadline]).catch(unavailable).finally(() => { if (timer) clearTimeout(timer); });
257
+ }
258
+
259
+ /** The host runs the same launch-gate judgement the Pod would (chain ⊕ the user's caps) and ships the verdict, not raw usage to re-judge. */
260
+ async function measureHostBudgetSnapshot(childLlm: PodBudgetChildLlm, env: NodeJS.ProcessEnv, inputDeps?: ReadBudgetInputsDeps & { readLiveGrok?: () => Promise<number | undefined> }): Promise<BudgetSnapshot | undefined> {
261
+ const host = resolveHostId(env);
262
+ const measuredAt = Date.now();
263
+ const { readBudgetInputsLive, CODEX_PROVIDER, GROK_PROVIDER } = await import('../../self-implement/budget-gate.js');
264
+ const inputs = await readBudgetInputsLive(inputDeps);
265
+ const { decision } = harnessLaunchBudgetDecision(inputs, { ...(childLlm.provider ? { childLlmProvider: childLlm.provider } : {}), ...(childLlm.model ? { childLlmModel: childLlm.model } : {}) });
266
+ const provider = decision.provider ?? childLlm.provider ?? 'chain';
267
+ const used = provider === GROK_PROVIDER
268
+ ? inputs.grokUsedPercent
269
+ : provider === CODEX_PROVIDER
270
+ ? (() => {
271
+ const percents = inputs.codexCandidates
272
+ .map((candidate) => candidate.reached === true ? 100 : candidate.usedPercent)
273
+ .filter((percent): percent is number => typeof percent === 'number' && Number.isFinite(percent));
274
+ return percents.length === 0 ? undefined : Math.min(...percents);
275
+ })()
276
+ : undefined;
277
+ return {
278
+ provider, ...(used !== undefined ? { remaining: Math.min(100, Math.max(0, 100 - used)) } : {}), window: 'weekly', measuredAt, host,
279
+ ...(childLlm.provider ? { requested: childLlm.provider } : {}),
280
+ decision: { action: decision.action, ...(decision.provider ? { provider: decision.provider } : {}), ...(decision.model ? { model: decision.model } : {}) },
281
+ };
282
+ }
283
+
224
284
  /** «3시간 안 만료» — 선갱신 대상이라는 표지(다른 자격 오류와 구분한다). */
225
285
  export class PodCodexExpiringError extends Error {
226
286
  constructor(readonly account: string, readonly hoursLeft: number) {
@@ -403,10 +463,16 @@ export type PodGrokSkipReason = 'missing' | 'expiring' | 'refresh-failed';
403
463
 
404
464
  /** GROK-OPTIONAL (10-05) — may this launch plan put grok in the Pod's chain at all?
405
465
  * The Pod copy must outlive the Job (POD_GROK_MIN_VALIDITY_MS), so an expiring subscription that the host cannot
406
- * refresh is «not available» here: the plan drops grok and goes on with codex instead of failing every launch. */
466
+ * refresh is «not available» here: the plan drops grok and goes on with codex instead of failing every launch.
467
+ * AUT-GROK-CRED-EXPIRY-NO-LAUNCH (10-12): the refresh is already attempted once (`grok models`), but
468
+ * `refreshGrokSubscriptionToken` reports failure as a «value», never a throw — so a missing/broken CLI used to be
469
+ * read as `expiring`. The outcome is now classified (`failed`/`no-credential` → `refresh-failed`, `unchanged` →
470
+ * `expiring`) and every unusable verdict also lands as `harness.pod`/`grok-credential-unusable` so the autopsy and
471
+ * the dispatcher can group same-cause no-launches. ⛔ Never switches the provider here (billing path unchanged). */
407
472
  export function podGrokSubscriptionUsable(opts: {
408
473
  home?: string; env?: NodeJS.ProcessEnv;
409
- refresh?: () => void; isExpiring?: () => boolean; expiresAt?: () => string | null;
474
+ /** Test seam — the host refresh. A returned outcome is classified; `void` counts as an attempt that did not fail. */
475
+ refresh?: () => GrokRefreshOutcome | void; isExpiring?: () => boolean; expiresAt?: () => string | null;
410
476
  log?: (category: string, event: string, data: Record<string, unknown>) => void;
411
477
  } = {}): { usable: true } | { usable: false; reason: PodGrokSkipReason; expiresAt: string | null } {
412
478
  const log = opts.log ?? ((category, event, data) => debug.log(category, event, data));
@@ -418,19 +484,35 @@ export function podGrokSubscriptionUsable(opts: {
418
484
  return all.sort().at(-1) ?? null;
419
485
  } catch { return null; }
420
486
  };
421
- const skip = (reason: PodGrokSkipReason) => {
487
+ const skip = (reason: PodGrokSkipReason, refreshOutcome: GrokRefreshOutcome | 'threw' | 'not-attempted') => {
422
488
  const at = expiresAt();
423
- try { log('pod.grok-credentials', 'skipped', { reason, expiresAt: at }); } catch { /* observation is fail-soft */ }
489
+ try { log('pod.grok-credentials', 'skipped', { reason, expiresAt: at, refreshOutcome }); } catch { /* observation is fail-soft */ }
490
+ try { log('harness.pod', 'grok-credential-unusable', { reason, expiresAt: at, refreshOutcome, minValidityMs: POD_GROK_MIN_VALIDITY_MS }); } catch { /* fail-soft */ }
424
491
  return { usable: false as const, reason, expiresAt: at };
425
492
  };
426
493
  const credential = resolveGrokCredential({ home: opts.home, env: opts.env });
427
- if (credential?.kind !== 'subscription') return skip('missing');
494
+ if (credential?.kind !== 'subscription') return skip('missing', 'not-attempted');
428
495
  const expiring = opts.isExpiring ?? (() => isGrokSubscriptionExpiring({ home: opts.home, bufferMs: POD_GROK_MIN_VALIDITY_MS }));
429
496
  if (!expiring()) return { usable: true };
430
- let refreshed = true;
431
- try { (opts.refresh ?? (() => { refreshGrokSubscriptionToken({ home: opts.home }); }))(); } catch { refreshed = false; }
497
+ let outcome: GrokRefreshOutcome | 'threw' = 'unchanged';
498
+ try { outcome = (opts.refresh ?? (() => refreshGrokSubscriptionToken({ home: opts.home })))() ?? 'unchanged'; } catch { outcome = 'threw'; }
432
499
  if (!expiring()) return { usable: true };
433
- return skip(refreshed ? 'expiring' : 'refresh-failed');
500
+ return skip(outcome === 'failed' || outcome === 'no-credential' || outcome === 'threw' ? 'refresh-failed' : 'expiring', outcome);
501
+ }
502
+
503
+ /** AUT-GROK-CRED-EXPIRY-NO-LAUNCH — read-only launch check for dispatchers: no refresh, no CLI spawn, no log.
504
+ * `ready:false` means a Pod launch that names grok will be refused (or drop grok) unless a refresh extends the token. */
505
+ export function grokLaunchReadiness(opts: { home?: string; env?: NodeJS.ProcessEnv; now?: () => number } = {}):
506
+ { ready: true; expiresAt: string | null } | { ready: false; reason: 'missing' | 'expiring'; expiresAt: string | null } {
507
+ const credential = resolveGrokCredential({ home: opts.home, env: opts.env });
508
+ let at: string | null = null;
509
+ try {
510
+ const scopes = JSON.parse(readFileSync(grokAuthFilePath(opts.home), 'utf8')) as Record<string, { expires_at?: unknown }>;
511
+ at = Object.values(scopes).flatMap((s) => (s && typeof s.expires_at === 'string' ? [s.expires_at] : [])).sort().at(-1) ?? null;
512
+ } catch { /* no auth file */ }
513
+ if (credential?.kind !== 'subscription') return { ready: false, reason: 'missing', expiresAt: at };
514
+ const expiring = isGrokSubscriptionExpiring({ home: opts.home, bufferMs: POD_GROK_MIN_VALIDITY_MS, ...(opts.now ? { now: opts.now } : {}) });
515
+ return expiring ? { ready: false, reason: 'expiring', expiresAt: at } : { ready: true, expiresAt: at };
434
516
  }
435
517
 
436
518
  /** The one launch line for a skipped grok copy — the reader sees why grok left this run's chain. */
@@ -861,11 +943,17 @@ export function podDelegatedChildLlm(args: readonly string[]): { provider: strin
861
943
  * 짧게(≤8s) 백그라운드로 쏘고 `exit 143` 으로 원래 rc 를 보존한다 — podUsageMissingReason 의 `sigterm-143`
862
944
  * 분기가 실물 경로로 도달한다(시험은 합성 exitCode:143 이 아니라 실물 신호로 잰다).
863
945
  * ⛔ 롤업 실패는 rc 를 바꾸지 않는다(각 단계 `|| true`). trap 몸통은 짧게 유지한다(골 ①). */
864
- export function podSigtermTrapScript(): string {
865
- return `trap '{ [ -n "$si_pid" ] && kill "$si_pid" 2>/dev/null || true; { [ -f scripts/usage-rollup.ts ] && bun scripts/usage-rollup.ts --since 12h --partial; } & si_rollup_pid=$!; for si_i in 1 2 3 4 5 6 7 8; do kill -0 "$si_rollup_pid" 2>/dev/null || break; sleep 1; done; kill "$si_rollup_pid" 2>/dev/null || true; wait "$si_rollup_pid" 2>/dev/null || true; exit 143; }' TERM`;
946
+ /** METER-POD-ROLLUP-GAP-2 — 부분 롤업 표본기가 «방금 낸 seq» 를 적는 파일. trap 은 여기에 +1 해 마지막 PARTIAL 이 가장 큰 seq 를 갖게 한다
947
+ * (표본기는 서브셸이라 변수가 trap 에 안 보인다 · 없거나 숫자가 아니면 0 으로 보고 1 을 쓴다). */
948
+ export const POD_USAGE_PARTIAL_SEQ_FILE = '/tmp/si.usage-partial-seq';
949
+
950
+ export function podSigtermTrapScript(seqFile: string = POD_USAGE_PARTIAL_SEQ_FILE): string {
951
+ // ⭐ METER-POD-ROLLUP-GAP-2 — trap PARTIAL 은 `--seq <표본기 seq + 1>` 로 낸다(전엔 seq 가 늘 1 이라 dedup 에서 앞선 표본에 졌다) ·
952
+ // 표본기를 먼저 끊어 trap 뒤에 옛 표본이 «마지막 줄»로 끼어들지 않게 한다.
953
+ return `trap '{ [ -n "$si_pid" ] && kill "$si_pid" 2>/dev/null || true; [ -n "\${usage_partial_pid:-}" ] && kill "$usage_partial_pid" 2>/dev/null || true; si_seq=$(cat ${seqFile} 2>/dev/null || true); case "$si_seq" in ""|*[!0-9]*) si_seq=0;; esac; si_seq=$((10#$si_seq + 1)); { [ -f scripts/usage-rollup.ts ] && bun scripts/usage-rollup.ts --since 12h --partial --seq "$si_seq"; } & si_rollup_pid=$!; for si_i in 1 2 3 4 5 6 7 8; do kill -0 "$si_rollup_pid" 2>/dev/null || break; sleep 1; done; kill "$si_rollup_pid" 2>/dev/null || true; wait "$si_rollup_pid" 2>/dev/null || true; exit 143; }' TERM`;
866
954
  }
867
955
 
868
- export function podJobManifest(o: { name: string; namespace: string; image: string; /** 레지스트리 이미지면 IfNotPresent(노드가 pull) · 반입 이미지면 Never. */ imagePullPolicy?: 'Never' | 'IfNotPresent'; repoUrl: string; source?: PodSource; hostMirror?: string; args: readonly string[]; passEnv: readonly string[]; deadlineSeconds: number; runId?: string; parentRunId?: string; armEnv?: Readonly<Record<string, string>>; hostId?: string; imageCommit?: string | null; skillEnvs?: readonly string[]; memoryLimit?: string; memoryRequest?: string; goalDoc?: string; /** AUTHOR-POD2 — run `harness say` on /creds/feature inside the Pod (authoring happens off the host). */ authorSentence?: boolean; authorGrade?: 'full' | 'lite'; grokCredential?: 'subscription' | 'api_key'; codexAccounts?: readonly string[]; appCredential?: boolean; /** Test seam — default POD_GH_STALE_SECONDS. */ githubStaleSeconds?: number; /** Which goal execution and attempt this Job is — a resumed host verifies it before following the Job (POD9). */ execution?: { key: string; attempt: number }; hostLeaseAdmitted?: boolean; /** POD-ROLE-LLM — OpenRouter 자식 Pod 에 리뷰어용 codex 자격을 깐다. */ reviewerCodexAuth?: boolean; /** BEDROCK-PROVIDER ② — bedrock 자식만: 이름 있는 AWS Secret 의 키(secretKeyRef) ⊕ 리전 ⊕ 이그레스 라벨. */ bedrock?: BedrockPodSpec; /** ZAI-POD-CHILD — glm(ZAI) 자식만: 이름 있는 ZAI Secret 의 키(secretKeyRef) ⊕ 이그레스·동시 상한 라벨(Pod ⊕ Job). */ zai?: ZaiPodSpec }): Record<string, unknown> {
956
+ export function podJobManifest(o: { name: string; namespace: string; image: string; workIdentity?: PodWorkIdentity; /** 레지스트리 이미지면 IfNotPresent(노드가 pull) · 반입 이미지면 Never. */ imagePullPolicy?: 'Never' | 'IfNotPresent'; repoUrl: string; source?: PodSource; hostMirror?: string; args: readonly string[]; passEnv: readonly string[]; deadlineSeconds: number; runId?: string; parentRunId?: string; armEnv?: Readonly<Record<string, string>>; hostId?: string; imageCommit?: string | null; skillEnvs?: readonly string[]; memoryLimit?: string; memoryRequest?: string; goalDoc?: string; /** AUTHOR-POD2 — run `harness say` on /creds/feature inside the Pod (authoring happens off the host). */ authorSentence?: boolean; authorGrade?: 'full' | 'lite'; grokCredential?: 'subscription' | 'api_key'; codexAccounts?: readonly string[]; appCredential?: boolean; /** Test seam — default POD_GH_STALE_SECONDS. */ githubStaleSeconds?: number; /** Which goal execution and attempt this Job is — a resumed host verifies it before following the Job (POD9). */ execution?: { key: string; attempt: number }; hostLeaseAdmitted?: boolean; /** POD-ROLE-LLM — OpenRouter 자식 Pod 에 리뷰어용 codex 자격을 깐다. */ reviewerCodexAuth?: boolean; /** BEDROCK-PROVIDER ② — bedrock 자식만: 이름 있는 AWS Secret 의 키(secretKeyRef) ⊕ 리전 ⊕ 이그레스 라벨. */ bedrock?: BedrockPodSpec; /** ZAI-POD-CHILD — glm(ZAI) 자식만: 이름 있는 ZAI Secret 의 키(secretKeyRef) ⊕ 이그레스·동시 상한 라벨(Pod ⊕ Job). */ zai?: ZaiPodSpec }): Record<string, unknown> {
869
957
  const quoted = o.args.map((a) => `'${a.replace(/'/g, `'\\''`)}'`).join(' ');
870
958
  const childProviderIndex = o.args.indexOf('--child-llm-provider');
871
959
  const childModelIndex = o.args.indexOf('--child-llm-model');
@@ -916,7 +1004,7 @@ export function podJobManifest(o: { name: string; namespace: string; image: stri
916
1004
  `(while :; do { mem=$(if [ -r /sys/fs/cgroup/memory.current ]; then cat /sys/fs/cgroup/memory.current; elif [ -r /sys/fs/cgroup/memory/memory.usage_in_bytes ]; then cat /sys/fs/cgroup/memory/memory.usage_in_bytes; else printf -- -; fi); top=$(ps -eo rss=,comm=,args= --sort=-rss | head -5 | awk 'function encode(s) { gsub(/%/, "%25", s); gsub(/:/, "%3A", s); gsub(/ /, "%20", s); gsub(/\\t/, "%09", s); return s } { rss=$1; name=$2; sub(/^[[:space:]]*[0-9]+[[:space:]]+[^[:space:]]+[[:space:]]*/, ""); n=split($0, a, /[[:space:]]+/); cmd="<redacted>"; if (name=="sleep" && a[2]=="30") cmd="sleep 30" (n>2 ? " <redacted>" : ""); else if (name=="bun") { cmd="bun <redacted>"; if (a[2]=="test") cmd="bun test <redacted>"; else if (a[2]=="run") cmd="bun run <redacted>"; else if ((a[2]=="x" || a[2]=="exec") && a[3]=="tsc") cmd="bun x tsc <redacted>" } else if (name=="tsc") cmd="tsc <redacted>"; else if (name=="elanous") { cmd="elanous <redacted>"; if (a[2]=="self") cmd="elanous self <redacted>"; else if (a[2]=="harness") cmd="elanous harness <redacted>" } else if (name=="node") cmd="node <redacted>"; if (name=="sleep" && cmd=="<redacted>") cmd="sleep <redacted>"; else if (cmd=="<redacted>" && name!="bash" && name!="sh") name="other"; printf " %s:%s:%s", rss, encode(name), encode(substr(cmd,1,120)) }'); printf "ELANOUS_MEM %s %s%s\\n" "$(date +%s)" "$mem" "$top"; } || true; sleep 15 || break; done) & mem_sampler_pid=$!`,
917
1005
  ...(o.appCredential ? [podGithubWatchdogScript(o.githubStaleSeconds ?? POD_GH_STALE_SECONDS)] : []),
918
1006
  // METER-POD-ROLLUP-GAP — 부분 롤업 표본기: 최종 줄까지 못 사는 Pod 도 N 분마다(기본 5 · ELANOUS_USAGE_PARTIAL_MINUTES) PARTIAL 줄을 하나씩 남긴다.
919
- `(usage_partial_seq=0; while :; do { usage_partial_seq=$((usage_partial_seq+1)); [ -f scripts/usage-rollup.ts ] && bun scripts/usage-rollup.ts --since 12h --partial --seq "$usage_partial_seq" || true; } || true; usage_partial_sleep=$(( \${ELANOUS_USAGE_PARTIAL_MINUTES:-5} * 60 )); sleep "$usage_partial_sleep" || break; done) & usage_partial_pid=$!`,
1007
+ `(usage_partial_seq=0; while :; do { usage_partial_seq=$((usage_partial_seq+1)); printf '%s\\n' "$usage_partial_seq" > ${POD_USAGE_PARTIAL_SEQ_FILE} 2>/dev/null || true; [ -f scripts/usage-rollup.ts ] && bun scripts/usage-rollup.ts --since 12h --partial --seq "$usage_partial_seq" || true; } || true; usage_partial_sleep=$(( \${ELANOUS_USAGE_PARTIAL_MINUTES:-5} * 60 )); sleep "$usage_partial_sleep" || break; done) & usage_partial_pid=$!`,
920
1008
  // ⭐ MF-d3b5a70f — si_pid 초기화 + trap: 메인 명령을 아래에서 `& si_pid=$!` 로 띄우고 `wait "$si_pid"` 로
921
1009
  // 기다려야 trap 이 grace 안에 발화한다(bash 는 foreground 명령 실행 중 trap 을 미룬다). trap 은
922
1010
  // podSigtermTrapScript() 가 내놓는다(수신 측 reemitPodUsage 포맷과 계약을 같은 파일 안에서 공유).
@@ -997,7 +1085,7 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
997
1085
  return {
998
1086
  apiVersion: 'batch/v1',
999
1087
  kind: 'Job',
1000
- metadata: { name: o.name, namespace: o.namespace, labels: { 'elanous.substrate': 'pod', 'elanous.job': o.name, ...podRunLabels(o), ...(o.zai ? { [ZAI_POD_EGRESS_LABEL]: 'true' } : {}) },
1088
+ metadata: { name: o.name, namespace: o.namespace, labels: { 'elanous.substrate': 'pod', 'elanous.job': o.name, ...podRunLabels(o), ...(o.workIdentity ? podWorkLabels(o.workIdentity) : {}), ...(o.zai ? { [ZAI_POD_EGRESS_LABEL]: 'true' } : {}) },
1001
1089
  ...((o.execution || o.hostLeaseAdmitted) ? { annotations: { ...(o.execution ? { [POD_EXECUTION_KEY_ANNOTATION]: o.execution.key, [POD_ATTEMPT_ANNOTATION]: String(o.execution.attempt) } : {}), ...(o.hostLeaseAdmitted ? { [POD_HOST_LEASE_ANNOTATION]: 'true' } : {}) } } : {}) },
1002
1090
  spec: {
1003
1091
  backoffLimit: 0,
@@ -1005,7 +1093,7 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1005
1093
  activeDeadlineSeconds: o.deadlineSeconds,
1006
1094
  template: {
1007
1095
  // ⭐ Pod 라벨 — local 팔만 `elanous.egress/local-llm` 을 단다. docker/h1/policy-local-llm.yaml 이 그 라벨에만 호스트 LLM 포트 «하나»를 연다.
1008
- metadata: { labels: { 'elanous.job': o.name, ...podRunLabels(o), ...(o.armEnv?.ELANOUS_LLM_PROVIDER === 'local' ? { 'elanous.egress/local-llm': 'true' } : {}), ...(o.bedrock ? { [BEDROCK_POD_EGRESS_LABEL]: 'true' } : {}), ...(o.zai ? { [ZAI_POD_EGRESS_LABEL]: 'true' } : {}) } },
1096
+ metadata: { labels: { 'elanous.job': o.name, ...podRunLabels(o), ...(o.workIdentity ? podWorkLabels(o.workIdentity) : {}), ...(o.armEnv?.ELANOUS_LLM_PROVIDER === 'local' ? { 'elanous.egress/local-llm': 'true' } : {}), ...(o.bedrock ? { [BEDROCK_POD_EGRESS_LABEL]: 'true' } : {}), ...(o.zai ? { [ZAI_POD_EGRESS_LABEL]: 'true' } : {}) } },
1009
1097
  spec: {
1010
1098
  restartPolicy: 'Never',
1011
1099
  securityContext: { runAsUser: 1000, fsGroup: 1000 },
@@ -1705,11 +1793,20 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1705
1793
  ...(authorChoice.modelSource !== 'default' ? { ELANOUS_PROMPT_ENHANCE_MODEL: authorChoice.model } : {}),
1706
1794
  ...(authorChoice.effortSource !== 'default' ? { ELANOUS_PROMPT_ENHANCE_EFFORT: authorChoice.effort } : {}),
1707
1795
  } : {};
1708
- const jobArmEnv = grounding || credentialRelay || githubRelay || env.ELANOUS_DISPATCH_RECORDED === '1' || options.armEnv || detailUntil || seat || env.ELANOUS_POD_AUTHOR_ON_POD === '1' || reviewerPin
1796
+ const budgetRead = hostBudgetSnapshot(podDelegatedChildLlm(jobArgs) ?? {}, options, env, name);
1797
+ const budgetSnapshot = budgetRead instanceof Promise ? await budgetRead : budgetRead;
1798
+ // REVIEW-ACP-POD ②-b — 호스트가 병합 전에 Claude ACP 로 리뷰할 런이면 Pod 안 api 리뷰를 «호스트로 미룬다»(리뷰 둘 = 돈 두 번 방지).
1799
+ // ⛔ 자동 병합(merge-by-host) 런만 — 호스트 리뷰 문은 merge-ready 에서만 열린다. kubectl 주입(=시험)이면 사용자 설정을 읽지 않는다.
1800
+ const reviewDeferredToHost = input.autoMerge === true
1801
+ && resolvePodHostAcpReview(options.hostAcpReview, env, options.kubectl ? () => undefined : getUserConfig).enabled;
1802
+ if (reviewDeferredToHost) debug.log('self-implement.pod', 'review-deferred-armed', { job: name, env: REVIEW_DEFERRED_TO_HOST_ENV, ...(reviewerPin ? { reviewerPinUnused: reviewerPin } : {}) });
1803
+ const jobArmEnv = grounding || credentialRelay || githubRelay || env.ELANOUS_DISPATCH_RECORDED === '1' || options.armEnv || detailUntil || seat || env.ELANOUS_POD_AUTHOR_ON_POD === '1' || reviewerPin || reviewDeferredToHost || budgetSnapshot
1709
1804
  ? {
1710
1805
  ...armEnv,
1806
+ ...(budgetSnapshot ? { [BUDGET_SNAPSHOT_ENV]: encodeBudgetSnapshot(budgetSnapshot) } : {}),
1711
1807
  ...authorEnv,
1712
1808
  ...(reviewerPin ? { [roleLlmEnvName('review')]: reviewerPin } : {}),
1809
+ ...(reviewDeferredToHost ? { [REVIEW_DEFERRED_TO_HOST_ENV]: '1' } : {}),
1713
1810
  ...(detailUntil ? { ELANOUS_LIVE_DETAIL_UNTIL: detailUntil } : {}),
1714
1811
  ...(env.ELANOUS_DISPATCH_RECORDED === '1' ? { ELANOUS_DISPATCH_RECORDED: '1' } : {}),
1715
1812
  ...(seat === 'OP' || seat === 'TC' || seat === 'MK' || seat === 'UX' ? { ELANOUS_HARNESS_SEAT: seat } : {}),
@@ -1732,7 +1829,16 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1732
1829
  debug.log('self-implement.pod', 'memory-request', { spaceId: input.spaceId, job: name,
1733
1830
  tier: oomRetried ? retryTier : memoryTier, reason: oomRetried ? 'OOMKilled' : memoryReason,
1734
1831
  memoryLimit, memoryRequest });
1735
- const job = podJobManifest({ name, namespace, image: jobImage, ...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}), repoUrl, ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), args: jobArgs, passEnv: jobPassEnv, deadlineSeconds: options.deadlineSeconds ?? POD_JOB_DEADLINE_SECONDS, ...(goalDoc ? { goalDoc } : env.ELANOUS_POD_AUTHOR_ON_POD === '1' && !shard ? { authorSentence: true, ...(env.ELANOUS_POD_AUTHOR_GRADE === 'lite' || env.ELANOUS_POD_AUTHOR_GRADE === 'full' ? { authorGrade: env.ELANOUS_POD_AUTHOR_GRADE } : {}) } : {}), runId: launchRunId, ...(parentRunId ? { parentRunId } : {}), ...(jobArmEnv ? { armEnv: jobArmEnv } : {}), hostId: resolveHostId(env), skillEnvs: Object.keys(skillEnvs), memoryLimit, memoryRequest, imageCommit: options.imageCommit !== undefined ? options.imageCommit : options.kubectl ? null : podImageFreshness({ image }).imageCommit, ...(grok ? { grokCredential: 'grokAuth' in creds && creds.grokAuth ? 'subscription' as const : 'api_key' as const } : {}), ...(codexAccounts ? { codexAccounts } : {}), ...(hostRefresh ? { appCredential: true } : {}), execution: { key: executionKey, attempt: oomRetried ? 2 : 1 }, hostLeaseAdmitted: !!releaseAdmission, ...(reviewerCredential ? { reviewerCodexAuth: true } : {}), ...(bedrockSpec ? { bedrock: bedrockSpec } : {}), ...(zaiSpec ? { zai: zaiSpec } : {}) }); // kubectl 주입(=시험)이면 docker 를 부르지 않는다
1832
+ const ownerKind = env.ELANOUS_POD_OWNER_KIND;
1833
+ const workIdentity: PodWorkIdentity = {
1834
+ ...(ownerKind === 'seat' || ownerKind === 'steward' || ownerKind === 'orchestrator' || ownerKind === 'external'
1835
+ ? { ownerKind, ownerId: env.ELANOUS_POD_OWNER_ID } : seat === 'OP' || seat === 'TC' || seat === 'MK' || seat === 'UX'
1836
+ ? { ownerKind: 'seat', ownerId: seat } : {}),
1837
+ taskCard: env.ELANOUS_POD_TASK_CARD ?? env.ELANOUS_TASK_CARD_ID,
1838
+ slotId: env.ELANOUS_POD_SLOT_ID,
1839
+ work: !goalDoc && env.ELANOUS_POD_AUTHOR_ON_POD === '1' && !shard ? 'authoring' : (oomRetried ? retryTier : memoryTier) === 'lite' ? 'lite' : 'harness',
1840
+ };
1841
+ const job = podJobManifest({ name, namespace, image: jobImage, workIdentity, ...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}), repoUrl, ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), args: jobArgs, passEnv: jobPassEnv, deadlineSeconds: options.deadlineSeconds ?? POD_JOB_DEADLINE_SECONDS, ...(goalDoc ? { goalDoc } : env.ELANOUS_POD_AUTHOR_ON_POD === '1' && !shard ? { authorSentence: true, ...(env.ELANOUS_POD_AUTHOR_GRADE === 'lite' || env.ELANOUS_POD_AUTHOR_GRADE === 'full' ? { authorGrade: env.ELANOUS_POD_AUTHOR_GRADE } : {}) } : {}), runId: launchRunId, ...(parentRunId ? { parentRunId } : {}), ...(jobArmEnv ? { armEnv: jobArmEnv } : {}), hostId: resolveHostId(env), skillEnvs: Object.keys(skillEnvs), memoryLimit, memoryRequest, imageCommit: options.imageCommit !== undefined ? options.imageCommit : options.kubectl ? null : podImageFreshness({ image }).imageCommit, ...(grok ? { grokCredential: 'grokAuth' in creds && creds.grokAuth ? 'subscription' as const : 'api_key' as const } : {}), ...(codexAccounts ? { codexAccounts } : {}), ...(hostRefresh ? { appCredential: true } : {}), execution: { key: executionKey, attempt: oomRetried ? 2 : 1 }, hostLeaseAdmitted: !!releaseAdmission, ...(reviewerCredential ? { reviewerCodexAuth: true } : {}), ...(bedrockSpec ? { bedrock: bedrockSpec } : {}), ...(zaiSpec ? { zai: zaiSpec } : {}) }); // kubectl 주입(=시험)이면 docker 를 부르지 않는다
1736
1842
  const carriedBranch = goalDoc ? 'goal-doc' as const : env.ELANOUS_POD_AUTHOR_ON_POD === '1' && !shard ? 'author' as const : undefined;
1737
1843
  const carriedChildLlm = carriedBranch ? podDelegatedChildLlm(jobArgs) : undefined;
1738
1844
  const a = kubectl(['apply', '-f', '-'], JSON.stringify(job));
@@ -1793,6 +1899,10 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1793
1899
  let abortLogs = '';
1794
1900
  // ⭐ 런 «도중» 원장 증분 회수 — 호스트 슈퍼바이저가 Pod 걸음을 실시간으로 본다(🅣 요청 · 힐 루프 runtime 성형의 전제).
1795
1901
  const follower = createPodLedgerFollower({ runId: liveChildRunId, dir: ledgerDir, exec: (script) => kubectl(['-n', namespace, 'exec', `job/${name}`, '-c', 'child', '--', 'sh', '-c', script]) });
1902
+ // ⭐ METER-POD-ROLLUP-GAP-3 — 런 «도중» 마지막 PARTIAL 줄을 호스트가 쥔다: Pod 가 지워지면(SIGTERM 등) 종료 로그에서 PARTIAL 이 사라진다.
1903
+ let livePartialLine: string | null = null;
1904
+ let pollsSinceCapture = 0;
1905
+ const capturePolls = Math.max(1, options.usagePartialCapturePolls ?? Math.round(POD_USAGE_PARTIAL_CAPTURE_MS / Math.max(1, options.pollMs ?? 15_000)));
1796
1906
  for (;;) {
1797
1907
  if (input.signal?.aborted) {
1798
1908
  // METER-POD-ROLLUP-GAP — Job 삭제 «전»에 로그를 한 번 거둔다: PARTIAL 줄이 삭제와 함께 사라지면 사용량이 0 처럼 보인다.
@@ -1852,6 +1962,18 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1852
1962
  }
1853
1963
  }
1854
1964
  try { follower?.poll(); } catch (e) { debug.log('self-implement.pod', 'ledger-live-unavailable', { job: name, reason: e instanceof Error ? e.message : String(e) }); }
1965
+ if (++pollsSinceCapture >= capturePolls) {
1966
+ pollsSinceCapture = 0;
1967
+ try {
1968
+ const sampled = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child', `--since=${POD_USAGE_PARTIAL_CAPTURE_SINCE}`]);
1969
+ const seen = sampled.status === 0 ? lastPodUsagePartialLine(sampled.stdout) : null;
1970
+ // 창 안에 새 줄이 없으면 앞서 쥔 줄을 지킨다(덮어 지우지 않는다).
1971
+ if (seen) {
1972
+ livePartialLine = seen;
1973
+ debug.log('self-implement.pod', 'usage-partial-captured', { job: name, bytes: seen.length });
1974
+ }
1975
+ } catch (e) { debug.log('self-implement.pod', 'usage-partial-capture-failed', { job: name, reason: e instanceof Error ? e.message : String(e) }); }
1976
+ }
1855
1977
  await sleep(options.pollMs ?? 15_000);
1856
1978
  }
1857
1979
  let logs = '';
@@ -1891,7 +2013,9 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1891
2013
  // ⭐ 호스트 단가로 다시 매긴다(BACKLOG C1b) — Pod 엔 레지스트리 스냅숏이 없다.
1892
2014
  const { estimateLlmCost } = await import('../../budget/llm-cost.js');
1893
2015
  // METER-POD-ROLLUP-GAP — 최종 줄 → 마지막 PARTIAL 폴백 → 결손 행(measured:false · 종료 사유): 사용량이 0 처럼 보이는 침묵을 남기지 않는다.
1894
- reemitPodUsage(logs, name, undefined, (u) => estimateLlmCost(u) as { kind: string; usd?: number }, { reason: podUsageMissingReason({ failedReason, exitCode: containerExitCode, logsAvailable: Boolean(logs) }), runId: liveChildRunId });
2016
+ // METER-POD-ROLLUP-GAP-3 — 판정은 kubectl 없는 순수 함수(podUsageReemitPlan)가 하고 여기선 행을 내보내기만 한다(ux-sim 심이 같은 함수를 부른다).
2017
+ const usagePlan = podUsageReemitPlan({ job: name, runId: liveChildRunId, logs, livePartialLine, exit: { state, failedReason, containerReason, containerExitCode } }, (u) => estimateLlmCost(u) as { kind: string; usd?: number });
2018
+ for (const row of usagePlan.rows) debug.log(row.category, row.event, row.data);
1895
2019
  const parsed = parseSelfImplementJson(logs);
1896
2020
  const terminal = parseSelfImplementJson(logs.trimEnd().split('\n').at(-1) ?? '');
1897
2021
  const nextAccount = codexAccounts?.find((candidate) => candidate !== account);
@@ -1936,7 +2060,38 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1936
2060
  if (!taLandOwner) debug.log('self-implement.pod', 'ta-land-marker-ignored', { job: name, pr: prNumber ?? null,
1937
2061
  reason: unreadable !== null ? 'live-moves-unreadable' : 'propose-land-not-enabled', ...(unreadable !== null ? { error: unreadable } : {}) });
1938
2062
  }
2063
+ // REVIEW-ACP-POD — opt-in: 재게이트 «전»에 호스트 Claude ACP(구독) 리뷰. must-fix 면 병합하지 않고 PR 을 연 채 둔다.
2064
+ // ⛔ 못 쓰면(refused) 종전 길 그대로 — Pod 리뷰 결과로 재게이트한다(다른 공급자로 새지 않는다 · 관측 `acp-review-refused`).
2065
+ // ⛔ kubectl 주입(=시험)이면 사용자 설정을 읽지 않는다.
2066
+ let hostAcpMustFix: Extract<PodHostAcpReviewOutcome, { status: 'must-fix' }> | undefined;
2067
+ // REVIEW-ACP-POD ②-b — Pod 가 리뷰를 «미뤘다»면(mergeReason) 호스트 ACP 리뷰가 «유일한» 리뷰다:
2068
+ // 스위치가 그 사이 꺼졌어도 리뷰한다 · 못 하면(refused) 병합하지 않는다(fail-closed — 리뷰 없이 병합 0).
2069
+ const podReviewDeferred = disposition.mergeReason === REVIEW_DEFERRED_TO_HOST_MERGE_REASON;
2070
+ let hostAcpUnavailable: string | undefined;
2071
+ const hostAcpSwitch = resolvePodHostAcpReview(options.hostAcpReview, env, options.kubectl ? () => undefined : getUserConfig);
2072
+ if ((hostAcpSwitch.enabled || podReviewDeferred) && Number.isSafeInteger(prNumber) && prNumber && headCommit && /^[0-9a-f]{40}$/i.test(headCommit)) {
2073
+ const hostRoot = findGitDir(process.cwd())?.root;
2074
+ const outcome: PodHostAcpReviewOutcome = hostRoot
2075
+ ? await (options.podHostAcpReview ?? ((i) => runPodHostAcpReview(i, { env })))({ prNumber, headCommit, repoRoot: hostRoot, job: name })
2076
+ : { status: 'refused', reason: 'host repository unavailable' };
2077
+ if (outcome.status === 'refused' && !hostRoot) debug.log('self-implement.pod', 'acp-review-refused', { job: name, pr: prNumber, reason: outcome.reason }, { level: 'warn' });
2078
+ debug.log('self-implement.pod', 'host-acp-review-gate', { job: name, pr: prNumber, source: hostAcpSwitch.enabled ? hostAcpSwitch.source : 'pod-deferred', podReviewDeferred, status: outcome.status, ...(outcome.status === 'refused' ? { reason: outcome.reason, path: podReviewDeferred ? 'hold-pr' : 'pod-review' } : { mustFix: outcome.mustFix }) });
2079
+ if (outcome.status === 'must-fix') hostAcpMustFix = outcome;
2080
+ if (outcome.status === 'refused' && podReviewDeferred) hostAcpUnavailable = outcome.reason;
2081
+ }
1939
2082
  let regate: HostRegateResult;
2083
+ if (hostAcpUnavailable !== undefined) {
2084
+ // ⛔ Pod 안 리뷰가 없다 — 재게이트·병합으로 가면 «리뷰 없이 병합»이다. PR 을 연 채 둔다.
2085
+ debug.log('self-implement.pod', 'host-acp-review-unavailable', { job: name, pr: prNumber ?? null, head: headCommit ?? null, reason: hostAcpUnavailable }, { level: 'warn' });
2086
+ try { (options.ghComment ?? defaultGhComment)(prNumber!, `호스트 Claude ACP 리뷰를 못 했다(${hostAcpUnavailable.replace(/\s+/g, ' ').slice(0, 200)}) — Pod 안 리뷰는 호스트로 미뤄져 없으므로 자동 병합하지 않는다(REVIEW-ACP-POD ②-b).`); }
2087
+ catch (error) { debug.log('self-implement.pod', 'host-acp-review-comment-failed', { job: name, pr: prNumber ?? null, detail: (error instanceof Error ? error.message : String(error)).slice(0, 200) }); }
2088
+ disposition = { ...disposition, stage: 'pr-opened', merged: false, ok: false, mergeReason: 'host-acp-review-unavailable' };
2089
+ } else if (hostAcpMustFix) {
2090
+ const body = [`호스트 Claude ACP 리뷰: must-fix ${hostAcpMustFix.mustFix}건 — 자동 병합하지 않는다(REVIEW-ACP-POD).`, ...hostAcpMustFix.findings.map((f, i) => `${i + 1}. ${f.replace(/\s+/g, ' ').slice(0, 400)}`)].join('\n');
2091
+ try { (options.ghComment ?? defaultGhComment)(prNumber!, body); }
2092
+ catch (error) { debug.log('self-implement.pod', 'host-acp-review-comment-failed', { job: name, pr: prNumber ?? null, detail: (error instanceof Error ? error.message : String(error)).slice(0, 200) }); }
2093
+ disposition = { ...disposition, stage: 'pr-opened', merged: false, ok: false, mergeReason: 'host-acp-review-must-fix' };
2094
+ } else {
1940
2095
  if (!Number.isSafeInteger(prNumber) || !prNumber || !headCommit || !/^[0-9a-f]{40}$/i.test(headCommit)) {
1941
2096
  debug.log('harness.host-regate', 'unmeasured', { pr: prNumber ?? null, files: [], os: process.platform, failedStep: 'pod-result' });
1942
2097
  regate = { passed: false, failures: [{ step: 'pod-result', detail: 'missing PR number or checked head commit' }], os: process.platform };
@@ -1969,6 +2124,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1969
2124
  if (taLandOwner) debug.log('self-implement.pod', 'ta-land-owner', { job: name, pr: prNumber ?? null, head: headCommit ?? null, regatePassed: false });
1970
2125
  disposition = { ...disposition, stage: frozen || releaseHold ? 'pr-opened' : regate.passed ? 'merged' : 'host-regate-failed', merged: regate.passed && !frozen, hostRegate: regate, ok: regate.passed || releaseHold || frozen };
1971
2126
  }
2127
+ }
1972
2128
  }
1973
2129
  const childFailure = state === 'failed' && !oomKilled && failedReason !== 'DeadlineExceeded'
1974
2130
  ? lastPodChildFailure(logs) : null;
@@ -2220,18 +2376,34 @@ export function podUsageMissingReason(input: { logsAvailable: boolean; exitCode?
2220
2376
  return 'stopped';
2221
2377
  }
2222
2378
 
2223
- export function reemitPodUsage(logs: string, job: string, log: (category: string, event: string, data: Record<string, unknown>) => void = (c, e, d) => debug.log(c, e, d), reprice?: PodRowReprice, missing?: { reason: PodUsageMissingReason; runId?: string | null }): number {
2379
+ const POD_USAGE_PARTIAL_PREFIX = 'ELANOUS_USAGE_ROLLUP_PARTIAL ';
2380
+
2381
+ /** METER-POD-ROLLUP-GAP-3 — 로그 덩어리에서 «마지막» PARTIAL 줄(없으면 null). 런 도중 표본과 종료 로그가 같은 판정을 쓴다. */
2382
+ export function lastPodUsagePartialLine(logs: string): string | null {
2383
+ return logs.split('\n').reverse().find((l) => l.startsWith(POD_USAGE_PARTIAL_PREFIX)) ?? null;
2384
+ }
2385
+
2386
+ /** METER-POD-ROLLUP-GAP-3 — 호스트가 런 «도중» 거두는 PARTIAL 표본 간격(Pod 표본기 기본 5분과 맞춘다) ⊕ 그때 읽는 로그 창(표본 간격 둘 ⊕ 여유). */
2387
+ export const POD_USAGE_PARTIAL_CAPTURE_MS = 5 * 60_000;
2388
+ export const POD_USAGE_PARTIAL_CAPTURE_SINCE = '11m';
2389
+
2390
+ export function reemitPodUsage(logs: string, job: string, log: (category: string, event: string, data: Record<string, unknown>) => void = (c, e, d) => debug.log(c, e, d), reprice?: PodRowReprice, missing?: { reason: PodUsageMissingReason; runId?: string | null; podExitClass?: PodExitClass | null; livePartialLine?: string | null }): number {
2224
2391
  const lines = logs.split('\n').reverse();
2225
2392
  const line = lines.find((l) => l.startsWith('ELANOUS_USAGE_ROLLUP '));
2226
2393
  // ⭐ METER-POD-ROLLUP-GAP — 최종 줄이 없으면 마지막 PARTIAL 줄로 폴백한다(부분 롤업 표본기가 남긴 줄).
2227
- const partialLine = line ? null : lines.find((l) => l.startsWith('ELANOUS_USAGE_ROLLUP_PARTIAL '));
2394
+ // ⭐ METER-POD-ROLLUP-GAP-3 — 종료 로그에도 PARTIAL 이 없으면(Pod 가 지워져 로그가 사라졌다) 런 «도중» 호스트가 거둔 마지막 PARTIAL 로.
2395
+ const logPartial = line ? null : lastPodUsagePartialLine(logs);
2396
+ const livePartial = line || logPartial || !missing?.livePartialLine?.startsWith(POD_USAGE_PARTIAL_PREFIX) ? null : missing.livePartialLine;
2397
+ const partialLine = logPartial ?? livePartial;
2228
2398
  if (!line && !partialLine) {
2229
- log('self-implement.pod', 'usage-rollup-missing', { job });
2399
+ // ⭐ METER-POD-ROLLUP-GAP-3 — 결손 이벤트에도 종료 사유를 싣는다(옛 줄은 {job} 뿐이라 «왜 없나» 를 못 물었다).
2400
+ const why = missing ? { reason: missing.reason, ...(missing.podExitClass ? { podExitClass: missing.podExitClass } : {}), ...(missing.runId ? { runId: missing.runId } : {}) } : {};
2401
+ log('self-implement.pod', 'usage-rollup-missing', { job, ...why });
2230
2402
  // ⭐ 결손 행 — «측정 불가» 를 한 줄로 남긴다: 0 처럼 보이지 않게.
2231
- if (missing) log('llm.usage', 'llm-usage', { site: 'pod-rollup:missing', measured: false, reason: missing.reason, job, ...(missing.runId ? { runId: missing.runId } : {}), substrate: 'pod', podRollupKey: `${missing.runId ?? job}|missing` });
2403
+ if (missing) log('llm.usage', 'llm-usage', { site: 'pod-rollup:missing', measured: false, ...why, job, substrate: 'pod', podRollupKey: `${missing.runId ?? job}|missing` });
2232
2404
  return 0;
2233
2405
  }
2234
- const prefix = line ? 'ELANOUS_USAGE_ROLLUP ' : 'ELANOUS_USAGE_ROLLUP_PARTIAL ';
2406
+ const prefix = line ? 'ELANOUS_USAGE_ROLLUP ' : POD_USAGE_PARTIAL_PREFIX;
2235
2407
  let parsed: { measured?: boolean; truncated?: boolean; runId?: string | null; armId?: string | null; podName?: string | null; nodeName?: string | null; hostId?: string | null; seq?: number; at?: string; rows?: Array<Record<string, unknown>> };
2236
2408
  try { parsed = JSON.parse((line ?? partialLine)!.slice(prefix.length)); } catch { log('self-implement.pod', 'usage-rollup-unparsable', { job }); return 0; }
2237
2409
  const rows = parsed.rows ?? [];
@@ -2249,16 +2421,51 @@ export function reemitPodUsage(logs: string, job: string, log: (category: string
2249
2421
  substrate: 'pod', job, ...(parsed.runId ? { podRunId: parsed.runId } : {}), ...(parsed.armId ? { armId: parsed.armId } : {}),
2250
2422
  // ⭐ MF-3c0d253e — 재방출 행의 downstream dedup 키: 같은 Pod(job·runId)의 같은 버킷(site·provider·model)은
2251
2423
  // 부분(seq 달라도)·최종·abort⊕resume 재방출이 몇 번 만나도 집계(rollup)에서 한 번만 센다. 키 없는 기존 행은 종전대로.
2252
- podRollupKey: `${job}|${parsed.runId ?? ''}|pod-rollup:${String(r.site)}|${String(r.provider)}|${String(r.model)}`,
2424
+ // ⭐ METER-POD-ROLLUP-GAP-2 — podName 을 키에 넣는다: gh-login·usage-limit 재시도는 «같은 job 이름·runId» 로 새 Pod 를 띄우므로
2425
+ // (podJobName 은 spaceId 결정적) 그것 없이는 서로 다른 시도의 사용량이 한 번으로 접혀 앞 시도분이 사라진다.
2426
+ podRollupKey: `${job}|${parsed.podName ?? ''}|${parsed.runId ?? ''}|pod-rollup:${String(r.site)}|${String(r.provider)}|${String(r.model)}`,
2253
2427
  ...(parsed.podName ? { podName: parsed.podName } : {}), ...(parsed.nodeName ? { nodeName: parsed.nodeName } : {}), ...(parsed.hostId ? { podHostId: parsed.hostId } : {}),
2254
2428
  // ⭐ PARTIAL 폴백 재방출 꼬리표 — 최종 줄 행은 그대로(부분이 아님을 꾸미지 않는다).
2255
- ...(partialLine ? { partial: true, ...(parsed.seq !== undefined ? { partialSeq: parsed.seq } : {}), ...(parsed.at !== undefined ? { partialAt: parsed.at } : {}) } : {}),
2429
+ ...(partialLine ? { partial: true, ...(parsed.seq !== undefined ? { partialSeq: parsed.seq } : {}), ...(parsed.at !== undefined ? { partialAt: parsed.at } : {}), ...(livePartial ? { partialSource: 'live-capture' } : {}) } : {}),
2256
2430
  });
2257
2431
  }
2258
- log('self-implement.pod', 'usage-rollup', { job, rows: rows.length, measured: parsed.measured ?? null, truncated: parsed.truncated ?? null, ...(partialLine ? { partial: true, ...(parsed.seq !== undefined ? { seq: parsed.seq } : {}), ...(parsed.at !== undefined ? { at: parsed.at } : {}) } : {}) });
2432
+ log('self-implement.pod', 'usage-rollup', { job, rows: rows.length, measured: parsed.measured ?? null, truncated: parsed.truncated ?? null, ...(partialLine ? { partial: true, ...(parsed.seq !== undefined ? { seq: parsed.seq } : {}), ...(parsed.at !== undefined ? { at: parsed.at } : {}), ...(livePartial ? { partialSource: 'live-capture' } : {}) } : {}) });
2259
2433
  return rows.length;
2260
2434
  }
2261
2435
 
2436
+ /** METER-POD-ROLLUP-GAP-3 — 호스트 사용량 재방출 판정의 «순수» 입력·출력(kubectl·debug 없음). */
2437
+ export interface PodUsageReemitInput {
2438
+ job: string;
2439
+ runId?: string | null;
2440
+ /** Job 이 끝난 뒤 거둔 로그(Pod 가 사라졌으면 ''). */
2441
+ logs: string;
2442
+ /** 런 «도중» 호스트가 본 마지막 `ELANOUS_USAGE_ROLLUP_PARTIAL` 줄(없으면 null). */
2443
+ livePartialLine?: string | null;
2444
+ /** 종료 정보 — state 가 'failed' 일 때만 classifyPodExit 분류를 싣는다. */
2445
+ exit: { state: 'complete' | 'failed' | 'aborted'; failedReason?: string | null; containerReason?: string | null; containerExitCode?: number | null };
2446
+ }
2447
+ export interface PodUsageReemitPlan {
2448
+ /** 어느 줄로 재방출했나 — final(최종 줄) · partial-log(끝 로그의 PARTIAL) · partial-live(런 도중 본 PARTIAL) · missing(결손 행) · unparsable. */
2449
+ source: 'final' | 'partial-log' | 'partial-live' | 'missing' | 'unparsable';
2450
+ /** 그대로 debug.log(category, event, data) 로 내보낼 행들(llm-usage 행 ⊕ self-implement.pod 요약/결손 이벤트). */
2451
+ rows: Array<{ category: string; event: string; data: Record<string, unknown> }>;
2452
+ }
2453
+
2454
+ /** METER-POD-ROLLUP-GAP-3 — 끝 로그 ⊕ 런 도중 PARTIAL ⊕ 종료 정보 → 재방출할 행/결손 행. 호스트 Job 경로와 ux-sim 심이 «같은» 함수를 부른다. */
2455
+ export function podUsageReemitPlan(input: PodUsageReemitInput, reprice?: PodRowReprice): PodUsageReemitPlan {
2456
+ const { job, logs, exit } = input;
2457
+ const reason = podUsageMissingReason({ failedReason: exit.failedReason ?? undefined, exitCode: exit.containerExitCode ?? null, logsAvailable: Boolean(logs) });
2458
+ const podExitClass = exit.state === 'failed' ? classifyPodExit({ containerReason: exit.containerReason ?? null, containerExitCode: exit.containerExitCode ?? null, jobReason: exit.failedReason || null, logs }).class : null;
2459
+ const rows: PodUsageReemitPlan['rows'] = [];
2460
+ reemitPodUsage(logs, job, (category, event, data) => rows.push({ category, event, data }), reprice, { reason, runId: input.runId ?? null, podExitClass, livePartialLine: input.livePartialLine ?? null });
2461
+ const usage = rows.find((r) => r.category === 'llm.usage');
2462
+ const source: PodUsageReemitPlan['source'] = rows.some((r) => r.event === 'usage-rollup-missing') ? 'missing'
2463
+ : rows.some((r) => r.event === 'usage-rollup-unparsable') ? 'unparsable'
2464
+ : rows.find((r) => r.event === 'usage-rollup')?.data.partialSource === 'live-capture' ? 'partial-live'
2465
+ : rows.find((r) => r.event === 'usage-rollup')?.data.partial === true || usage?.data.partial === true ? 'partial-log' : 'final';
2466
+ return { source, rows };
2467
+ }
2468
+
2262
2469
  /** 이 기계가 Pod 칸을 쓸 수 있나(클러스터 · 이미지) — 발사 전 한 번. */
2263
2470
  export function podSubstrateReady(kubectl: Kubectl = defaultKubectl, image = 'elanous-harness:local'): { ok: boolean; reason: string } {
2264
2471
  const ctx = kubectl(['config', 'current-context']);
@@ -200,6 +200,9 @@ export interface LLMConfig {
200
200
  * 이 축은 «같은 provider 안에서 어느 계정의 토큰을 쓸지»를 바꾼다.
201
201
  * 리셋 크레딧 자동 소비는 별도 일일 상한으로 제한한다. */
202
202
  codexAccountRotation?: boolean;
203
+ /** REVIEW-ACP-POD — Pod merge-ready PR 을 병합 전에 호스트 Claude ACP(구독)로 리뷰한다. `true` 일 때만 켜진다(기본 꺼짐 = 종전).
204
+ * env `ELANOUS_POD_HOST_ACP_REVIEW` 가 이 값보다 앞선다. ACP 를 못 쓰면 종전 길(Pod 리뷰 → 재게이트). */
205
+ podHostAcpReview?: boolean;
203
206
  /** ⭐⭐ codex 계정 «알림» — 회전·리셋크레딧 소비를 텔레그램 등 outbound 로 보낼지.
204
207
  * ⛔ **기본 ON** — `false` 일 때만 조용해진다.
205
208
  * ⛔⭐ 위 `codexAccountRotation` 과 «다른 축»이다(대표 지시 2026-08-17 *"회전을 끄라는 게
@@ -3829,7 +3832,7 @@ export interface UserConfig {
3829
3832
  guardian?: { mode?: 'shadow' | 'live'; /** Orphan CLI GC on the guardian tick: off = no ps collection, shadow (default) = evidence only, on = evidence then SIGTERM. */ orphanGc?: 'off' | 'shadow' | 'on' };
3830
3833
  /** TA-JUDGE-LIVE-SAFE: task-agent judge moves executed for real. Only `review` · `propose-green` are honoured
3831
3834
  * (`src/task-agent/live-moves.ts` drops anything else with a warning). Absent = env ELANOUS_TASK_AGENT_LIVE_MOVES, else none (pure shadow). */
3832
- taskAgent?: { liveMoves?: string[]; parentHost?: { host?: string; cwd?: string; elanous?: string; configDir?: string; podPool?: string; approvalCapacity?: number } | Array<{ host?: string; cwd?: string; elanous?: string; configDir?: string; podPool?: string; approvalCapacity?: number }> };
3835
+ taskAgent?: { liveMoves?: string[]; /** TA-REJUDGE-PERIODIC — steward tick runs `tasks rejudge --all` every N minutes (absent/0 = off). */ rejudgeEveryMinutes?: number; /** 1-minute load average above which that tick is skipped (default 60). */ rejudgeMaxLoad?: number; parentHost?: { host?: string; cwd?: string; elanous?: string; configDir?: string; podPool?: string; approvalCapacity?: number } | Array<{ host?: string; cwd?: string; elanous?: string; configDir?: string; podPool?: string; approvalCapacity?: number }> };
3833
3836
  events?: EventsConfig;
3834
3837
  /** GATE-REMOTE — see GateRemoteConfig. Absent = defaults (auto on · node-b · load 20 · cap 2). */
3835
3838
  gateRemote?: GateRemoteConfig;
@@ -4140,15 +4143,24 @@ function parseTaskAgentConfig(raw: unknown): UserConfig['taskAgent'] {
4140
4143
  return undefined;
4141
4144
  }
4142
4145
  const parentHost = parseTaskAgentParentHost((raw as Record<string, unknown>).parentHost);
4146
+ // TA-REJUDGE-PERIODIC — 음이 아닌 유한수만 산다(0 = 끔). 그 밖은 경고하고 버린다(= 끔 · 기본 부하 상한).
4147
+ const rejudge: { rejudgeEveryMinutes?: number; rejudgeMaxLoad?: number } = {};
4148
+ for (const key of ['rejudgeEveryMinutes', 'rejudgeMaxLoad'] as const) {
4149
+ const value = (raw as Record<string, unknown>)[key];
4150
+ if (value === undefined) continue;
4151
+ if (typeof value === 'number' && Number.isFinite(value) && value >= 0) rejudge[key] = value;
4152
+ else warnUserConfigDrop(`taskAgent.${key}`, `음이 아닌 수가 아니다(${JSON.stringify(value)}) — 버림`);
4153
+ }
4154
+ const extras = { ...rejudge, ...(parentHost ? { parentHost } : {}) };
4143
4155
  const liveMoves = (raw as Record<string, unknown>).liveMoves;
4144
- if (liveMoves === undefined) return parentHost ? { parentHost } : undefined;
4156
+ if (liveMoves === undefined) return Object.keys(extras).length ? extras : undefined;
4145
4157
  // 설정이 «있으면» 환경 변수로 내려가지 않는다 — 배열이 아니면 빈 목록(fail-closed), 문자열 밖 항목은 글자로 바꿔 넘겨
4146
4158
  // 실행부가 «모르는 항목»으로 경고하고 버리게 한다(유효한 항목은 산다).
4147
4159
  if (!Array.isArray(liveMoves)) {
4148
4160
  warnUserConfigDrop('taskAgent.liveMoves', '배열이 아니다 — 빈 목록(실행 0)');
4149
- return { liveMoves: [], ...(parentHost ? { parentHost } : {}) };
4161
+ return { liveMoves: [], ...extras };
4150
4162
  }
4151
- return { liveMoves: liveMoves.map((entry) => typeof entry === 'string' ? entry : JSON.stringify(entry) ?? String(entry)), ...(parentHost ? { parentHost } : {}) };
4163
+ return { liveMoves: liveMoves.map((entry) => typeof entry === 'string' ? entry : JSON.stringify(entry) ?? String(entry)), ...extras };
4152
4164
  }
4153
4165
 
4154
4166
  function parseGuardianConfig(raw: unknown): UserConfig['guardian'] {
@@ -5240,6 +5252,7 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
5240
5252
  goalLoop: parseGoalLoop(llm.goalLoop),
5241
5253
  memoryJudge: parseMemoryJudge(llm.memoryJudge),
5242
5254
  codexInspectExempt: llm.codexInspectExempt === true ? true : undefined,
5255
+ podHostAcpReview: llm.podHostAcpReview === true ? true : undefined,
5243
5256
  // ⛔⭐ 「false 만 끈다」 — 미설정·true 는 undefined 로 두어 기본 ON 을 유지한다(대표 결정 ②).
5244
5257
  // ⚠️ 이 줄이 «없으면» 타입만 있고 파서가 안 읽어 ***노브가 no-op 이 된다***(실측으로 잡았다).
5245
5258
  codexAccountRotation: llm.codexAccountRotation === false ? false : undefined,
@@ -6550,6 +6563,7 @@ export function saveUserConfig(
6550
6563
  goalLoop: cfg.llm.goalLoop,
6551
6564
  memoryJudge: cfg.llm.memoryJudge,
6552
6565
  codexInspectExempt: cfg.llm.codexInspectExempt,
6566
+ podHostAcpReview: cfg.llm.podHostAcpReview,
6553
6567
  codexAccountRotation: cfg.llm.codexAccountRotation,
6554
6568
  codexAccountAlerts: cfg.llm.codexAccountAlerts,
6555
6569
  codexAccountRotationThresholdPercent: cfg.llm.codexAccountRotationThresholdPercent,