elanous 0.2.23 → 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 (688) 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-ad3bd8084048bee4.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-a648bc464c9dc754.js → page-dea4b795741126fd.js} +1 -1
  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-48fb31810693c357.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-cb154acadb025414.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/css/72becfd42807b50d.css +1 -0
  183. package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → dRS6lEhSRRBr1abbzp7fJ}/_buildManifest.js +1 -1
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +23 -23
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +23 -23
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +23 -23
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +22 -22
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +22 -22
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +23 -23
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +22 -22
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +23 -23
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +23 -23
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +22 -22
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +23 -23
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +23 -23
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +23 -23
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +23 -23
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +22 -22
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +22 -22
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +23 -23
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +23 -23
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +23 -23
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +22 -22
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +22 -22
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +23 -23
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +23 -23
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +22 -22
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +22 -22
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +22 -22
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +23 -23
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +23 -23
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +22 -22
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +23 -23
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +23 -23
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +23 -23
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +23 -23
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +23 -23
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +22 -22
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +23 -23
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +23 -23
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +23 -23
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +23 -23
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +23 -23
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +23 -23
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +23 -23
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +23 -23
  277. package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
  278. package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
  279. package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
  280. package/catalog/providers/openrouter.yaml +2 -0
  281. package/graphs/implement-loop.yaml +31 -0
  282. package/graphs/ops/harness-gc.yaml +17 -0
  283. package/graphs/ops/recipes.yaml +3 -0
  284. package/graphs/overlays/README.md +1 -1
  285. package/graphs/overlays/stop-heal-ladder.yaml +105 -0
  286. package/graphs/release/release-loop.yaml +5 -5
  287. package/graphs/steward/recipes.yaml +4 -0
  288. package/graphs/steward/steward.yaml +10 -1
  289. package/package.json +1 -1
  290. package/scripts/add-api-key.sh +1 -1
  291. package/scripts/bench-report.ts +46 -1
  292. package/scripts/ci-typecheck-changed.ts +73 -14
  293. package/scripts/fleet/bedrock-pod-secret.ts +122 -0
  294. package/scripts/fleet/node-setup-linux.sh +97 -0
  295. package/scripts/fleet/node-setup.sh +11 -0
  296. package/scripts/fleet/zai-pod-secret.ts +86 -0
  297. package/scripts/land-global-checks.ts +3 -0
  298. package/scripts/measure-log-diet-2.ts +213 -0
  299. package/scripts/measure-tsc-affected-roots.ts +289 -0
  300. package/scripts/release-loop/auto-approve-node.ts +6 -0
  301. package/scripts/release-loop/gate-closure.ts +286 -0
  302. package/scripts/release-loop/gate-executor.ts +28 -0
  303. package/scripts/release-loop/gate-node.ts +333 -37
  304. package/scripts/release-loop/gate-partial.ts +34 -6
  305. package/scripts/release-loop/ops-upgrade-node.ts +63 -42
  306. package/scripts/release-loop/publish-node.ts +6 -0
  307. package/scripts/release-loop/resume-release.ts +46 -13
  308. package/scripts/release-loop/resume.ts +110 -4
  309. package/scripts/release-loop/unattended-release.ts +22 -7
  310. package/scripts/tsc-baseline-cache.ts +172 -0
  311. package/scripts/usage-rollup.ts +72 -6
  312. package/scripts/ux-sim.ts +30 -1
  313. package/skills/youtube-master/scripts/main.ts +4 -1
  314. package/skills/youtube-master/src/obsidian.ts +9 -0
  315. package/src/agent/run-context.ts +10 -0
  316. package/src/agent-mission/driver.ts +18 -3
  317. package/src/agent-mission/resource-ladder.ts +8 -3
  318. package/src/agent-mission/review-loop.ts +8 -2
  319. package/src/agent-substrate/acp-implementer.ts +146 -0
  320. package/src/agent-substrate/pr-reviewer.ts +60 -13
  321. package/src/agent-substrate/self-review-cli.ts +170 -15
  322. package/src/autopilot/mission-critique.ts +18 -5
  323. package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
  324. package/src/autopilot/mission-trace.ts +12 -1
  325. package/src/autopilot/system-lookback-run.ts +16 -10
  326. package/src/bench/bench.ts +183 -0
  327. package/src/budget/cost-tier-advisor.ts +91 -0
  328. package/src/budget/fetchers/grok.ts +15 -5
  329. package/src/budget/llm-cost.ts +37 -5
  330. package/src/budget/shadow-arms.ts +77 -0
  331. package/src/budget/types.ts +10 -2
  332. package/src/budget/unified-usage.ts +256 -10
  333. package/src/cli/bench-cli.ts +34 -0
  334. package/src/cli/doctor-cli.ts +21 -0
  335. package/src/cli/friendly-errors.ts +113 -0
  336. package/src/cli/guardian-cli.ts +26 -1
  337. package/src/cli/image-cli.ts +101 -0
  338. package/src/cli/intake-cli.ts +3 -1
  339. package/src/cli/log-event-names.ts +4 -0
  340. package/src/cli/memory-cli.ts +182 -0
  341. package/src/cli/model-watch-cli.ts +4 -1
  342. package/src/cli/pr-cli.ts +62 -5
  343. package/src/cli/pr-land-overlap-evidence.ts +160 -12
  344. package/src/cli/pr-land-pod-shadow.ts +54 -0
  345. package/src/cli/release-cli.ts +27 -16
  346. package/src/cli/release-run-if-ready.ts +11 -0
  347. package/src/cli/resource-cli.ts +48 -0
  348. package/src/cli/retro-cli.ts +12 -3
  349. package/src/cli/rfc-status.ts +52 -2
  350. package/src/cli/seat-requests-cli.ts +25 -0
  351. package/src/cli/self-update.ts +104 -0
  352. package/src/cli/tasks-cli.ts +139 -10
  353. package/src/cli/usage-cli.ts +93 -8
  354. package/src/compact/verify-probe.ts +23 -3
  355. package/src/context-card/index.ts +50 -0
  356. package/src/control/control-status.ts +30 -1
  357. package/src/core-turn/run-goal-loop.ts +5 -4
  358. package/src/dashboard/ad-run-setup-bindings.ts +279 -0
  359. package/src/dashboard/index.ts +18 -276
  360. package/src/dashboard/slash-runtime/dashboard-handlers.ts +4 -138
  361. package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
  362. package/src/dashboard/stale-install-check.ts +11 -0
  363. package/src/debug/log-diet.ts +53 -10
  364. package/src/debug/log.ts +19 -1
  365. package/src/domains/morning-essential.ts +18 -3
  366. package/src/domains/release-tool.ts +43 -0
  367. package/src/error-report/report.ts +21 -4
  368. package/src/execution-loop/launch-gate.ts +158 -2
  369. package/src/fleet/host-doctor.ts +375 -0
  370. package/src/github/pr-labels.ts +1 -0
  371. package/src/goals/judge.ts +20 -6
  372. package/src/graph-runner/graph-cli.ts +42 -1
  373. package/src/graph-runner/runner.ts +176 -11
  374. package/src/graph-wizard/archetypes.ts +14 -8
  375. package/src/graph-wizard/generate.ts +77 -1
  376. package/src/grok/usage.ts +23 -2
  377. package/src/grok.ts +13 -7
  378. package/src/grounding/ref-index.ts +253 -0
  379. package/src/harness/dispatch-backpressure.ts +10 -2
  380. package/src/harness/harness-clean.ts +199 -78
  381. package/src/harness/harness-cli-command.ts +176 -52
  382. package/src/harness/harness-gc.ts +331 -0
  383. package/src/harness/harness-stop.ts +82 -10
  384. package/src/harness/harness-substrate-default.ts +142 -7
  385. package/src/harness/launch-registry.ts +6 -0
  386. package/src/harness/worktree-branch-prefix.ts +9 -0
  387. package/src/hq/fence.ts +187 -0
  388. package/src/hq/seats.ts +38 -22
  389. package/src/images/image-ledger.ts +179 -0
  390. package/src/index.ts +110 -186
  391. package/src/instance/child-scope.ts +32 -1
  392. package/src/instance/dev-project.ts +133 -0
  393. package/src/instance/resolve.ts +24 -0
  394. package/src/instance/spawn-elanous.ts +45 -0
  395. package/src/intake-plane/collect-github.ts +7 -2
  396. package/src/intake-plane/lens.ts +46 -4
  397. package/src/intake-plane/ref-prefetch.ts +110 -0
  398. package/src/intake-plane/requirement-funnel.ts +53 -1
  399. package/src/intelligence-map/catalog-feed.ts +119 -0
  400. package/src/intelligence-map/model-catalog.ts +72 -0
  401. package/src/intelligence-map/model-watch-intake.ts +40 -0
  402. package/src/intelligence-map/model-watch-mission.ts +14 -1
  403. package/src/llm/bedrock-eventstream.ts +215 -0
  404. package/src/llm/bedrock-provider.ts +114 -41
  405. package/src/llm/bedrock.ts +174 -28
  406. package/src/llm/open-weight-discipline.ts +21 -0
  407. package/src/llm/openrouter-byok-cost.ts +96 -0
  408. package/src/llm/openrouter-deepseek.ts +151 -0
  409. package/src/llm/openrouter-upstream-pins.config.ts +25 -0
  410. package/src/llm/zai-coding-plan.ts +700 -0
  411. package/src/llm.ts +91 -24
  412. package/src/loops/checker.ts +148 -9
  413. package/src/loops/orchestrator/resync-shadow.ts +34 -7
  414. package/src/maturity/feature-maturity.ts +3 -3
  415. package/src/model-tier/llm-tier-map.ts +9 -5
  416. package/src/models/prompts.ts +2 -1
  417. package/src/mss/logging/log-store.ts +58 -11
  418. package/src/nexus/api/http-server.ts +22 -0
  419. package/src/nexus/api/missions.ts +73 -2
  420. package/src/nexus/api/ops-api.ts +18 -0
  421. package/src/nexus/index.ts +7 -75
  422. package/src/nexus/tools-kind.ts +78 -0
  423. package/src/oauth/codex-account-rotation.ts +43 -3
  424. package/src/oauth/codex-account-store.ts +339 -27
  425. package/src/oauth/codex-quota-policy.ts +33 -4
  426. package/src/oauth/fallback-chain.ts +53 -15
  427. package/src/onboarding/first-run.ts +37 -18
  428. package/src/onboarding/web-first.ts +20 -2
  429. package/src/ops/machine-heartbeat.ts +185 -0
  430. package/src/ops/overview-cache.ts +175 -0
  431. package/src/ops/overview.ts +8 -0
  432. package/src/preview/terminal.ts +15 -5
  433. package/src/project/project-store.ts +20 -0
  434. package/src/prompt-cache/openai.ts +3 -0
  435. package/src/prompt-cache/types.ts +5 -0
  436. package/src/prompt-enhance/enhance.ts +23 -0
  437. package/src/release-loop/auto-start.ts +7 -5
  438. package/src/release-loop/checklist.ts +11 -1
  439. package/src/release-loop/gate-shards.ts +4 -0
  440. package/src/release-loop/light-rc.ts +84 -13
  441. package/src/release-loop/merged-pr-checklist.ts +35 -5
  442. package/src/release-loop/placement.ts +16 -1
  443. package/src/release-loop/rehearsal.ts +1 -1
  444. package/src/requirements/requirement-ledger.ts +536 -0
  445. package/src/retro/daily.ts +5 -5
  446. package/src/seat-loop/duty-ledger.ts +64 -0
  447. package/src/seat-loop/seat-loop.ts +32 -10
  448. package/src/self-dev/decompose.ts +37 -3
  449. package/src/self-dev/dev-cli.ts +44 -10
  450. package/src/self-dev/dev-pipeline.ts +39 -9
  451. package/src/self-dev/draft-residue.ts +27 -5
  452. package/src/self-dev/draft-sweep.ts +151 -0
  453. package/src/self-dev/fabric-decompose-adapter.ts +9 -2
  454. package/src/self-dev/graph-journey-route.ts +6 -0
  455. package/src/self-dev/orchestrate-cli.ts +25 -3
  456. package/src/self-dev/orchestrate.ts +41 -6
  457. package/src/self-dev/run-supervisor.ts +218 -15
  458. package/src/self-dev/run-types.ts +13 -0
  459. package/src/self-dev/supervisor-verdict-edges.ts +1 -0
  460. package/src/self-implement/budget-gate.ts +53 -13
  461. package/src/self-implement/child-context-composition.ts +139 -0
  462. package/src/self-implement/child-llm-preference.ts +13 -5
  463. package/src/self-implement/claude-acp-implement.ts +67 -0
  464. package/src/self-implement/flex-signals.ts +59 -0
  465. package/src/self-implement/frozen-merges.ts +8 -3
  466. package/src/self-implement/gate-cli.ts +29 -10
  467. package/src/self-implement/gate-remote.ts +4 -1
  468. package/src/self-implement/goal-author-decompose.ts +10 -2
  469. package/src/self-implement/goal-author.ts +36 -11
  470. package/src/self-implement/goal-new-paths.ts +42 -0
  471. package/src/self-implement/graph-overlay-condition.ts +28 -0
  472. package/src/self-implement/graph-overlay-yaml.ts +41 -7
  473. package/src/self-implement/graph-templates.ts +33 -1
  474. package/src/self-implement/graph-yaml.ts +56 -0
  475. package/src/self-implement/heal-intake.ts +5 -1
  476. package/src/self-implement/host-regate.ts +124 -30
  477. package/src/self-implement/importer-test-index.ts +3 -1
  478. package/src/self-implement/l8-merge-queue.ts +80 -2
  479. package/src/self-implement/merge-train.ts +19 -0
  480. package/src/self-implement/off-diff-evidence.ts +40 -1
  481. package/src/self-implement/orchestrator.ts +230 -32
  482. package/src/self-implement/premise-review.ts +159 -0
  483. package/src/self-implement/regate-detail.ts +79 -0
  484. package/src/self-implement/review-deferred-to-host.ts +21 -0
  485. package/src/self-implement/rework-budget-judgment.ts +23 -3
  486. package/src/self-implement/running-runs.ts +75 -5
  487. package/src/self-implement/scope-adjacency.ts +23 -0
  488. package/src/self-implement/seams.ts +89 -8
  489. package/src/self-implement/self-implement-cli.ts +9 -4
  490. package/src/self-implement/stop-autoheal.ts +69 -2
  491. package/src/session-runtime/retry-policy.ts +2 -1
  492. package/src/skills/tools/agent.ts +16 -1
  493. package/src/skills/tools/persistent-grounding.ts +11 -1
  494. package/src/skills/tools/shell.ts +33 -1
  495. package/src/steward/launch.ts +5 -4
  496. package/src/steward/rejudge-tick.ts +142 -0
  497. package/src/steward/triage-budget.ts +62 -0
  498. package/src/steward/triage.ts +83 -22
  499. package/src/task-agent/actions.ts +62 -5
  500. package/src/task-agent/board.ts +92 -3
  501. package/src/task-agent/card-evidence.ts +88 -1
  502. package/src/task-agent/completion-evidence.ts +5 -0
  503. package/src/task-agent/cover.ts +166 -3
  504. package/src/task-agent/judge.ts +16 -0
  505. package/src/task-agent/land-order-ledger.ts +95 -0
  506. package/src/task-agent/live-move-history.ts +87 -1
  507. package/src/task-agent/live-moves.ts +350 -20
  508. package/src/task-agent/parent-host.ts +27 -3
  509. package/src/task-agent/rejudge-on-head.ts +223 -24
  510. package/src/task-agent/review-prior-fix.ts +146 -0
  511. package/src/task-agent/review-result-capture.ts +3 -1
  512. package/src/task-agent/run-adopt.ts +136 -0
  513. package/src/task-agent/shadow.ts +65 -9
  514. package/src/task-agent/task-hand.ts +57 -7
  515. package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
  516. package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
  517. package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
  518. package/src/task-orchestrator/surfaces/pod-child-providers.ts +14 -1
  519. package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -0
  520. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +79 -6
  521. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +122 -0
  522. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -5
  523. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
  524. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +23 -0
  525. package/src/task-orchestrator/surfaces/pod-pool.ts +73 -4
  526. package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
  527. package/src/task-orchestrator/surfaces/self-implement-pod.ts +432 -35
  528. package/src/task-orchestrator/surfaces/self-implement.ts +19 -1
  529. package/src/typecheck-ratchet.ts +1 -0
  530. package/src/user-config.ts +69 -15
  531. package/src/ux-sim/fault-cred-expiry.ts +100 -0
  532. package/src/ux-sim/fault-pod-death.ts +74 -0
  533. package/src/ux-sim/fault-pool-cap.ts +81 -0
  534. package/src/version/packed-revision.json +1 -1
  535. package/src/webclone/qa-table.ts +22 -0
  536. package/src/workflow-runtime/triggers/registry.ts +59 -0
  537. package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
  538. package/apps/pwa/out/_next/static/chunks/0a09e062-34f747a17d8d8c2e.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +0 -77
  540. package/apps/pwa/out/_next/static/chunks/1325-dc3f3c21eb181cb4.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +0 -34
  542. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +0 -24
  543. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/1669-da843ed73aa301f5.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +0 -36
  553. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +0 -122
  554. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +0 -62
  556. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +0 -149
  563. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +0 -309
  567. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/5313.1697309c532b9856.js +0 -2
  579. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +0 -74
  587. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +0 -64
  591. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +0 -32
  594. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +0 -24
  595. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +0 -93
  599. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +0 -148
  604. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +0 -226
  605. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +0 -27
  606. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +0 -115
  609. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +0 -8
  616. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +0 -23
  617. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +0 -90
  622. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +0 -94
  623. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +0 -41
  625. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +0 -287
  627. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +0 -79
  628. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +0 -104
  633. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/app/consult/page-6168a7c43e6ef8f5.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/framework-b2763b10dc6b3836.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +0 -1
  687. package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +0 -1
  688. /package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → dRS6lEhSRRBr1abbzp7fJ}/_ssgManifest.js +0 -0
@@ -0,0 +1,50 @@
1
+ /** SUBSCRIPTION-EXHAUST-REROUTE (0.2.24 · P0) — Pod 구현 자식의 «기본» 모델을 codex 밖으로 뺀다.
2
+ *
3
+ * 🩸 10-11 실측(apiEq 24h): codex 소모의 ~95% 가 node-b Pod 구현 자식이었다($2,633 · 107런). 원인은
4
+ * 자식 모델을 안 준 Pod 발사가 `planPodProvider` 로 codex(gpt-6-sol)에 떨어진 것이다.
5
+ * ⭐ 결정 지점은 «호스트가 발사 인자를 만드는 곳»(`self orchestrate --substrate pod`) — 여기서 «자식 모델 없음 → 기본값»을
6
+ * `--child-llm-provider/--child-llm-model` 과 «같은 모양»으로 채운다. 그 뒤 경로(키 확인·passEnv·Job 인자)는 명시 발사와 같다.
7
+ * ⛔ 명시(`--child-llm-*`)가 있으면 손대지 않는다 · `--bench-arms`(팔마다 모델) · `--pod-account`(codex 계정 고정 = 사람의 선택)도 손대지 않는다.
8
+ * ⛔ 기본값이 «못 서면»(OpenRouter 키 없음) 종전 codex 경로로 간다 — 기본값 때문에 발사가 죽지 않는다(관측은 남긴다).
9
+ * config = `tools.selfImplement.podChildDefault`: `{ provider, model? }` · `'off'`(종전 codex 기본). 없으면 아래 상수. */
10
+
11
+ /** 대표 라우팅 «중» 시작 모델 — OpenRouter 키는 Pod 에 이미 있다(새 자격 0). */
12
+ export const POD_CHILD_DEFAULT = { provider: 'openrouter', model: 'openrouter/z-ai/glm-5.3' } as const;
13
+
14
+ export type PodChildDefaultDecision =
15
+ | { apply: true; provider: string; model?: string; source: 'config' | 'default' }
16
+ | { apply: false; reason: 'flag' | 'bench-arms' | 'pod-account' | 'config-off' | 'no-openrouter-key'; provider?: string; model?: string; source?: 'config' | 'default' };
17
+
18
+ function parseConfigValue(raw: unknown): { value: { provider: string; model?: string } | 'off'; source: 'config' } | { value: typeof POD_CHILD_DEFAULT; source: 'default'; invalid?: unknown } {
19
+ if (raw === undefined) return { value: POD_CHILD_DEFAULT, source: 'default' };
20
+ if (raw === 'off' || raw === false) return { value: 'off', source: 'config' };
21
+ if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
22
+ const v = raw as Record<string, unknown>;
23
+ const provider = typeof v.provider === 'string' ? v.provider.trim() : '';
24
+ const model = typeof v.model === 'string' ? v.model.trim() : '';
25
+ if (provider) return { value: { provider, ...(model ? { model } : {}) }, source: 'config' };
26
+ }
27
+ return { value: POD_CHILD_DEFAULT, source: 'default', invalid: raw };
28
+ }
29
+
30
+ /** 순수 판정 — 「무엇을 보고 정했나」가 인자에 다 있다. */
31
+ export function resolvePodChildDefault(input: {
32
+ flags: { provider?: string; model?: string; effort?: string };
33
+ benchArms: boolean;
34
+ explicitPodAccount?: string;
35
+ config: unknown;
36
+ /** OpenRouter 키가 호스트에 «있나»(값은 안 본다) — openrouter 기본일 때만 묻는다. */
37
+ openrouterKeyPresent: () => boolean;
38
+ }): PodChildDefaultDecision & { invalidConfig?: unknown } {
39
+ if (input.flags.provider?.trim() || input.flags.model?.trim() || input.flags.effort?.trim()) return { apply: false, reason: 'flag' };
40
+ if (input.benchArms) return { apply: false, reason: 'bench-arms' };
41
+ if (input.explicitPodAccount?.trim()) return { apply: false, reason: 'pod-account' };
42
+ const parsed = parseConfigValue(input.config);
43
+ const invalid = 'invalid' in parsed ? { invalidConfig: parsed.invalid } : {};
44
+ if (parsed.value === 'off') return { apply: false, reason: 'config-off', source: 'config' };
45
+ const { provider, model } = parsed.value as { provider: string; model?: string };
46
+ if (provider === 'openrouter' && !input.openrouterKeyPresent()) {
47
+ return { apply: false, reason: 'no-openrouter-key', provider, ...(model ? { model } : {}), source: parsed.source, ...invalid };
48
+ }
49
+ return { apply: true, provider, ...(model ? { model } : {}), source: parsed.source, ...invalid };
50
+ }
@@ -7,7 +7,9 @@
7
7
  * 목록 밖 provider 는 발사 «전»에 같은 문면으로 거부된다.
8
8
  * ⛔ 이 모듈은 가볍게 둔다(무거운 import 0) — 하니스 CLI 가 Pod 표면 전체를 끌어오지 않게.
9
9
  */
10
- export const POD_CHILD_PROVIDERS = ['openai-codex', 'grok', 'openrouter', 'anthropic'] as const;
10
+ // BEDROCK-PROVIDER ② (0.2.24) — bedrock 은 «이름 있는 AWS Secret» 이 클러스터에 있을 때만 뜬다(pod-bedrock-child.ts · 발사 전 거부).
11
+ // ZAI-POD-CHILD (0.2.24) — glm 은 Z.ai GLM Coding Plan(정액 구독) · «이름 있는 ZAI Secret» 이 클러스터에 있을 때만 뜬다(pod-zai-child.ts · 발사 전 거부 · 동시 상한 넘치면 정책대로).
12
+ export const POD_CHILD_PROVIDERS = ['openai-codex', 'grok', 'openrouter', 'anthropic', 'bedrock', 'glm'] as const;
11
13
  export type PodChildProvider = typeof POD_CHILD_PROVIDERS[number];
12
14
 
13
15
  /** 사람이 쓰는 별칭 → 정식 이름. */
@@ -27,3 +29,14 @@ export function podChildProviderRefusal(named: string | undefined): string | und
27
29
  if (!id || podChildProviderOf(id)) return undefined;
28
30
  return `pod: Pod 자식 provider 는 ${POD_CHILD_PROVIDERS.join('|')} 만 — 받음 ${id}`;
29
31
  }
32
+
33
+ /**
34
+ * BEDROCK-POD-PROVIDER-DROP (0.2.24) — 발사(`index.ts`)가 고른 Pod provider 를 Pod 옵션(`provider` · `account`)으로 옮기는 «한 곳».
35
+ * 🩸 10-11: podBase 가 grok·openrouter·anthropic 만 손으로 나열해 `bedrock` 이 떨어졌다 — Pod 자식은 codex(team) 로 돌았다.
36
+ * ⭐ codex 가 아닌 provider 는 «그 이름»이 곧 account 다(Pod 표면 `plannedAccount` 와 같은 규칙) · codex 만 명시 계정 ?? team.
37
+ */
38
+ export function podLaunchProviderOptions(podProvider: PodChildProvider, o: { explicitPodAccount?: string; grokApiKeyOptIn: boolean }): { account: string; provider: PodChildProvider; grokApiKeyOptIn?: boolean } {
39
+ // provider 는 여섯 전부 싣는다 — Pod 의 podChildLlmArgs 는 명시 발사에 provider 가 비면 거부한다(조용한 codex 금지).
40
+ if (podProvider === 'openai-codex') return { account: o.explicitPodAccount ?? 'team', provider: 'openai-codex' };
41
+ return { account: podProvider, provider: podProvider, ...(podProvider === 'grok' ? { grokApiKeyOptIn: o.grokApiKeyOptIn } : {}) };
42
+ }
@@ -371,6 +371,12 @@ export interface RunPodCommandOptions {
371
371
  runId?: string;
372
372
  name?: string;
373
373
  pollMs?: number;
374
+ /**
375
+ * GATE-MULTI-HOST — throw once the Job's status has been unreadable (`kubectl get job` failing) this long, instead of
376
+ * polling forever: a pool member that died mid-Job (host off · tailnet drop) then frees its caller to place the work
377
+ * elsewhere. Omitted = poll without a bound (unchanged for every caller but the release gate).
378
+ */
379
+ statusUnreadableMs?: number;
374
380
  kubectl?: Kubectl;
375
381
  /** A caller-owned scheduler is self-capped: acquires count only its own Jobs, never cluster occupancy (POOLGLOBAL-REG). */
376
382
  poolScheduler?: PodPoolScheduler;
@@ -536,10 +542,18 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
536
542
  throw new Error(applied.stderr.trim() || 'pod command: Job 적용 실패');
537
543
  }
538
544
  let state: 'complete' | 'failed' = 'failed';
545
+ let unreadableSince: number | null = null;
539
546
  for (;;) {
540
547
  const got = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.status.conditions[*].type}']);
541
548
  const finished = jobFinished(got.stdout);
542
549
  if (finished) { state = finished; break; }
550
+ if (got.status !== 0 && options.statusUnreadableMs !== undefined) {
551
+ unreadableSince ??= Date.now();
552
+ if (Date.now() - unreadableSince >= options.statusUnreadableMs) {
553
+ log('pod.command', 'job-status-unreadable', { job: name, context, unreadableMs: Date.now() - unreadableSince, error: (got.stderr ?? '').trim().slice(0, 300) });
554
+ throw new Error(`pod command: Job 상태를 ${Math.round(options.statusUnreadableMs / 1000)}초 동안 못 읽었다(${context}) — ${(got.stderr ?? '').trim().split('\n').pop()?.slice(0, 200) ?? ''}`);
555
+ }
556
+ } else unreadableSince = null;
543
557
  await sleep(options.pollMs ?? 15_000);
544
558
  }
545
559
  const logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
@@ -44,6 +44,81 @@ export function podTerminalRow(row: Record<string, unknown>): { stage: string; o
44
44
  return nestedPodResult(row);
45
45
  }
46
46
 
47
+ export const POD_EXIT_CLASSES = ['oom-killed', 'deadline-exceeded', 'gh-login-failed', 'pod-secret', 'ask-reprompt', 'child-unconverged', 'child-error', 'no-result-line', 'unknown'] as const;
48
+
49
+ export type PodExitClass = typeof POD_EXIT_CLASSES[number];
50
+
51
+ const isPodBookkeepingLine = (line: string): boolean =>
52
+ /^(?:ELANOUS_(?:MEM|RUN_LEDGER|USAGE_ROLLUP|POD_)|\[graph\] |\[ask\]\s+\d+\)\s)/u.test(line) || /^(?:at\s+\S|\.\.\.\s+\d+\s+more\b|cleanup\s+(?:complete|done|finished)\b)/iu.test(line);
53
+
54
+ const isPodErrorLine = (line: string): boolean =>
55
+ /\berror\b|\bfail(?:ed|ure)?\b|exception|fatal|denied|timed?\s*out|exceeded|overloaded|unavailable|exhausted|오류|실패/iu.test(line);
56
+
57
+ const normalizePodLogLine = (line: string): string => line.replace(/\/home\/[^/\s]+\//gu, '~/').slice(0, 240);
58
+
59
+ /** Classify a failed Pod using its terminal metadata and child output, without side effects. */
60
+ export function classifyPodExit(input: {
61
+ errorCode?: string | null;
62
+ containerReason?: string | null;
63
+ containerExitCode?: number | null;
64
+ jobReason?: string | null;
65
+ logs: string;
66
+ result?: Record<string, unknown> | null;
67
+ }): { class: PodExitClass; errorCode: string | null; containerReason: string | null; exitCode: number | null; jobReason: string | null; tail: string[] } {
68
+ const logLines = input.logs.split(/\r\n|\n|\r/u).map((line) => line.trim()).filter(Boolean);
69
+ let terminalResult: { stage: string; ok: boolean; error?: string } | null = null;
70
+ for (const line of logLines) {
71
+ if (!line.startsWith('{')) continue;
72
+ let parsed: unknown;
73
+ try { parsed = JSON.parse(line); } catch { continue; }
74
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;
75
+ terminalResult = podTerminalRow(parsed as Record<string, unknown>) ?? terminalResult;
76
+ }
77
+ if (!terminalResult && input.result) terminalResult = podTerminalRow(input.result);
78
+ const hasResultLine = terminalResult !== null;
79
+ const askReprompt = logLines.some((line) =>
80
+ /^\[ask\](?!\s+\d+\)\s).*(?:implementation[_ -]?target|reprompt|re-prompt|되묻)/iu.test(line));
81
+ // 파싱되는 JSON 줄(진행·결과 행)은 오류 «줄»로 세지 않는다 — tail 과 같은 기준.
82
+ const isParsedJsonLine = (line: string): boolean => {
83
+ if (!line.startsWith('{')) return false;
84
+ try { const parsed = JSON.parse(line); return !!parsed && typeof parsed === 'object' && !Array.isArray(parsed); } catch { return false; }
85
+ };
86
+ const hasErrorLine = logLines.some((line) => !isPodBookkeepingLine(line) && !isParsedJsonLine(line) && isPodErrorLine(line));
87
+ let exitClass: PodExitClass;
88
+ if (input.errorCode === 'pod-secret') exitClass = 'pod-secret';
89
+ else if (input.jobReason === 'DeadlineExceeded') exitClass = 'deadline-exceeded';
90
+ else if (input.containerReason === 'OOMKilled') exitClass = 'oom-killed';
91
+ else if (input.containerExitCode === 7) exitClass = 'gh-login-failed';
92
+ else if (askReprompt) exitClass = 'ask-reprompt';
93
+ else if (terminalResult?.stage && terminalResult.ok === false) exitClass = 'child-unconverged';
94
+ else if (!hasResultLine && hasErrorLine) exitClass = 'child-error';
95
+ else if (!hasResultLine) exitClass = 'no-result-line';
96
+ else exitClass = 'unknown';
97
+
98
+ const tail = logLines.flatMap((line) => {
99
+ if (line.startsWith('{')) {
100
+ let parsed: unknown;
101
+ try { parsed = JSON.parse(line); } catch { parsed = undefined; }
102
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
103
+ const terminal = podTerminalRow(parsed as Record<string, unknown>);
104
+ if (terminal?.error) return terminal.error.split(/\r\n|\n|\r/u).map((part) => part.trim())
105
+ .filter((part) => part && !isPodBookkeepingLine(part)).map(normalizePodLogLine);
106
+ return [];
107
+ }
108
+ }
109
+ return isPodBookkeepingLine(line) ? [] : [normalizePodLogLine(line)];
110
+ }).slice(-5);
111
+
112
+ return {
113
+ class: exitClass,
114
+ errorCode: input.errorCode ?? null,
115
+ containerReason: input.containerReason ?? null,
116
+ exitCode: input.containerExitCode ?? null,
117
+ jobReason: input.jobReason ?? null,
118
+ tail,
119
+ };
120
+ }
121
+
47
122
  /** Extract a human-readable reason from a failed child Pod without treating transfer markers as child errors. */
48
123
  export function extractPodFailureReason(input: {
49
124
  logs: string;
@@ -59,10 +134,8 @@ export function extractPodFailureReason(input: {
59
134
  }
60
135
  if (input.containerReason === 'OOMKilled') return 'OOMKilled: 컨테이너 메모리 한도 초과';
61
136
 
62
- const isBookkeeping = (line: string): boolean =>
63
- /^(?:ELANOUS_(?:MEM|RUN_LEDGER|USAGE_ROLLUP|POD_)|\[graph\] |\[ask\]\s+\d+\)\s)/u.test(line) || /^(?:at\s+\S|\.\.\.\s+\d+\s+more\b|cleanup\s+(?:complete|done|finished)\b)/iu.test(line);
64
- const isError = (line: string): boolean =>
65
- /\berror\b|\bfail(?:ed|ure)?\b|exception|fatal|denied|timed?\s*out|exceeded|overloaded|unavailable|exhausted|오류|실패/iu.test(line);
137
+ const isBookkeeping = isPodBookkeepingLine;
138
+ const isError = isPodErrorLine;
66
139
  const meaningful: Array<{ text: string; terminal: boolean }> = [];
67
140
  for (const line of input.logs.split(/\r\n|\n|\r/u)) {
68
141
  const trimmed = line.trim();
@@ -90,7 +163,7 @@ export function extractPodFailureReason(input: {
90
163
  meaningful.push({ text: trimmed, terminal: false });
91
164
  }
92
165
  const errorLine = [...meaningful].reverse().find((line) => line.terminal || isError(line.text));
93
- const reason = errorLine?.text.replace(/\/home\/[^/\s]+\//gu, '~/').slice(0, 240);
166
+ const reason = errorLine ? normalizePodLogLine(errorLine.text) : undefined;
94
167
  if (reason) return reason;
95
168
  // POD-NORESULT: an unconverged child (exit 2 → BackoffLimitExceeded under backoffLimit 0) often leaves a result row
96
169
  // with a stage and PR but no error text — report that instead of «unreadable».
@@ -101,5 +174,5 @@ export function extractPodFailureReason(input: {
101
174
  return pr ? `수확 가능(${stage}) · ${pr}` : `수렴 못 함(단계 ${stage})`;
102
175
  }
103
176
  const why = input.logTailReason?.trim() || (input.logs.trim() ? '로그에 읽을 수 있는 오류 줄 없음' : '자식 로그 비어 있음');
104
- return `사유 못 읽음: ${why.replace(/\/home\/[^/\s]+\//gu, '~/').slice(0, 240)}`;
177
+ return `사유 못 읽음: ${normalizePodLogLine(why)}`;
105
178
  }
@@ -0,0 +1,122 @@
1
+ // REVIEW-ACP-POD (0.2.25 · REVIEW-ACP-DEFAULT ② 조각) — Pod 런이 낸 merge-ready PR 을 «호스트»가 Claude ACP(구독)로 다시 본다.
2
+ //
3
+ // S Pod 안 하니스 리뷰는 api 리뷰어(codex 기본 gpt-6-sol · OR Pod 는 glm 고정)로 돈다 — Pod 엔 Claude 구독도 정책 파일도 없어
4
+ // `roleLlm.reviewer = claude-acp`(운영에 이미 켜져 있다)가 Pod 안에선 «안 닿는다». 호스트 레인 런만 ACP 로 리뷰받는다.
5
+ // C Pod 가 호스트로 돌려보내는 유일한 문은 merge-ready → 호스트 재게이트 → 병합이다. 여기에 리뷰가 없다.
6
+ // Q Pod 런의 리뷰를 구독(ACP)으로 옮기려면 어디서 하나?
7
+ // A 호스트 병합 직전 한 자리에서, 하니스 레인과 «같은» 정책 행(`resolveSubscriptionReviewer`)·같은 가용성 검사
8
+ // (`subscriptionReviewerAvailability` — 구독 확인 · 상한 · 프록시)·같은 ACP 리뷰어(`makeAcpReviewLLM`)로 PR 을 본다.
9
+ // ⛔ 못 쓰면(설정 없음·구독 확인 실패·상한·프록시 없음·리뷰 미완) «refused» 로 돌려주고 호출자는 종전 길(Pod 리뷰 결과로 재게이트)을 그대로 간다.
10
+ // 조용히 다른 공급자로 새지 않는다 — 이 함수 안엔 api 폴백이 «없다».
11
+ // ⛔ 기본 꺼짐(opt-in): 옵션 → env `ELANOUS_POD_HOST_ACP_REVIEW` → config `llm.podHostAcpReview` 순.
12
+ // 📌 남은 조각(②-b): 이 문이 켜진 런에서 Pod 안 api 리뷰를 «끄는» 것은 Pod 이미지 쪽 변경이라 따로 간다.
13
+ import { spawnSync } from 'node:child_process';
14
+ import { debug } from '../../debug/log.js';
15
+ import type { ReviewResult } from '../../agent-substrate/pr-reviewer.js';
16
+ import type { SubscriptionReviewerSpec } from '../../user-config.js';
17
+ import type { SubscriptionReviewerDeps, subscriptionReviewerSpawn } from '../../self-dev/review-provider-fallback.js';
18
+
19
+ export const POD_HOST_ACP_REVIEW_ENV = 'ELANOUS_POD_HOST_ACP_REVIEW';
20
+
21
+ export type PodHostAcpReviewEnable = { enabled: boolean; source: 'option' | 'env' | 'config' | 'default' };
22
+
23
+ /** 켜는 순서: 옵션 → env(`1`/`true` 켬 · `0`/`false` 끔) → config `llm.podHostAcpReview === true` → 꺼짐. 읽기 실패는 꺼짐(종전). */
24
+ export function resolvePodHostAcpReview(
25
+ option: boolean | undefined,
26
+ env: NodeJS.ProcessEnv,
27
+ readConfig: () => unknown,
28
+ ): PodHostAcpReviewEnable {
29
+ if (typeof option === 'boolean') return { enabled: option, source: 'option' };
30
+ const raw = env[POD_HOST_ACP_REVIEW_ENV]?.trim().toLowerCase();
31
+ if (raw === '1' || raw === 'true') return { enabled: true, source: 'env' };
32
+ if (raw === '0' || raw === 'false') return { enabled: false, source: 'env' };
33
+ try {
34
+ const cfg = readConfig() as { llm?: { podHostAcpReview?: unknown } } | undefined;
35
+ if (cfg?.llm?.podHostAcpReview === true) return { enabled: true, source: 'config' };
36
+ } catch { /* 읽기 실패 = 꺼짐(종전 길) */ }
37
+ return { enabled: false, source: 'default' };
38
+ }
39
+
40
+ export type PodHostAcpReviewOutcome =
41
+ | { status: 'clean'; mustFix: 0; shouldFix: number }
42
+ | { status: 'must-fix'; mustFix: number; findings: string[]; verdict: ReviewResult['verdict'] }
43
+ | { status: 'refused'; reason: string };
44
+
45
+ export interface PodHostAcpReviewDeps {
46
+ /** `{ spec, cap }` — 기본은 하니스 레인과 같은 정책 행(`resolveSubscriptionReviewer`). */
47
+ resolveReviewer?: () => { spec: SubscriptionReviewerSpec; cap: number } | undefined;
48
+ /** 구독·상한·프록시 확인 — 기본은 `subscriptionReviewerAvailability`. */
49
+ availability?: (spec: SubscriptionReviewerSpec, cap: number) => { spawn?: ReturnType<typeof subscriptionReviewerSpawn>; reason?: string };
50
+ subscriptionReviewerDeps?: SubscriptionReviewerDeps;
51
+ /** PR 머리 sha·제목·본문·diff. 기본은 `gh`. */
52
+ readPr?: (prNumber: number, repoRoot: string) => { headRefOid: string; title: string; body: string; diff: string } | undefined;
53
+ /** ACP 리뷰어(prompt→text). 기본은 `makeAcpReviewLLM({ backend: 'claude', backendSpec, env })`. */
54
+ makeAcpReviewLLM?: (spawn: ReturnType<typeof subscriptionReviewerSpawn>, repoRoot: string) => (prompt: string) => Promise<string>;
55
+ reviewPullRequest?: (input: { prDiff: string; phaseIntent: string }, llm: (prompt: string) => Promise<string>) => Promise<ReviewResult>;
56
+ env?: NodeJS.ProcessEnv;
57
+ }
58
+
59
+ function defaultReadPr(prNumber: number, repoRoot: string): { headRefOid: string; title: string; body: string; diff: string } | undefined {
60
+ const view = spawnSync('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,title,body'], { cwd: repoRoot, encoding: 'utf8', timeout: 60_000 });
61
+ if (view.status !== 0) return undefined;
62
+ const diff = spawnSync('gh', ['pr', 'diff', String(prNumber)], { cwd: repoRoot, encoding: 'utf8', timeout: 120_000, maxBuffer: 64 * 1024 * 1024 });
63
+ if (diff.status !== 0) return undefined;
64
+ try {
65
+ const parsed = JSON.parse(view.stdout) as { headRefOid?: unknown; title?: unknown; body?: unknown };
66
+ if (typeof parsed.headRefOid !== 'string') return undefined;
67
+ return { headRefOid: parsed.headRefOid, title: typeof parsed.title === 'string' ? parsed.title : '', body: typeof parsed.body === 'string' ? parsed.body : '', diff: diff.stdout };
68
+ } catch { return undefined; }
69
+ }
70
+
71
+ function refused(reason: string, data: Record<string, unknown>): PodHostAcpReviewOutcome {
72
+ try { debug.log('self-implement.pod', 'acp-review-refused', { ...data, reason }, { level: 'warn' }); } catch { /* 관측은 결과를 안 바꾼다 */ }
73
+ return { status: 'refused', reason };
74
+ }
75
+
76
+ /** Pod merge-ready PR 을 호스트 Claude ACP 로 리뷰한다. ⛔ 던지지 않는다 — 모든 실패는 `refused`(호출자는 종전 길). */
77
+ export async function runPodHostAcpReview(
78
+ input: { prNumber: number; headCommit: string; repoRoot: string; job?: string },
79
+ deps: PodHostAcpReviewDeps = {},
80
+ ): Promise<PodHostAcpReviewOutcome> {
81
+ const obs = { job: input.job ?? null, pr: input.prNumber, head: input.headCommit };
82
+ try {
83
+ const env = deps.env ?? process.env;
84
+ // 지연 import — 이 문이 꺼진 런은 정책·설정을 안 읽는다.
85
+ const picked = deps.resolveReviewer ? deps.resolveReviewer() : await (async () => {
86
+ const { loadLlmPolicy, resolveSubscriptionReviewer } = await import('../../policy/llm-policy.js');
87
+ const { getUserConfig } = await import('../../user-config.js');
88
+ return resolveSubscriptionReviewer(loadLlmPolicy(), getUserConfig().roleLlm);
89
+ })();
90
+ if (!picked) return refused('no-subscription-reviewer', obs);
91
+ const avail = deps.availability
92
+ ? deps.availability(picked.spec, picked.cap)
93
+ : (await import('../../self-dev/review-provider-fallback.js')).subscriptionReviewerAvailability(picked.spec, picked.cap, env, deps.subscriptionReviewerDeps);
94
+ if (!avail.spawn) return refused(`unavailable: ${avail.reason ?? 'unknown'}`, { ...obs, cap: picked.cap });
95
+ const pr = (deps.readPr ?? defaultReadPr)(input.prNumber, input.repoRoot);
96
+ if (!pr) return refused('pr-unreadable', obs);
97
+ if (pr.headRefOid.toLowerCase() !== input.headCommit.toLowerCase()) return refused('head-moved', { ...obs, prHead: pr.headRefOid });
98
+ if (!pr.diff.trim()) return refused('empty-diff', obs);
99
+ const llm = deps.makeAcpReviewLLM
100
+ ? deps.makeAcpReviewLLM(avail.spawn, input.repoRoot)
101
+ : await (async () => {
102
+ const { makeAcpReviewLLM } = await import('../../agent-substrate/acp-reviewer.js');
103
+ const spawn = avail.spawn!;
104
+ return makeAcpReviewLLM({ cwd: input.repoRoot, backend: 'claude', backendSpec: spawn.backendSpec, env: spawn.env });
105
+ })();
106
+ const review = deps.reviewPullRequest ?? (await import('../../agent-substrate/pr-reviewer.js')).reviewPullRequest;
107
+ const phaseIntent = [`Pod 런 PR #${input.prNumber} 의 호스트 Claude ACP 리뷰(병합 전 관문).`, pr.title, pr.body.slice(0, 4000)].filter((s) => s.trim()).join('\n\n');
108
+ const rr = await review({ prDiff: pr.diff, phaseIntent }, llm);
109
+ // ⛔ reviewed=false(파싱 실패·ACP 오류를 리뷰어가 흡수) 는 «리뷰 완료»가 아니다 — 통과로 읽지 않는다.
110
+ if (!rr.reviewed) return refused('acp-review-not-completed', obs);
111
+ const mustFix = rr.mustFix.length;
112
+ if (rr.verdict === 'fail' || mustFix > 0) {
113
+ debug.log('self-implement.pod', 'host-acp-review', { ...obs, status: 'must-fix', verdict: rr.verdict, mustFix, shouldFix: rr.shouldFix.length });
114
+ return { status: 'must-fix', mustFix, findings: rr.mustFix.slice(0, 10), verdict: rr.verdict };
115
+ }
116
+ debug.log('self-implement.pod', 'host-acp-review', { ...obs, status: 'clean', verdict: rr.verdict, mustFix: 0, shouldFix: rr.shouldFix.length });
117
+ return { status: 'clean', mustFix: 0, shouldFix: rr.shouldFix.length };
118
+ } catch (error) {
119
+ // 원문은 싣지 않는다 — 계정·프록시 문면이 섞일 수 있다(하니스 레인과 같은 규율).
120
+ return refused(/handshake timeout/i.test(error instanceof Error ? error.message : String(error)) ? 'acp-handshake-timeout' : 'acp-error', obs);
121
+ }
122
+ }
@@ -40,6 +40,8 @@ export function leaseKubectl(args: readonly string[], input?: string): { status:
40
40
  export interface PodLeaseMember {
41
41
  context: string;
42
42
  capacity: number;
43
+ /** POD-POOL-UNCAPPED-SPEC — `capacity` came from the spec default (`:N` absent), not from the operator. */
44
+ capacityDefaulted?: boolean;
43
45
  running: number | null;
44
46
  pending: number | null;
45
47
  /** Job names of Pending harness Pods already included in pending (used to avoid counting the same Job's host lease twice). */
@@ -94,7 +96,12 @@ export interface PoolLeaseMeasure {
94
96
 
95
97
  export interface PoolLeaseRecommendation {
96
98
  recommended: number | null;
97
- limitedBy: 'capacity' | 'memory' | null;
99
+ /**
100
+ * What stopped admission: `memory` = node memory headroom · `capacity` = the pool slot budget ·
101
+ * `pool-cap` = POD-POOL-UNCAPPED-SPEC — a member whose cap came from the spec default (`:N` absent → 2) is
102
+ * already at/over that cap, so the pool spec itself (not memory, not a configured budget) is the bound.
103
+ */
104
+ limitedBy: 'capacity' | 'memory' | 'pool-cap' | null;
98
105
  reason: string | null;
99
106
  capacitySlots: number | null;
100
107
  memorySlots: number | null;
@@ -392,7 +399,7 @@ export function measurePoolLease(members: readonly PodPoolMember[], deps: { kube
392
399
  const kubectl = deps.kubectl ?? leaseKubectl;
393
400
  return { members: members.map((member) => {
394
401
  const base = ['--context', member.context, '--request-timeout=10s'];
395
- const result: PodLeaseMember = { context: member.context, capacity: member.capacity, running: null, pending: null, unleasedRunning: null, memoryLimitBytes: null, allocatableMemoryBytes: null, allocatableCpuMillicores: null, availableMemoryByNodeBytes: null, reason: null };
402
+ const result: PodLeaseMember = { context: member.context, capacity: member.capacity, ...(member.capacityDefaulted ? { capacityDefaulted: true } : {}), running: null, pending: null, unleasedRunning: null, memoryLimitBytes: null, allocatableMemoryBytes: null, allocatableCpuMillicores: null, availableMemoryByNodeBytes: null, reason: null };
396
403
  try {
397
404
  const nodes = kubectl([...base, 'get', 'nodes', '-o', 'json']);
398
405
  const jobs = kubectl([...base, '-n', 'elanous-test', 'get', 'jobs', '-l', 'elanous.substrate=pod', '-o', 'json']);
@@ -635,7 +642,7 @@ export function recommendConcurrency(measure: PoolLeaseMeasure, options: { capac
635
642
  if (goalBytes === null || goalBytes <= 0) return { ...empty, reason: '측정 불가: perGoalMemory' };
636
643
  const admission = admissionByUsage(measure, goalBytes, options.perGoalMemory !== undefined);
637
644
  if (!measure.members.length || measure.members.some((m) => m.running === null || m.pending === null || m.unleasedRunning === null || m.allocatableMemoryBytes === null || m.memoryLimitBytes === null || m.allocatableCpuMillicores === null || m.availableMemoryByNodeBytes === null)) {
638
- debug.log('pod-lease', 'admit-by-usage', { samples: admission.samples, p95Bytes: admission.p95Bytes, admitBytes: admission.admitBytes, fallback: admission.fallback, recommended: null, limitedBy: null });
645
+ debug.log('pod-lease', 'admit-by-usage', { samples: admission.samples, p95Bytes: admission.p95Bytes, admitBytes: admission.admitBytes, fallback: admission.fallback, recommended: null, limitedBy: null, capacity: options.capacity, capacitySlots: null, memorySlots: null, running: null, pending: null });
639
646
  return { ...empty, reason: `측정 불가: cluster${measure.members.map((m) => m.reason ? ` ${m.context}: ${m.reason}` : '').join('')}` };
640
647
  }
641
648
  if (!Number.isSafeInteger(options.capacity) || options.capacity < 0) return { ...empty, reason: '측정 불가: capacity' };
@@ -680,9 +687,14 @@ export function recommendConcurrency(measure: PoolLeaseMeasure, options: { capac
680
687
  Math.floor((m.allocatableMemoryBytes! - m.memoryLimitBytes!) / liteBytes))), 0);
681
688
  const memoryBound = Math.min(memorySlots, placeableSlots);
682
689
  const recommended = Math.max(0, Math.min(capacitySlots, memoryBound) - eligibleUnleasedRunning);
683
- const limitedBy = memoryBound < capacitySlots ? 'memory' : 'capacity';
690
+ // POD-POOL-UNCAPPED-SPEC — `capacity ≤ occupied` on a member whose cap is the spec default (`:N` absent → 2) means
691
+ // the «uncapped» pool spec is what admits nothing. Name it `pool-cap`, not the generic `capacity`, so a launch that
692
+ // sits on `recommended=0` says in its first admit line that the pool spec never declared a cap of its own.
693
+ const defaultCapFull = capacitySlots <= 0 && measure.members.some((m) => m.capacityDefaulted === true
694
+ && m.reason !== 'dns' && m.running !== null && m.pending !== null && m.running + m.pending >= m.capacity);
695
+ const limitedBy: PoolLeaseRecommendation['limitedBy'] = memoryBound < capacitySlots ? 'memory' : defaultCapFull ? 'pool-cap' : 'capacity';
684
696
  if (unleasedRunning > 0) debug.log('pod-lease', 'unleased', { unleasedRunning, running, recommended });
685
- debug.log('pod-lease', 'admit-by-usage', { samples: admission.samples, p95Bytes: admission.p95Bytes, admitBytes: admission.admitBytes, fallback: admission.fallback, recommended, limitedBy });
697
+ debug.log('pod-lease', 'admit-by-usage', { samples: admission.samples, p95Bytes: admission.p95Bytes, admitBytes: admission.admitBytes, fallback: admission.fallback, recommended, limitedBy, capacity: options.capacity, capacitySlots, memorySlots, running, pending });
686
698
  return { recommended, limitedBy, reason: measure.members.some((m) => m.reason === 'dns') ? 'dns' : null, capacitySlots, memorySlots, liteMemorySlots, placeableSlots, accountSlots, running, pending, pendingJobs, unleasedRunning, admission };
687
699
  }
688
700
 
@@ -14,6 +14,8 @@ type ParseResult = Ledger[] | { error: Incomplete[]; ledgers: Ledger[] };
14
14
  const NON_PROGRESS_EVENTS = new Set(['progress-delivery-outcome']);
15
15
  const REEMIT_EXCLUDED_PREFIX = 'progress-delivery';
16
16
  type Emit = (category: string, event: string, data: Record<string, unknown>) => void;
17
+ /** Heal-loop starter seam — defaults to the real `startHealLoop` inside `recordFailureEvent`. */
18
+ type StartHealLoop = Parameters<typeof recordFailureEvent>[2];
17
19
 
18
20
  /** Reemit only complete ledger records; offsets name the first byte of each line in the Pod ledger. */
19
21
  function reemitLedgerLines(jsonl: string, runId: string, startOffset: number, emit: Emit): number {
@@ -93,7 +95,7 @@ export function parsePodLedgerChunks(logs: string): ParseResult {
93
95
  return error.length ? { error, ledgers } : ledgers;
94
96
  }
95
97
 
96
- function intakeCollectedFailure(runId: string, dir: string, log: Emit): void {
98
+ function intakeCollectedFailure(runId: string, dir: string, log: Emit, startHealLoop?: StartHealLoop): void {
97
99
  let ledger: ReturnType<typeof loadRunLedger>;
98
100
  try { ledger = loadRunLedger(runId, dir); }
99
101
  catch { return; }
@@ -104,8 +106,10 @@ function intakeCollectedFailure(runId: string, dir: string, log: Emit): void {
104
106
  if (terminal?.data.runStatus !== 'failed' || !terminal.timestamp || !Number.isFinite(Date.parse(terminal.timestamp))
105
107
  || ledger.slice(terminalIndex + 1).some(entry => !TRAILING_BOOKKEEPING_EVENTS.includes(entry.event as typeof TRAILING_BOOKKEEPING_EVENTS[number]))) return;
106
108
  try {
109
+ // POD-HEAL-HOST — the recovered Pod failure is recorded into the HOST universe (`dirname(dir)`),
110
+ // so the host heal loop triages it (harvest + narrowed relaunch) instead of dying inside the Pod.
107
111
  recordFailureEvent({ source: 'harness-run', kind: 'pod-run', ref: runId,
108
- summary: `Pod run ${runId} failed`, at: terminal.timestamp }, dirname(dir));
112
+ summary: `Pod run ${runId} failed`, at: terminal.timestamp }, dirname(dir), startHealLoop);
109
113
  } catch (error) {
110
114
  log('self-implement.pod', 'heal-intake-failed', { runId, reason: error instanceof Error ? error.message : String(error) });
111
115
  }
@@ -115,11 +119,13 @@ function intakeCollectedFailure(runId: string, dir: string, log: Emit): void {
115
119
  * except a ledger that THIS run's live follower created (`replace`): that one is a partial copy and the final is complete. */
116
120
  export function collectPodLedgers(
117
121
  logs: string,
118
- { dir = runLedgerDir(), log = defaultPodReemit(), emit = defaultPodReemit(), replace = new Set<string>() }: {
122
+ { dir = runLedgerDir(), log = defaultPodReemit(), emit = defaultPodReemit(), replace = new Set<string>(), startHealLoop }: {
119
123
  dir?: string;
120
124
  log?: (category: string, event: string, data: Record<string, unknown>) => void;
121
125
  emit?: Emit;
122
126
  replace?: ReadonlySet<string>;
127
+ /** Which starter receives a recovered Pod failure (POD-HEAL-HOST 판정선 measurement); default = real `startHealLoop`. */
128
+ startHealLoop?: StartHealLoop;
123
129
  } = {},
124
130
  ): void {
125
131
  const parsed = parsePodLedgerChunks(logs);
@@ -136,7 +142,7 @@ export function collectPodLedgers(
136
142
  const newLines = Buffer.from(jsonl).subarray(previousBytes).toString('utf8');
137
143
  reemitLedgerLines(newLines, runId, previousBytes, emit);
138
144
  log('self-implement.pod', 'ledger-collected', { runId, lines: jsonl.split('\n').filter(Boolean).length, bytes: Buffer.byteLength(jsonl) });
139
- intakeCollectedFailure(runId, dir, log);
145
+ intakeCollectedFailure(runId, dir, log, startHealLoop);
140
146
  } catch (e) {
141
147
  if ((e as NodeJS.ErrnoException).code === 'EEXIST') {
142
148
  // A reattached Job may have already delivered this exact complete snapshot.
@@ -145,7 +151,7 @@ export function collectPodLedgers(
145
151
  const existing = readFileSync(runLedgerPath(runId, dir));
146
152
  const identical = existing.equals(Buffer.from(jsonl));
147
153
  log('self-implement.pod', identical ? 'ledger-collect-already-complete' : 'ledger-collect-skipped', { runId, reason: 'exists' });
148
- if (identical) intakeCollectedFailure(runId, dir, log);
154
+ if (identical) intakeCollectedFailure(runId, dir, log, startHealLoop);
149
155
  } catch (readError) {
150
156
  log('self-implement.pod', 'ledger-collect-incomplete', { runId, reason: readError instanceof Error ? readError.message : String(readError) });
151
157
  }
@@ -0,0 +1,23 @@
1
+ import { BUDGET_SNAPSHOT_ENV } from '../../execution-loop/launch-gate.js';
2
+
3
+ // Preserve the manifest contract except for two values generated per launch.
4
+ export function stablePodManifestText(applied: Array<Record<string, any>>): string {
5
+ const manifests = structuredClone(applied.filter((entry) => entry.kind === 'Job' || entry.kind === 'Secret'));
6
+ let snapshots = 0;
7
+ for (const manifest of manifests) {
8
+ if (manifest.kind !== 'Job') continue;
9
+ for (const container of manifest.spec?.template?.spec?.containers ?? []) {
10
+ for (const entry of container.env ?? []) {
11
+ if (entry.name !== BUDGET_SNAPSHOT_ENV) continue;
12
+ snapshots++;
13
+ // Keep every original byte except this one volatile numeric value.
14
+ const measuredAt = /("measuredAt"\s*:\s*)\d+/g;
15
+ const matches = [...entry.value.matchAll(measuredAt)];
16
+ if (matches.length !== 1) throw new Error('budget snapshot must have exactly one numeric measuredAt');
17
+ entry.value = entry.value.replace(measuredAt, (_match: string, prefix: string) => `${prefix}0`);
18
+ }
19
+ }
20
+ }
21
+ if (snapshots === 0) throw new Error('manifest comparison requires a budget snapshot');
22
+ return JSON.stringify(manifests).replace(/run-[0-9a-f-]{36}/g, 'run-<id>');
23
+ }
@@ -31,6 +31,11 @@ export interface PodPoolMember {
31
31
  /** 원격 클러스터가 도는 기계(ssh 호스트). 없으면 이 기계의 docker 에 있다. */
32
32
  readonly sshHost?: string;
33
33
  readonly capacity: number;
34
+ /**
35
+ * POD-POOL-UNCAPPED-SPEC — 스펙에 `:N` 이 없어서 `capacity` 가 운영자 숫자가 아니라 `POD_POOL_DEFAULT_CAPACITY` 다.
36
+ * 발사 허가는 이 표시로 «풀 기본 상한이 막았다»(`limitedBy=pool-cap`)를 일반 `capacity` 와 갈라 말한다.
37
+ */
38
+ readonly capacityDefaulted?: boolean;
34
39
  /** k3d 클러스터 이름(이미지 반입용). 기본: 컨텍스트가 `k3d-<이름>` 이면 그 이름, 원격이면 `elanous-pool`. */
35
40
  readonly k3dCluster: string;
36
41
  /** 노드 로컬 레지스트리의 이미지(커밋 태그) — 있으면 Pod 가 이것을 pull 한다(델타 · 대표 2026-09-26). 없으면 반입된 로컬 이미지. */
@@ -115,18 +120,23 @@ export function remoteImageSkillsDigest(member: PodPoolMember, image: string, ru
115
120
 
116
121
  const MEMBER = /^([A-Za-z0-9][A-Za-z0-9._-]*)(?:@([A-Za-z0-9][A-Za-z0-9._-]*))?(?::(\d+))?(?:#(k3d-[A-Za-z0-9][A-Za-z0-9._-]*):([1-9]\d{0,4}))?$/u;
117
122
 
123
+ /** 상한 없는 풀 스펙(`:N` 없음)의 노드 상한 — 파일 머리 주석의 «기본 2» 정본(POD-POOL-UNCAPPED-SPEC). */
124
+ export const POD_POOL_DEFAULT_CAPACITY = 2;
125
+
118
126
  export function parsePodPool(spec: string): PodPoolMember[] {
119
127
  const members = spec.split(',').map((s) => s.trim()).filter(Boolean).map((part) => {
120
128
  const m = MEMBER.exec(part);
121
129
  if (!m) throw new Error(`--pod-pool: 못 읽는 노드 「${part}」 — 형식 컨텍스트[@ssh호스트][:상한][#k3d-레지스트리:포트]`);
122
- const capacity = m[3] === undefined ? 2 : Number(m[3]);
130
+ // `:N` 이 없으면 «상한 없음»이 아니라 기본 상한 2 다 — 그 사실(`capacityDefaulted`)을 멤버에 남긴다.
131
+ const capacityDefaulted = m[3] === undefined;
132
+ const capacity = capacityDefaulted ? POD_POOL_DEFAULT_CAPACITY : Number(m[3]);
123
133
  // POOL-LITE (10-07): `:0` means «this member is off» — a `node-c:0` entry once threw here and broke every launch.
124
134
  // It is dropped below (never chosen); only a pool with no live member left is an error.
125
135
  if (!Number.isInteger(capacity) || capacity < 0) throw new Error(`--pod-pool: 상한은 1 이상 — 「${part}」`);
126
136
  if (m[5] && Number(m[5]) > 65535) throw new Error(`--pod-pool: 레지스트리 포트는 65535 이하 — 「${part}」`);
127
137
  const context = m[1]!;
128
138
  const k3dCluster = context.startsWith('k3d-') ? context.slice(4) : 'elanous-pool';
129
- return { context, capacity, k3dCluster, ...(m[2] ? { sshHost: m[2] } : {}), ...(m[4] ? { registry: `${m[4]}:${m[5]}` } : {}) };
139
+ return { context, capacity, ...(capacityDefaulted ? { capacityDefaulted: true } : {}), k3dCluster, ...(m[2] ? { sshHost: m[2] } : {}), ...(m[4] ? { registry: `${m[4]}:${m[5]}` } : {}) };
130
140
  });
131
141
  if (members.length === 0) throw new Error('--pod-pool: 노드가 없다');
132
142
  if (new Set(members.map((m) => m.context)).size !== members.length) throw new Error('--pod-pool: 컨텍스트가 겹친다');
@@ -144,6 +154,59 @@ export function parsePodPool(spec: string): PodPoolMember[] {
144
154
  */
145
155
  export type PodPlacementKind = 'lite' | 'standard';
146
156
 
157
+ /** Identity carried by a launched pool Job and its Pod; absent source fields stay absent. */
158
+ export interface PodWorkIdentity {
159
+ ownerKind?: 'seat' | 'steward' | 'orchestrator' | 'external';
160
+ ownerId?: string;
161
+ taskCard?: string;
162
+ slotId?: string;
163
+ work?: 'harness' | 'authoring' | 'lite';
164
+ }
165
+
166
+ /** Kubernetes label values cannot exceed 63 characters or contain arbitrary card/owner text. */
167
+ export function podWorkLabels(identity: PodWorkIdentity): Record<string, string> {
168
+ const value = (raw: string | undefined): string | undefined => {
169
+ const cleaned = (raw ?? '').replace(/[^A-Za-z0-9._-]+/g, '-').slice(0, 63).replace(/^[^A-Za-z0-9]+|[^A-Za-z0-9]+$/g, '');
170
+ return cleaned || undefined;
171
+ };
172
+ const ownerId = identity.ownerId && value(identity.ownerId) === identity.ownerId ? identity.ownerId : undefined;
173
+ const taskCard = identity.taskCard && value(identity.taskCard) === identity.taskCard ? identity.taskCard : undefined;
174
+ const slotId = identity.slotId && value(identity.slotId) === identity.slotId ? identity.slotId : undefined;
175
+ return {
176
+ ...(identity.ownerKind && ownerId ? { 'elanous.owner-kind': identity.ownerKind, 'elanous.owner-id': ownerId } : {}),
177
+ ...(taskCard ? { 'elanous.task-card': taskCard } : {}),
178
+ ...(slotId ? { 'elanous.checklist': slotId } : {}),
179
+ ...(identity.work ? { 'elanous.work': identity.work } : {}),
180
+ };
181
+ }
182
+
183
+ /** Minih standard-Job policy, independent of the configured pool member capacity. Not wired into allocation. */
184
+ export type MinihLocation = 'home' | 'external';
185
+
186
+ export function minihStandardCapacity(location: MinihLocation): number {
187
+ return location === 'home' ? 1 : 2;
188
+ }
189
+
190
+ /** A drain withholds new slots until occupancy falls to the target; it never evicts Running Pods. */
191
+ export function decideMinihDrain(location: MinihLocation, runningPods: number, pendingPods = 0): {
192
+ capacity: number;
193
+ runningPods: number;
194
+ drainNewAdmissions: boolean;
195
+ availableSlots: number;
196
+ } {
197
+ if (![runningPods, pendingPods].every((count) => Number.isSafeInteger(count) && count >= 0)) {
198
+ throw new RangeError('node-c occupancy must be non-negative whole Pods');
199
+ }
200
+ const capacity = minihStandardCapacity(location);
201
+ const occupied = runningPods + pendingPods;
202
+ return {
203
+ capacity,
204
+ runningPods,
205
+ drainNewAdmissions: occupied > capacity,
206
+ availableSlots: Math.max(0, capacity - occupied),
207
+ };
208
+ }
209
+
147
210
  export interface PodPlacement {
148
211
  readonly member: string;
149
212
  readonly kind: PodPlacementKind | null;
@@ -642,7 +705,11 @@ export function syncPoolImage(member: PodPoolMember, image: string, localCommit:
642
705
  // The import phase gets its own stale window (the lock file's age restarts here).
643
706
  try { const now = new Date(); utimesSync(lockPath, now, now); } catch { /* lock gone · finish anyway */ }
644
707
  const imp = remote(host, `k3d image import ${image} -c ${member.k3dCluster}`);
645
- if (imp.status !== 0) return { ok: false, action: 'failed', detail: `k3d import rc=${imp.status}: ${imp.stderr.slice(-300)}` };
708
+ // As in build.sh, only tools-node cleanup errors may follow a nonzero import rc.
709
+ // Ignore informational lines, but reject any other failure line (including WARN and untagged output).
710
+ const failures = imp.stderr.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !/^(?:INFO|DEBU|DEBUG|TRAC|TRACE)(?:\[|\s|:|$)/.test(line));
711
+ const cleanup = /^(?:(?:ERROR|ERRO|FATAL|FATA|WARNING|WARN|INFO)(?:\[[^\]]*\])?:?\s*)?(?:failed to import images: )?failed to delete tools node '[^']*': (?:Error response from daemon: )?(?:No such container: [A-Za-z0-9_.-]+|removal of container [A-Za-z0-9_.-]+ is already in progress)$/i;
712
+ if (imp.status !== 0 && (failures.length === 0 || !failures.every((line) => cleanup.test(line)))) return { ok: false, action: 'failed', detail: `k3d import rc=${imp.status}: ${imp.stderr.slice(-300)}` };
646
713
  const after = remoteImageCommit(member, image, remote);
647
714
  return after && (!localCommit || after === localCommit)
648
715
  ? { ok: true, action: 'shipped', detail: `${labelNow?.slice(0, 12) ?? '없음'} → ${after.slice(0, 12)}` }
@@ -736,7 +803,9 @@ export async function syncPoolImages(members: readonly PodPoolMember[], image: s
736
803
  const run = deps.run ?? defaultRemoteRun;
737
804
  const script = deps.buildScript === undefined ? podImageBuildScript() : deps.buildScript;
738
805
  const remoteBuild = deps.remoteBuild ?? (script ? defaultRemoteBuild(script, image) : null);
739
- const ship = deps.ship ?? ((m: PodPoolMember, img: string, commit: string | null, remote: RemoteRun) => syncPoolImage(m, img, commit, { run: remote, inspect: deps.inspect, transfer: deps.transfer }));
806
+ // The registry-less build fallback below calls this ship path, including its remote import result check.
807
+ const ship = deps.ship ?? ((m: PodPoolMember, img: string, commit: string | null, remote: RemoteRun) =>
808
+ syncPoolImage(m, img, commit, { run: remote, inspect: deps.inspect, transfer: deps.transfer }));
740
809
  const results = new Map<string, PoolImageSync>();
741
810
  // pack 한 번 ⊕ 나눠 쓰기 — 원격 멤버가 둘 이상일 때만(하나뿐이면 종전대로 build.sh 가 스스로 pack 한다).
742
811
  // 주입된 remoteBuild(시험)에는 진짜 pack 을 붙이지 않는다 — pack 도 주입해야 쓴다.