elanous 0.2.32 → 0.2.34

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 (633) 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/{IVKr3AlRUVLKsw2fh7eXF → L04y73dlwKeTW-GetaTF3}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +79 -0
  5. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +94 -0
  8. package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 1644.35dd25240ae24e4b.js} +2 -2
  9. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 1895-60ed0e341c658bd4.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 2124.ed5bf480cea7f85b.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +23 -0
  13. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +115 -0
  15. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +8 -0
  16. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 2547.dd27303624cb4da8.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 2554.3b5e200f5f5cfcd6.js} +16 -16
  19. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 2987-30cf9c2eb7b8bdd5.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{3541-ce3a5424ed5ad7f1.js → 3001-5a52788c813b6113.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +34 -0
  30. package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 3110.0a7065f25c841818.js} +17 -17
  31. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3121.779fafe3e44612c5.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 3414.172ad4ca2d9b08e8.js} +2 -2
  37. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{4745.67d6f99c245af3f7.js → 3498.cf2a15a8a9e5b926.js} +3 -3
  39. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +32 -0
  41. package/apps/pwa/out/_next/static/chunks/{5543.a438b8ab5a13ea47.js → 3837.722e053fb9f321ad.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +104 -0
  44. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +286 -0
  45. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +149 -0
  46. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +148 -0
  47. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +64 -0
  48. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +74 -0
  51. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → 4fa33ebd.21c1bd5b294496e6.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 5014f970-22bef0b5210f7d60.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/{2112-e4efc21a6505d5bc.js → 5028-f0722e6114c313e7.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/{2898.fd781bc7cf01a7b7.js → 5249.96a848656b582a93.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +62 -0
  60. package/apps/pwa/out/_next/static/chunks/{9407.e49124dedf0f5e72.js → 5446.edf141cff9ef647d.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9002.e5658224e3dc1b6f.js → 5489.ec2dd1b5272a19dc.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 5576-82d3703636d5c4b9.js} +3 -3
  63. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 6086.913a69e6fa3e4a8b.js} +4 -4
  70. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +77 -0
  76. package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 6740.43de73fc427c9fe2.js} +1 -1
  77. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +90 -0
  80. package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7005.1623d2aea78eb85f.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +287 -0
  87. package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 7431.3051e9b8a4372d2d.js} +2 -2
  88. package/apps/pwa/out/_next/static/chunks/{3583.a05e88cc8d594628.js → 7448.478958ffbbba0ac0.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +41 -0
  91. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +27 -0
  94. package/apps/pwa/out/_next/static/chunks/{9989.3694300e5f000b14.js → 7952.b192c31b6a0e00cc.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +36 -0
  97. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 8368.014caa8de2f5af34.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 8548.036c344973968847.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 9131-fce7256c4180c4a5.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +93 -0
  114. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +24 -0
  116. package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9550.d5f76828f972058c.js} +2 -2
  117. package/apps/pwa/out/_next/static/chunks/{2534.e85ae21ad0dac829.js → 9739.8d5f36ac67a3b236.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → 9a8cb466.cc9fc9e6e46038aa.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → 9b48c871.204d5d13e7809bd0.js} +7 -7
  123. package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → abb4b98b.163e0f56e84ae35d.js} +1 -1
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-8c66a3b24a745630.js → page-398c0faa173203f7.js} +1 -1
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-df3445b207ceceab.js} +1 -1
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{ebc7d829.264a0bcb6c750b50.js → ffdc3a04.b9c23c1b28dd4a96.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +1 -0
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/bin/elanous.mjs +9 -2
  278. package/docs/goal-context/README.md +1 -0
  279. package/graphs/default-loop.yaml +20 -3
  280. package/graphs/document-loop.yaml +21 -2
  281. package/graphs/implement-loop.yaml +6 -0
  282. package/graphs/journey/SCENARIOS.md +33 -0
  283. package/graphs/journey/recipes.yaml +1 -0
  284. package/graphs/journey/ta-journey.yaml +84 -0
  285. package/graphs/journey/units/author/author.yaml +20 -0
  286. package/graphs/journey/units/author/recipes.yaml +2 -0
  287. package/graphs/journey/units/green/green.yaml +20 -0
  288. package/graphs/journey/units/green/recipes.yaml +2 -0
  289. package/graphs/journey/units/pr/pr.yaml +20 -0
  290. package/graphs/journey/units/pr/recipes.yaml +2 -0
  291. package/graphs/journey/units/remember/recipes.yaml +2 -0
  292. package/graphs/journey/units/remember/remember.yaml +20 -0
  293. package/graphs/operate-loop.yaml +21 -2
  294. package/graphs/overlays/stop-heal-ladder.yaml +1 -1
  295. package/graphs/release-rehearsal/recipes.yaml +1 -1
  296. package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
  297. package/graphs/research-loop.yaml +23 -2
  298. package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
  299. package/graphs/units/dispatch-pod/recipes.yaml +14 -0
  300. package/graphs/units/entry/entry.yaml +50 -0
  301. package/graphs/units/entry/recipes.yaml +14 -0
  302. package/graphs/units/harvest/harvest.yaml +25 -0
  303. package/graphs/units/harvest/recipes.yaml +4 -0
  304. package/graphs/units/land/land.yaml +45 -0
  305. package/graphs/units/land/recipes.yaml +3 -0
  306. package/graphs/units/recipes.yaml +7 -0
  307. package/graphs/units/recover.yaml +39 -0
  308. package/graphs/units/reflect/recipes.yaml +3 -0
  309. package/graphs/units/reflect/reflect.yaml +15 -0
  310. package/graphs/units/task-agent-recover-review.yaml +17 -0
  311. package/graphs/units/task-agent-recover-wait.yaml +17 -0
  312. package/graphs/units/verbs/make-doc.yaml +34 -0
  313. package/graphs/units/verbs/recipes.yaml +33 -0
  314. package/graphs/units/verbs/verify.yaml +55 -0
  315. package/graphs/work/recipes.yaml +2 -0
  316. package/graphs/work/research-report.yaml +28 -0
  317. package/package.json +1 -1
  318. package/scripts/ci-typecheck-changed.ts +69 -16
  319. package/scripts/docs/generate-graph-anatomy.ts +19 -2
  320. package/scripts/graph-harvest-unit.ts +22 -0
  321. package/scripts/graph-units/journey-stub.ts +6 -0
  322. package/scripts/graph-units/land-enqueue.ts +78 -0
  323. package/scripts/graph-units/recover-plan.ts +15 -0
  324. package/scripts/graph-units/reflect-node.ts +88 -0
  325. package/scripts/graph-units/ta-journey-observe.ts +109 -0
  326. package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
  327. package/scripts/graph-units/verbs/verify-stage.ts +75 -0
  328. package/scripts/graph-units/verbs-envelope.ts +139 -0
  329. package/scripts/hq/standby-snapshot.ts +25 -0
  330. package/scripts/public-export.ts +43 -1
  331. package/scripts/ratchets/train-side-invariants.sh +45 -0
  332. package/scripts/release-loop/auto-approve-node.ts +30 -16
  333. package/scripts/release-loop/gate-closure.ts +5 -1
  334. package/scripts/release-loop/gate-diff.ts +1 -1
  335. package/scripts/release-loop/gate-node.ts +498 -31
  336. package/scripts/release-loop/gate-partial.ts +3 -3
  337. package/scripts/release-loop/gate-radius-shadow.ts +138 -0
  338. package/scripts/release-loop/gate-traffic-mode.ts +128 -0
  339. package/scripts/release-loop/gate-triage-node.ts +5 -2
  340. package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
  341. package/scripts/release-loop/known-issues-node.ts +77 -8
  342. package/scripts/release-loop/preflight.ts +93 -7
  343. package/scripts/release-loop/publish-node.ts +60 -9
  344. package/scripts/release-loop/resume-cap.ts +56 -0
  345. package/scripts/release-loop/resume-release.ts +114 -15
  346. package/scripts/release-loop/resume.ts +24 -1
  347. package/scripts/release-loop/tui-sim-node.ts +8 -2
  348. package/scripts/release-loop/unattended-release.ts +8 -2
  349. package/src/acp/core-turn-bridge.ts +20 -5
  350. package/src/acp/reasoning-thought-buffer.ts +45 -0
  351. package/src/agent-substrate/acp-reviewer.ts +52 -12
  352. package/src/agent-substrate/review-finding-key.ts +53 -0
  353. package/src/agent-substrate/self-review-cli.ts +126 -5
  354. package/src/ask-user-question/pending-questions.ts +1 -1
  355. package/src/autopilot/pr-manager.ts +192 -43
  356. package/src/chat/tool-render/dispatch.ts +62 -10
  357. package/src/cli/control-cli.ts +24 -7
  358. package/src/cli/guardian-cli.ts +10 -0
  359. package/src/cli/light-entry-route.ts +35 -0
  360. package/src/cli/llm-detect-cli.ts +23 -1
  361. package/src/cli/pr-cli.ts +76 -12
  362. package/src/cli/pr-land-base-read.ts +2 -0
  363. package/src/cli/pr-land-overlap-evidence.ts +154 -16
  364. package/src/cli/pr-land-recovery.ts +64 -0
  365. package/src/cli/pty-takeover-cli.ts +6 -5
  366. package/src/cli/release-cli.ts +120 -33
  367. package/src/cli/release-run-if-ready.ts +29 -28
  368. package/src/cli/release-single-flight.ts +178 -0
  369. package/src/cli/seat-cli.ts +37 -0
  370. package/src/cli/setup-cli.ts +40 -1
  371. package/src/cli/tasks-cli.ts +149 -5
  372. package/src/control/control-status.ts +8 -3
  373. package/src/control-plane/ledger.ts +5 -3
  374. package/src/control-plane/server.ts +5 -3
  375. package/src/core-turn/short-question.ts +5 -1
  376. package/src/dashboard/index.ts +36 -67
  377. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
  378. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  379. package/src/dashboard/input/seat-autowake.ts +56 -3
  380. package/src/dashboard/seat-boot-preamble.ts +1 -1
  381. package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
  382. package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
  383. package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
  384. package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
  385. package/src/dashboard/turn-preamble.ts +47 -1
  386. package/src/dashboard/turn-stream-formatter.ts +34 -1
  387. package/src/dashboard/turn-stream-runtime.ts +2 -0
  388. package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
  389. package/src/domains/guardian-tick.ts +54 -2
  390. package/src/domains/outbound-alert.ts +3 -2
  391. package/src/extractors.ts +3 -1
  392. package/src/git-fs/retry.ts +4 -0
  393. package/src/git-fs/runner.ts +2 -0
  394. package/src/graph-runner/runner.ts +114 -44
  395. package/src/grok/credential.ts +5 -0
  396. package/src/harness/harness-cli-command.ts +39 -10
  397. package/src/harness/harness-incidents.ts +4 -0
  398. package/src/harness/harness-pod-dispatch.ts +38 -1
  399. package/src/harness/harness-salvage-cli.ts +14 -2
  400. package/src/index.ts +192 -8
  401. package/src/intake-plane/already-built-hint.ts +89 -0
  402. package/src/knowhow/pack.ts +199 -0
  403. package/src/light-cli.ts +95 -0
  404. package/src/llm.ts +55 -9
  405. package/src/loops/budget.ts +95 -0
  406. package/src/loops/msg-wake.ts +8 -2
  407. package/src/loops/orchestrator/traffic.ts +132 -1
  408. package/src/mss/logging/log-store.ts +4 -5
  409. package/src/nexus/api/graphs-api.ts +22 -3
  410. package/src/nexus/api/http-server.ts +1 -1
  411. package/src/nexus/api/ops-api.ts +12 -0
  412. package/src/oauth/claude-pty-maturity.ts +66 -0
  413. package/src/oauth/codex-access-mirror.ts +55 -0
  414. package/src/oauth/fallback-chain.ts +1 -1
  415. package/src/onboarding/first-run.ts +5 -3
  416. package/src/onboarding/non-interactive.ts +64 -13
  417. package/src/onboarding.ts +10 -2
  418. package/src/ops/overview-collect.ts +36 -1
  419. package/src/ops/overview.ts +11 -0
  420. package/src/pr-tool/census.ts +23 -5
  421. package/src/pr-tool/inflight-registry.ts +160 -7
  422. package/src/prompt-library/gpt6-family-addendum.ts +14 -1
  423. package/src/pty-shell/herdr-agent-report.ts +442 -0
  424. package/src/pty-shell/pty-control-ipc.ts +5 -5
  425. package/src/pty-shell/pty-write-outcome.ts +24 -6
  426. package/src/pty-shell/tui-run-state.ts +117 -3
  427. package/src/release-loop/checklist.ts +79 -5
  428. package/src/release-loop/feature-store.ts +19 -2
  429. package/src/release-loop/placement.ts +10 -3
  430. package/src/release-loop/rehearsal.ts +205 -25
  431. package/src/release-loop/rubric.ts +16 -2
  432. package/src/self-dev/draft-sweep.ts +52 -3
  433. package/src/self-dev/graph-journey-nodes.ts +10 -6
  434. package/src/self-dev/graph-journey-route.ts +60 -6
  435. package/src/self-dev/orchestrate.ts +79 -3
  436. package/src/self-dev/run-supervisor.ts +107 -12
  437. package/src/self-dev/run-types.ts +5 -1
  438. package/src/self-implement/gate-baseline.ts +49 -5
  439. package/src/self-implement/gate-remote.ts +9 -5
  440. package/src/self-implement/goal-author-identity.ts +66 -0
  441. package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
  442. package/src/self-implement/goal-author.ts +4 -120
  443. package/src/self-implement/graph-overlay-yaml.ts +17 -2
  444. package/src/self-implement/graph-unit-flatten.ts +103 -0
  445. package/src/self-implement/graph-unit-resolver.ts +107 -0
  446. package/src/self-implement/graph-yaml.ts +151 -1
  447. package/src/self-implement/headless-elanous-driver.ts +1 -0
  448. package/src/self-implement/knowhow-pack.ts +103 -0
  449. package/src/self-implement/orchestrator.ts +8 -0
  450. package/src/self-implement/pod-warm-pool-profile.ts +45 -0
  451. package/src/self-implement/review-mustfix-class.ts +203 -0
  452. package/src/self-implement/run-stop.ts +8 -2
  453. package/src/self-implement/seams.ts +32 -1
  454. package/src/self-implement/stop-autoheal.ts +25 -1
  455. package/src/session/chat.ts +27 -0
  456. package/src/session-runtime/retry-policy.ts +2 -1
  457. package/src/skills/tools/schedule-wakeup.ts +66 -17
  458. package/src/steward/release-day.ts +7 -3
  459. package/src/steward/triage.ts +37 -4
  460. package/src/task-agent/harvest-unit.ts +141 -0
  461. package/src/task-agent/live-moves.ts +98 -12
  462. package/src/task-agent/parent-host.ts +93 -3
  463. package/src/task-agent/postland-card.ts +80 -1
  464. package/src/task-agent/rejudge-on-head.ts +112 -26
  465. package/src/task-agent/repair-branch-cas.ts +4 -1
  466. package/src/task-agent/repair-cycle.ts +16 -3
  467. package/src/task-agent/run-identity.ts +4 -3
  468. package/src/task-agent/shadow.ts +12 -2
  469. package/src/task-agent/task-hand.ts +54 -7
  470. package/src/task-agent/work-order-build.ts +22 -0
  471. package/src/task-orchestrator/surfaces/pod-account-broker.ts +39 -3
  472. package/src/task-orchestrator/surfaces/pod-command-job.ts +2 -1
  473. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
  474. package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
  475. package/src/task-orchestrator/surfaces/pod-source-receive.ts +54 -4
  476. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +26 -3
  477. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +389 -0
  478. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
  479. package/src/task-orchestrator/surfaces/self-implement-pod.ts +223 -38
  480. package/src/task-orchestrator/surfaces/self-implement.ts +83 -2
  481. package/src/tool-runtime/truncation-store.ts +4 -0
  482. package/src/tui-client/dashboard-session.ts +10 -1
  483. package/src/user-config/coercion.ts +36 -0
  484. package/src/user-config.ts +18 -41
  485. package/src/ux-sim/scenario.ts +72 -13
  486. package/src/version/packed-revision.json +1 -1
  487. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
  490. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
  491. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
  492. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
  496. package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
  498. package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
  499. package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
  506. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
  507. package/apps/pwa/out/_next/static/chunks/3267c0e6.d34854e7b3984a6e.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +0 -34
  510. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
  514. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
  518. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
  519. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
  521. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
  524. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
  529. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
  531. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
  538. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
  539. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
  541. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
  546. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
  547. package/apps/pwa/out/_next/static/chunks/69-0a2c8209c6d4a158.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
  555. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/control/page-a27b1e5a0d1b308f.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/morning/page-32866485913d6a04.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
  625. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
  632. package/src/cli/g6a-registration-probe.ts +0 -16
  633. /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → L04y73dlwKeTW-GetaTF3}/_ssgManifest.js +0 -0
@@ -12,7 +12,7 @@
12
12
  // 부작용(kubectl·파일)은 주입받는다 — 시험은 가짜 kubectl 로 누른다.
13
13
 
14
14
  import { podSkillsDigest, readSkillEnvFiles, resolvePodSkills } from './pod-skills.js';
15
- import { emitPodLifecycle, parseSiTaskPodStages, siTaskPodLifecycleEvent, siTaskPodStageShell } from './pod-lifecycle-stages.js';
15
+ import { emitPodLifecycle, parseSiTaskDepsSkipped, parseSiTaskPodStages, siTaskPodK8sTiming, siTaskPodLifecycleEvent, siTaskPodStageShell } from './pod-lifecycle-stages.js';
16
16
  import { podSourceScript, type PodSource } from './pod-source-receive.js';
17
17
  import { GROUNDING_TOKEN_ENV, GROUNDING_URL_ENV, mintGroundingToken, revokeGroundingRun, type GroundingTokenScope } from '../../grounding/token.js';
18
18
  import { POD_CREDENTIAL_GROK_PATH, POD_CREDENTIAL_GITHUB_PATH, POD_GITHUB_CREDENTIAL_TOKEN_ENV, POD_GITHUB_CREDENTIAL_URL_ENV, installationRepositories } from '../../nexus/api/pod-credential-api.js';
@@ -22,6 +22,7 @@ import { collectPodLedgers, createPodLedgerFollower } from './pod-ledger-collect
22
22
  import { collectPodArtifacts, podNoResultDiagnostic } from './pod-artifact-return.js';
23
23
  import { readPodRepairArtifact } from './pod-repair-commit.js';
24
24
  import { isValidAccountName, resolveCodexAccount } from '../../oauth/codex-account.js';
25
+ import { createCodexAccessMirror } from '../../oauth/codex-access-mirror.js';
25
26
  import { effectiveInstanceRoot } from '../../instance/resolve.js';
26
27
  import { controlInboxEnv } from '../../harness/control-inbox.js';
27
28
  import { finishPodFragment, writePodFragment } from '../../harness/self-send-target.js';
@@ -97,9 +98,15 @@ import { classifyPodExit, extractPodFailureReason, podTerminalRow, type PodExitC
97
98
  import { kubectlTransientReason, retryKubectlTransient } from './kubectl-transient-retry.js';
98
99
  import { OLD_DOOR_STAMP_ENV } from '../../self-dev/old-door.js';
99
100
  import { resolveDefaultSourceHead, seedMirrorOnce, type MirrorSeedResult } from './pod-mirror-seed.js';
101
+ import { decideWarmReuse, type WarmReuseEvidenceByConsumer, type WarmReuseSwitchConfig } from './pod-warm-switch.js';
102
+ import type { WarmWorkerCommand } from './pod-warm-worker-protocol.js';
103
+ import type { WarmPodTransportResult } from './pod-warm-worker-pod.js';
100
104
 
101
105
  export type Kubectl = (args: readonly string[], input?: string) => { status: number | null; stdout: string; stderr: string };
102
106
 
107
+ /** TC supplies the validated candidate/lease transport. UX only forwards its request command. */
108
+ export type WarmPodRequestHook = (request: { command: WarmWorkerCommand }) => Promise<WarmPodTransportResult> | WarmPodTransportResult;
109
+
103
110
  // gh auth login may reject installation tokens when validating /user. Its config is
104
111
  // still the credential source for gh and setup-git's helper. Install it privately
105
112
  // on that failure; rename keeps concurrent readers from seeing a partial token.
@@ -148,6 +155,11 @@ export interface PodSpawnOptions {
148
155
  seedMirror?: (o: { host: string; commit: string; cwd: string }) => Promise<MirrorSeedResult | undefined>;
149
156
  /** Git tree that has the pinned commit for the mirror seed (default: process.cwd()). */
150
157
  mirrorSeedCwd?: string;
158
+ /** TA warm-reuse shadow evidence/config seams. Missing evidence must stay off; no warm candidate is consumed here. */
159
+ warmReuseConfig?: () => WarmReuseSwitchConfig | undefined;
160
+ warmReuseEvidence?: () => WarmReuseEvidenceByConsumer | undefined;
161
+ /** Optional warm-pool observation/preparation hook. It never replaces the feature implementation Job. */
162
+ warmPodRequest?: WarmPodRequestHook;
151
163
  /** SI-SEED-DEFAULT — resolves a default source's branch tip for the mirror seed (test seam · default
152
164
  * {@link resolveDefaultSourceHead}; none with an injected kubectl unless given). */
153
165
  resolveSourceHead?: (o: { repoUrl: string; base?: string; cwd: string }) => Promise<{ sha?: string; reason?: string }>;
@@ -423,7 +435,7 @@ async function defaultHqLeaseHolder(): Promise<boolean> {
423
435
  }
424
436
 
425
437
  /** 호스트 계정 → refresh 없는 사본(elanous 저장소 ⊕ codex auth.json) ⊕ gh 토큰. */
426
- export function hostCredentials(account: string, storePath: string = authStorePath(), ghToken: () => string = defaultGhToken): { elanousAuth: string; codexAuth: string; ghToken: string } {
438
+ export function hostCredentials(account: string, storePath: string = authStorePath(), ghToken: () => string = defaultGhToken, options: { requireExplicitChatgptAuthMode?: boolean } = {}): { elanousAuth: string; codexAuth: string; ghToken: string } {
427
439
  // 경로는 해석기로(격리 게이트 · 2026-09-25) — 손으로 `~/.elanous/auth.json` 을 조립하면 test↔prod 격리가 새는 자리가 된다.
428
440
  const store = JSON.parse(readFileSync(storePath, 'utf8')) as { version?: number; providers: Record<string, Record<string, unknown>> };
429
441
  // ⭐ 기본 계정은 정본 키가 `openai-codex`(이름 없음)이고 홈을 안 적는다 — 기본 위치로 푼다(회전 후보와 같은 해석).
@@ -431,22 +443,70 @@ export function hostCredentials(account: string, storePath: string = authStorePa
431
443
  const entry = store.providers[storeKey] as { tokens: Record<string, unknown>; lastRefresh?: string; authMode?: string; codexHome?: string } | undefined;
432
444
  const codexHome = entry?.codexHome ?? (entry && account === 'default' ? resolveCodexAccount(envLiteral({ CODEX_HOME: process.env.CODEX_HOME })).home : undefined);
433
445
  if (!entry || !codexHome) throw new Error(`${storeKey} 계정이 없거나 codexHome 을 모른다`);
434
- const codex = JSON.parse(readFileSync(join(codexHome, 'auth.json'), 'utf8')) as { tokens: Record<string, unknown> };
435
- const access = String(codex.tokens.access_token ?? '');
436
- const exp = Number(JSON.parse(Buffer.from(access.split('.')[1] ?? '', 'base64url').toString('utf8') || '{}').exp ?? 0);
437
- if (exp * 1000 - Date.now() < 3 * 3600_000) throw new PodCodexExpiringError(account, Math.round(((exp * 1000 - Date.now()) / 3_600_000) * 10) / 10);
438
- const elanousAuth = JSON.stringify({
439
- version: store.version ?? 1,
440
- // ⭐ P4(2026-09-26): elanous 사본도 «방금 검사한» codex 홈의 토큰으로 싣는다 — 두 저장소는 따로 갱신된다.
441
- // 🩸 실측: third 는 elanous 쪽 토큰이 4시간 전에 만료됐고 codex 홈 쪽은 235시간 남아 있었다 → Pod 가 갱신 400 으로 첫 호출 전에 죽었다(할당량 소진으로 오분류).
442
- providers: { 'openai-codex': { tokens: { ...entry.tokens, accessToken: access, expiresAt: exp * 1000, refreshToken: '' }, lastRefresh: entry.lastRefresh, authMode: entry.authMode, chatGPT: { accountId: codex.tokens.account_id } } },
443
- });
444
- const codexAuth = JSON.stringify({ ...codex, tokens: { ...codex.tokens, refresh_token: '' } });
445
- return { elanousAuth, codexAuth, ghToken: ghToken() };
446
+ const codex = JSON.parse(readFileSync(join(codexHome, 'auth.json'), 'utf8')) as { auth_mode?: string; tokens: Record<string, unknown> };
447
+ // Remote parents must not infer this from store metadata; ordinary Pod callers retain the legacy fallback.
448
+ if (options.requireExplicitChatgptAuthMode && codex.auth_mode !== 'chatgpt') throw new Error(`${storeKey} Codex CLI auth_mode must be explicitly chatgpt for remote parent`);
449
+ const mirror = createCodexAccessMirror({ account, store, codexAuth: codex });
450
+ const hoursLeft = (mirror.expiresAt - Date.now()) / 3_600_000;
451
+ if (hoursLeft < 3) throw new PodCodexExpiringError(account, Math.round(hoursLeft * 10) / 10);
452
+ // ⭐ P4(2026-09-26): both stores use the just-checked Codex access token; the stores refresh independently.
453
+ return { elanousAuth: mirror.elanousAuth, codexAuth: mirror.codexAuth, ghToken: ghToken() };
454
+ }
455
+
456
+ /** POD-GROK-VALIDITY-FIT (10-17) — the Pod gets a refresh-less grok access copy, so the copy must outlive the Job.
457
+ * It used to require 3 h (= the full POD_JOB_DEADLINE_SECONDS), but the token lives only 6 h and the grok CLI renews it
458
+ * only right before expiry (`grok models`/`grok -p` leave `expires_at` unchanged — node-b refreshOutcome:"unchanged"), and
459
+ * the CLI has no forced-refresh command (`grok --help`/`grok login --help` 10-17: login·logout only). So half of every
460
+ * day refused grok Pod launches (10-17 node-b·node-c·mbp 9 no-launch · 3 hand re-logins).
461
+ * ⇒ The Job is fitted to the token instead: a launch is allowed when the token has at least a minimum Job
462
+ * (POD_GROK_MIN_JOB_SECONDS) plus a margin left, and that launch's `activeDeadlineSeconds` is cut to the token's
463
+ * remaining life minus the margin (`fitPodDeadlineToGrok`) — so a long run ends as a classified DeadlineExceeded
464
+ * instead of a silent mid-run 401. With the host credential relay (pod.groundingUrl) the Pod renews mid-run and
465
+ * nothing is cut. 90 min = the Job cap before 대표 09-26 raised it (only two runs had reached it). */
466
+ export const POD_GROK_MIN_JOB_SECONDS = 90 * 60;
467
+ /** Slack between the fitted Job end and the token expiry (clock skew · Pod scheduling). */
468
+ export const POD_GROK_EXPIRY_MARGIN_MS = 15 * 60_000;
469
+ /** Minimum remaining token life for a grok Pod launch = minimum Job + margin (1 h 45 m). */
470
+ export const POD_GROK_MIN_VALIDITY_MS = POD_GROK_MIN_JOB_SECONDS * 1000 + POD_GROK_EXPIRY_MARGIN_MS;
471
+
472
+ /** «1h45m» · «20m» · «만료» — remaining-time text for refusal lines (no token value). */
473
+ export function formatGrokRemaining(ms: number | null): string {
474
+ if (ms === null || !Number.isFinite(ms)) return '알 수 없음';
475
+ if (ms <= 0) return '만료됨';
476
+ const m = Math.floor(ms / 60_000);
477
+ return m >= 60 ? `${Math.floor(m / 60)}h${String(m % 60).padStart(2, '0')}m` : `${m}m`;
478
+ }
479
+
480
+ /** Latest `expires_at` among scopes that carry an access key (the token the Pod would get). */
481
+ function grokSubscriptionExpiresAtMs(home?: string): number | null {
482
+ try {
483
+ const scopes = JSON.parse(readFileSync(grokAuthFilePath(home), 'utf8')) as Record<string, { key?: unknown; expires_at?: unknown }>;
484
+ const all = Object.values(scopes).flatMap((s) => (s && typeof s.key === 'string' && s.key && typeof s.expires_at === 'string' && Number.isFinite(Date.parse(s.expires_at)) ? [Date.parse(s.expires_at)] : []));
485
+ return all.length ? Math.max(...all) : null;
486
+ } catch { return null; }
487
+ }
488
+
489
+ /** POD-GROK-VALIDITY-FIT — this launch's Job deadline for a refresh-less grok subscription copy.
490
+ * · relay (the Pod can renew from the host) or unknown expiry → the requested deadline as is.
491
+ * · otherwise → min(requested, remaining − margin); below the minimum Job (time passed since the credential check)
492
+ * the launch is refused — the deadline never outlives the token. */
493
+ export function fitPodDeadlineToGrok(o: { requestedSeconds: number; expiresAtMs: number | null; nowMs: number; relay: boolean }):
494
+ { refused: false; deadlineSeconds: number; fitted: boolean; availableSeconds: number | null } | { refused: true; availableSeconds: number } {
495
+ if (o.relay || o.expiresAtMs === null || !Number.isFinite(o.expiresAtMs)) return { refused: false, deadlineSeconds: o.requestedSeconds, fitted: false, availableSeconds: null };
496
+ const availableSeconds = Math.floor((o.expiresAtMs - o.nowMs - POD_GROK_EXPIRY_MARGIN_MS) / 1000);
497
+ if (availableSeconds < POD_GROK_MIN_JOB_SECONDS) return { refused: true, availableSeconds };
498
+ if (availableSeconds >= o.requestedSeconds) return { refused: false, deadlineSeconds: o.requestedSeconds, fitted: false, availableSeconds };
499
+ return { refused: false, deadlineSeconds: availableSeconds, fitted: true, availableSeconds };
500
+ }
501
+
502
+ /** Expiry of the access the Pod will actually use — only scopes with a key, latest wins (same rule as the Pod reader). */
503
+ export function shippedGrokExpiresAtMs(grokAuth: string): number | null {
504
+ try {
505
+ const scopes = JSON.parse(grokAuth) as Record<string, { key?: unknown; expires_at?: unknown }>;
506
+ const all = Object.values(scopes).flatMap((sc) => (sc && typeof sc.key === 'string' && sc.key && typeof sc.expires_at === 'string' && Number.isFinite(Date.parse(sc.expires_at)) ? [Date.parse(sc.expires_at)] : []));
507
+ return all.length ? Math.max(...all) : null;
508
+ } catch { return null; }
446
509
  }
447
-
448
- /** A Pod gets a refresh-less access copy, so the copy must outlive the Job: same rule as the Codex path (3 h). */
449
- export const POD_GROK_MIN_VALIDITY_MS = 3 * 3600_000;
450
510
  /** PODCRED1 (10-05): an App installation token lives ~60 min and the host renews it in the Pod at the ten-minute
451
511
  * boundary; below this remaining life at launch the token is observed (`github-app-short-lived`). */
452
512
  export const POD_APP_TOKEN_MIN_START_MS = 20 * 60_000;
@@ -466,13 +526,21 @@ export function hostGrokCredentials(opts: {
466
526
  home?: string; env?: NodeJS.ProcessEnv; apiKeyOptIn?: boolean; ghToken?: () => string;
467
527
  /** Test seams — the host refresh (read-only `grok models`) and the expiry probe. */
468
528
  refresh?: () => void; isExpiring?: () => boolean;
529
+ /** Required remaining token life (default POD_GROK_MIN_VALIDITY_MS) — a caller whose Job is not fitted passes its own deadline. */
530
+ minValidityMs?: number; now?: () => number;
469
531
  } = {}): { grokAuth?: string; grokApiKey?: string; ghToken: string } {
470
532
  let credential = resolveGrokCredential({ home: opts.home, env: opts.env });
471
533
  if (credential?.kind === 'subscription') {
472
- const expiring = opts.isExpiring ?? (() => isGrokSubscriptionExpiring({ home: opts.home, bufferMs: POD_GROK_MIN_VALIDITY_MS }));
534
+ const minValidityMs = opts.minValidityMs ?? POD_GROK_MIN_VALIDITY_MS;
535
+ const expiring = opts.isExpiring ?? (() => isGrokSubscriptionExpiring({ home: opts.home, bufferMs: minValidityMs, ...(opts.now ? { now: opts.now } : {}) }));
473
536
  if (expiring()) {
474
537
  try { (opts.refresh ?? (() => { refreshGrokSubscriptionToken({ home: opts.home }); }))(); } catch { /* judged below */ }
475
- if (expiring()) throw new Error('grok: 구독 access 토큰이 3시간 안에 만료 — 호스트 갱신(grok models)도 못 늘렸다 · 호스트에서 grok login 후 다시');
538
+ if (expiring()) {
539
+ const at = grokSubscriptionExpiresAtMs(opts.home);
540
+ const remainingMs = at === null ? null : at - (opts.now ?? Date.now)();
541
+ try { debug.log('pod.grok-credentials', 'refused', { remainingMs, minValidityMs, expiresAt: at === null ? null : new Date(at).toISOString() }); } catch { /* fail-soft */ }
542
+ throw new Error(`grok: 구독 access 토큰 남은 시간 ${formatGrokRemaining(remainingMs)} < Pod 발사 기준 ${formatGrokRemaining(minValidityMs)} — 호스트 갱신(grok models)도 못 늘렸다 · 다음: 호스트에서 grok login --device-auth 후 다시`);
543
+ }
476
544
  credential = resolveGrokCredential({ home: opts.home, env: opts.env });
477
545
  if (credential?.kind !== 'subscription') throw new Error('grok: 갱신 뒤 구독 자격을 다시 읽지 못했다');
478
546
  }
@@ -554,9 +622,12 @@ export function grokLaunchReadiness(opts: { home?: string; env?: NodeJS.ProcessE
554
622
  }
555
623
 
556
624
  /** The one launch line for a skipped grok copy — the reader sees why grok left this run's chain. */
557
- export function podGrokSkippedLine(skip: { reason: PodGrokSkipReason; expiresAt: string | null }): string {
625
+ export function podGrokSkippedLine(skip: { reason: PodGrokSkipReason; expiresAt: string | null }, now?: () => number): string {
558
626
  const why = skip.reason === 'missing' ? '구독 자격 없음' : skip.reason === 'expiring' ? '만료 임박' : '만료 임박 · 호스트 갱신 실패';
559
- return `⚠️ grok 자격 없음(${why}${skip.expiresAt ? ` · 만료 ${skip.expiresAt}` : ''}) — 이 런의 폴백 체인에서 grok 을 뺐다`;
627
+ const at = skip.expiresAt ? Date.parse(skip.expiresAt) : NaN;
628
+ const left = skip.reason !== 'missing' && Number.isFinite(at) ? ` · 남은 ${formatGrokRemaining(at - (now ?? Date.now)())} < 기준 ${formatGrokRemaining(POD_GROK_MIN_VALIDITY_MS)}` : '';
629
+ const next = skip.reason === 'missing' ? '' : ' · 다음: 호스트에서 grok login --device-auth';
630
+ return `⚠️ grok 자격 없음(${why}${skip.expiresAt ? ` · 만료 ${skip.expiresAt}` : ''}${left}) — 이 런의 폴백 체인에서 grok 을 뺐다${next}`;
560
631
  }
561
632
 
562
633
  /** 키 캐시 관례: `~/.cache/<env 이름 소문자>`(예: OPENROUTER_API_KEY → ~/.cache/openrouter_api_key · src/config.ts 와 같다). */
@@ -769,7 +840,7 @@ export const POD_ATTEMPT_ANNOTATION = 'elanous.dev/attempt';
769
840
  export function podRunLabels(o: { runId?: string; parentRunId?: string }): Record<string, string> {
770
841
  const run = k8sLabelValue(o.parentRunId ?? o.runId);
771
842
  const child = k8sLabelValue(o.runId);
772
- return { ...(run ? { 'elanous.run': run } : {}), ...(child && child !== run ? { 'elanous.child-run': child } : {}) };
843
+ return { ...(run ? { 'elanous.run': run } : {}), ...(child ? { 'elanous.child-run': child } : {}) };
773
844
  }
774
845
 
775
846
  /** Pod 메모리 «등급» — 대표 09-27: PWA Pod 골이 16Gi 에서 OOM 으로 죽는다 ⇒ «high» 등급을 옵션으로 고른다.
@@ -998,7 +1069,7 @@ export function podSigtermTrapScript(seqFile: string = POD_USAGE_PARTIAL_SEQ_FIL
998
1069
  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`;
999
1070
  }
1000
1071
 
1001
- export function podJobManifest(o: { name: string; namespace: string; image: string; workIdentity?: PodWorkIdentity; /** 레지스트리 이미지면 IfNotPresent(노드가 pull) · 반입 이미지면 Never. */ imagePullPolicy?: 'Never' | 'IfNotPresent'; repoUrl: string; source?: PodSource; repairCommitOnly?: { pr: number; baseHead: string }; 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; fallbackChain?: { steps: readonly FallbackStep[]; source: 'host' | 'default' }; /** TA-POD-WARMBOOT-PARITY — the child's final line (podResultMarkerShellLine), just before `exit $rc`. */ resultMarkerLine?: string }): Record<string, unknown> {
1072
+ export function podJobManifest(o: { name: string; namespace: string; image: string; workIdentity?: PodWorkIdentity; boundPrNumber?: number; /** 레지스트리 이미지면 IfNotPresent(노드가 pull) · 반입 이미지면 Never. */ imagePullPolicy?: 'Never' | 'IfNotPresent'; repoUrl: string; source?: PodSource; repairCommitOnly?: { pr: number; baseHead: string }; 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; /** Codex Job may use the same named Secret only for an explicitly admitted ZAI fallback. */ zaiFallback?: ZaiPodSpec; fallbackChain?: { steps: readonly FallbackStep[]; source: 'host' | 'default' }; /** TA-POD-WARMBOOT-PARITY — the child's final line (podResultMarkerShellLine), just before `exit $rc`. */ resultMarkerLine?: string }): Record<string, unknown> {
1002
1073
  if (o.repairCommitOnly && (o.source?.kind !== 'pr' || o.source.number !== o.repairCommitOnly.pr || !/^[0-9a-f]{40}$/.test(o.repairCommitOnly.baseHead) || o.args.includes('--open-pr') || o.args.includes('--merge-by-host') || o.args.includes('--auto-merge'))) {
1003
1074
  throw new Error('repair commit-only requires matching PR source and no PR/merge flags');
1004
1075
  }
@@ -1057,6 +1128,9 @@ export function podJobManifest(o: { name: string; namespace: string; image: stri
1057
1128
  siTaskPodStageShell('clone', 'start'),
1058
1129
  podSourceScript(o.source ?? { kind: 'default' }, o.repoUrl, undefined, { stageMarkers: true }),
1059
1130
  siTaskPodStageShell('clone', 'end'),
1131
+ // This image already contains runtime dependencies; there is no child install command.
1132
+ // Record that fact before the main command, without treating clone completion as install completion.
1133
+ `printf 'ELANOUS_POD_DEPS skipped %s image-prepared-no-install\\n' "$(date +%s)" || true`,
1060
1134
  ...(o.repairCommitOnly ? [`[ "$(git rev-parse HEAD)" = '${o.repairCommitOnly.baseHead}' ] || { echo 'ELANOUS_POD_REPAIR_FAILED source-head-mismatch'; exit 8; }`] : []),
1061
1135
  ...(goalPath ? [
1062
1136
  `mkdir -p -- "$(dirname -- ${goalPath})" && cp -- /creds/goal-doc ${goalPath} || exit 6`,
@@ -1151,7 +1225,7 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1151
1225
  return {
1152
1226
  apiVersion: 'batch/v1',
1153
1227
  kind: 'Job',
1154
- 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' } : {}) },
1228
+ metadata: { name: o.name, namespace: o.namespace, labels: { 'elanous.substrate': 'pod', 'elanous.job': o.name, ...podRunLabels(o), ...(o.workIdentity ? podWorkLabels(o.workIdentity) : {}), ...(o.zai || o.zaiFallback ? { [ZAI_POD_EGRESS_LABEL]: 'true' } : {}) },
1155
1229
  ...((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' } : {}) } } : {}) },
1156
1230
  spec: {
1157
1231
  backoffLimit: 0,
@@ -1159,7 +1233,7 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1159
1233
  activeDeadlineSeconds: o.deadlineSeconds,
1160
1234
  template: {
1161
1235
  // ⭐ Pod 라벨 — local 팔만 `elanous.egress/local-llm` 을 단다. docker/h1/policy-local-llm.yaml 이 그 라벨에만 호스트 LLM 포트 «하나»를 연다.
1162
- 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' } : {}) } },
1236
+ 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 || o.zaiFallback ? { [ZAI_POD_EGRESS_LABEL]: 'true' } : {}) } },
1163
1237
  spec: {
1164
1238
  restartPolicy: 'Never',
1165
1239
  securityContext: { runAsUser: 1000, fsGroup: 1000 },
@@ -1175,6 +1249,8 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1175
1249
  ...(o.runId ? [{ name: 'ELANOUS_RUN_ID', value: o.runId }] : []),
1176
1250
  ...(o.parentRunId ? [{ name: 'ELANOUS_PARENT_RUN_ID', value: o.parentRunId }] : []),
1177
1251
  ...(o.workIdentity?.taskCard ? [{ name: 'ELANOUS_TASK_CARD_ID', value: o.workIdentity.taskCard }] : []),
1252
+ ...(o.boundPrNumber && Number.isSafeInteger(o.boundPrNumber) && o.boundPrNumber > 0
1253
+ ? [{ name: 'ELANOUS_TASK_BOUND_PR', value: String(o.boundPrNumber) }] : []),
1178
1254
  ...(o.workIdentity?.slotId ? [{ name: 'ELANOUS_POD_SLOT_ID', value: o.workIdentity.slotId }] : []),
1179
1255
  { name: 'ELANOUS_SUBSTRATE', value: 'pod' },
1180
1256
  ...Object.entries(controlInboxEnv(POD_CONTROL_INBOX_DIR)).map(([name, value]) => ({ name, value })),
@@ -1189,7 +1265,7 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1189
1265
  ...Object.entries(o.armEnv ?? {}).map(([name, value]) => ({ name, value })),
1190
1266
  ...o.passEnv.map((key) => ({ name: key, valueFrom: { secretKeyRef: { name: `${o.name}-creds`, key: `env-${key}` } } })),
1191
1267
  ...(o.bedrock ? bedrockPodEnv(o.bedrock) : []),
1192
- ...(o.zai ? zaiPodEnv(o.zai) : []),
1268
+ ...(o.zai || o.zaiFallback ? zaiPodEnv(o.zai ?? o.zaiFallback!) : []),
1193
1269
  ],
1194
1270
  volumeMounts: [{ name: 'creds', mountPath: '/creds', readOnly: true }, ...(o.hostMirror ? [{ name: 'host-mirror', mountPath: '/host-mirror', readOnly: true }] : [])],
1195
1271
  }],
@@ -1342,9 +1418,9 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1342
1418
  const timer = setTimeout(() => {
1343
1419
  if (stalledStages.has(stage)) return;
1344
1420
  stalledStages.add(stage);
1345
- const pool = options.pool as { waitReason?: () => string | null } | undefined;
1421
+ const pool = options.pool as { waitReason?: (memoryLimit?: string) => string | null } | undefined;
1346
1422
  debug.log('harness.launch', 'launch-stalled', { spaceId: input.spaceId, runId: childRunId, stage, waitedSec: Math.round((Date.now() - started) / 1000),
1347
- reason: (stage === 'pool-slot' ? stageReason['pool-slot'] : (typeof pool?.waitReason === 'function' ? pool.waitReason() : null)) ?? 'not-measured-yet' }, { level: 'warn' });
1423
+ reason: (stage === 'pool-slot' ? stageReason['pool-slot'] : (typeof pool?.waitReason === 'function' ? pool.waitReason(memoryLimit) : null)) ?? 'not-measured-yet' }, { level: 'warn' });
1348
1424
  }, stallMs);
1349
1425
  (timer as { unref?: () => void }).unref?.();
1350
1426
  return () => clearTimeout(timer);
@@ -1387,7 +1463,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1387
1463
  const acquireAdmission = async (): Promise<boolean> => {
1388
1464
  if (!options.pool || typeof options.pool.acquireAdmission !== 'function') return true;
1389
1465
  const stop = watchStall('admission');
1390
- try { releaseAdmission = await options.pool.acquireAdmission(input.signal, after); return true; }
1466
+ try { releaseAdmission = await options.pool.acquireAdmission(input.signal, after, { memoryLimit }); return true; }
1391
1467
  catch (error) {
1392
1468
  // A predecessor closed without merging is not a cancellation: surface it so the queue owner is notified.
1393
1469
  if (error instanceof Error && error.message.startsWith('pod lease predecessor blocked')) admissionBlocked = error.message;
@@ -1432,7 +1508,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1432
1508
  const cleanupSecret = () => { kubectl(['-n', namespace, 'delete', 'secret', `${name}-creds`, '--ignore-not-found']); };
1433
1509
  let repairResultAnnounced = false;
1434
1510
  let repairArtifactReady = false;
1435
- const collectFullLogs = (unavailableEvent: string, replace?: ReadonlySet<string>, onEvent?: (event: string, data: Record<string, unknown>) => void, childId?: string): { status: 'ok' | 'unavailable' | 'incomplete'; childLedgerIncomplete: boolean; samples: ReturnType<typeof parseMemSamples>; podStages?: Record<string, number> } => {
1511
+ const collectFullLogs = (unavailableEvent: string, replace?: ReadonlySet<string>, onEvent?: (event: string, data: Record<string, unknown>) => void, childId?: string): { status: 'ok' | 'unavailable' | 'incomplete'; childLedgerIncomplete: boolean; samples: ReturnType<typeof parseMemSamples> } => {
1436
1512
  let full: ReturnType<Kubectl>;
1437
1513
  try {
1438
1514
  full = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
@@ -1442,10 +1518,12 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1442
1518
  debug.log('self-implement.pod', unavailableEvent, { job: name, reason: error instanceof Error ? error.message : String(error) });
1443
1519
  return { status: 'unavailable', childLedgerIncomplete: false, samples: [] };
1444
1520
  }
1445
- const via = /^ELANOUS_POD_SOURCE_VIA (mirror|github)\r?$/m.exec(full.stdout)?.[1];
1521
+ const via = /^ELANOUS_POD_SOURCE_VIA (image|mirror|github)\r?$/m.exec(full.stdout)?.[1];
1446
1522
  // #28246 names why the mirror was skipped on the line before `VIA github`; carry it on the same event.
1447
1523
  const mirrorSkip = /^ELANOUS_POD_SOURCE_MIRROR_SKIP (no-mount|rev-parse-failed|clone-failed)\r?$/m.exec(full.stdout)?.[1];
1448
- if (via) debug.log('self-implement.pod', 'source-via', { job: name, via, ...(mirrorSkip ? { mirrorSkip } : {}) });
1524
+ const imageSkip = /^ELANOUS_POD_SOURCE_IMAGE_SKIP ([^\r\n]+)\r?$/m.exec(full.stdout)?.[1];
1525
+ const delta = /^ELANOUS_POD_SOURCE_DELTA (mirror|origin)\r?$/m.exec(full.stdout)?.[1];
1526
+ if (via) debug.log('self-implement.pod', 'source-via', { job: name, via, ...(mirrorSkip ? { mirrorSkip } : {}), ...(imageSkip ? { imageSkip } : {}), ...(delta ? { delta } : {}) });
1449
1527
  let ledgerIncomplete = false;
1450
1528
  let childLedgerIncomplete = false;
1451
1529
  let artifactIncomplete = false;
@@ -1478,7 +1556,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1478
1556
  record('self-implement.pod', 'repair-artifact-incomplete', { job: name, reason: error instanceof Error ? error.message : String(error) });
1479
1557
  }
1480
1558
  }
1481
- return { status: ledgerIncomplete || artifactIncomplete ? 'incomplete' : 'ok', childLedgerIncomplete, samples: parseMemSamples(full.stdout), podStages: parseSiTaskPodStages(full.stdout) };
1559
+ return { status: ledgerIncomplete || artifactIncomplete ? 'incomplete' : 'ok', childLedgerIncomplete, samples: parseMemSamples(full.stdout) };
1482
1560
  };
1483
1561
  let retryAccount: string | undefined;
1484
1562
  let retrySamples: ReturnType<typeof parseMemSamples> = [];
@@ -1590,6 +1668,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1590
1668
  }
1591
1669
  bedrockSpec = checked.spec;
1592
1670
  }
1671
+ let jobDeadlineSeconds = options.deadlineSeconds ?? POD_JOB_DEADLINE_SECONDS;
1593
1672
  const creds = grok
1594
1673
  ? (options.grokCredentials ?? (() => hostGrokCredentials({ env, apiKeyOptIn: options.grokApiKeyOptIn })))()
1595
1674
  : apiKeyChild ? { ghToken: (options.openrouterGhToken ?? defaultGhToken)() }
@@ -1787,7 +1866,38 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1787
1866
  const hostKey = (k: string): string | undefined => k === 'OPENROUTER_API_KEY' && openrouter ? openrouterKey : k === 'ANTHROPIC_API_KEY' && anthropic ? anthropicKey : env[k] ?? (options.readKeyCache ?? defaultReadKeyCache)(k);
1788
1867
  const hostFallbackNames = (options.fallbackConfig ?? getUserConfig)().llm.fallbackChain;
1789
1868
  const normalizedFallback = normalizeFallbackChain(hostFallbackNames);
1790
- const fallbackChain = { steps: normalizedFallback.chain, source: normalizedFallback.usedDefault ? 'default' as const : 'host' as const };
1869
+ let fallbackSteps = normalizedFallback.chain;
1870
+ let zaiFallbackSpec: ZaiPodSpec | undefined;
1871
+ const codexChild = options.provider === undefined || options.provider === 'openai-codex';
1872
+ if (!codexChild && fallbackSteps.includes('zai')) {
1873
+ fallbackSteps = fallbackSteps.filter(step => step !== 'zai');
1874
+ debug.log('self-implement.pod', 'zai-fallback-unavailable', {
1875
+ job: name, reason: 'non-codex-child',
1876
+ }, { level: 'warn' });
1877
+ }
1878
+ if (codexChild && fallbackSteps.includes('zai')) {
1879
+ const settings = (options.zaiSettings ?? (() => zaiSettingsFromConfig(getUserConfig().llm)))();
1880
+ const poolMembers = (options.pool as { members?: readonly PodPoolMember[] } | undefined)?.members;
1881
+ const contexts = Array.isArray(poolMembers) && poolMembers.length > 0 ? poolMembers.map((m) => m.context) : [context];
1882
+ let active: number | null = 0;
1883
+ for (const c of contexts) {
1884
+ const n = c === context ? countActiveZaiJobs(kubectl, namespace)
1885
+ : countActiveZaiJobs((a, i) => baseKubectl(['--context', c, ...a], i), namespace);
1886
+ if (n === null) { active = null; break; }
1887
+ active += n;
1888
+ }
1889
+ const slot = decideZaiPodSlot({ active, pending: zaiPendingApply.size,
1890
+ maxConcurrent: settings.maxConcurrent, overage: 'stop' });
1891
+ if (slot.route === 'zai') {
1892
+ const checked = checkZaiPodSecret(kubectl, namespace);
1893
+ if (checked.ok) { zaiFallbackSpec = checked.spec; zaiPendingApply.add(name); }
1894
+ else debug.log('self-implement.pod', 'zai-fallback-unavailable', { job: name, reason: 'secret-unavailable' }, { level: 'warn' });
1895
+ } else debug.log('self-implement.pod', 'zai-fallback-unavailable', {
1896
+ job: name, reason: slot.route === 'refuse' ? 'slot-refused' : 'slot-unavailable', active,
1897
+ }, { level: 'warn' });
1898
+ if (!zaiFallbackSpec) fallbackSteps = fallbackSteps.filter(step => step !== 'zai');
1899
+ }
1900
+ const fallbackChain = { steps: fallbackSteps, source: normalizedFallback.usedDefault ? 'default' as const : 'host' as const };
1791
1901
  debug.log('self-implement.pod', 'fallback-chain-carried', {
1792
1902
  job: name, source: fallbackChain.source, steps: fallbackChain.steps,
1793
1903
  ...(normalizedFallback.dropped.length ? { droppedCount: normalizedFallback.dropped.length } : {}),
@@ -1830,9 +1940,12 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1830
1940
  let existingExecutionKey: string | undefined;
1831
1941
  let existingAttempt = NaN;
1832
1942
  let existingChildScript = '';
1943
+ let jobApplyStartedAt: number | undefined;
1944
+ let lifecycleJobUid: string | undefined;
1833
1945
  const existing = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.metadata.uid} {.status.conditions[*].type}']);
1834
1946
  const [existingUid = '', ...existingConditions] = existing.status === 0 ? existing.stdout.trim().split(/\s+/u) : [];
1835
1947
  const hasExistingJob = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(existingUid);
1948
+ if (hasExistingJob) lifecycleJobUid = existingUid;
1836
1949
  let reattach = hasExistingJob && !/Failed|FailureTarget/.test(existingConditions.join(' '));
1837
1950
  const failedExisting = hasExistingJob && /Failed|FailureTarget/.test(existingConditions.join(' '));
1838
1951
  if (hasExistingJob) {
@@ -1994,6 +2107,13 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1994
2107
  slotId: env.ELANOUS_POD_SLOT_ID,
1995
2108
  work: !goalDoc && env.ELANOUS_POD_AUTHOR_ON_POD === '1' && !shard ? 'authoring' : (oomRetried ? retryTier : memoryTier) === 'lite' ? 'lite' : 'harness',
1996
2109
  };
2110
+ // TA-POD-WARMBOOT-PARITY shadow only: record the decision on the existing fresh-Job path.
2111
+ // Until a shared warm-candidate contract exists, evidence stays unmeasured and this never changes execution.
2112
+ if (workIdentity.taskCard) {
2113
+ const warmReuseConfig = options.warmReuseConfig?.() ?? (options.kubectl ? undefined : getUserConfig().pod?.warmReuse);
2114
+ const decision = decideWarmReuse('ta', warmReuseConfig, options.warmReuseEvidence?.());
2115
+ debug.log('pod.warm', 'ta-shadow-observation', { ...decision, execution: 'fresh-job' });
2116
+ }
1997
2117
  // TA-POD-WARMBOOT-PARITY (GATE-WARM-BOOT parity · #27805): a commit-pinned source on a pool host — put that commit into
1998
2118
  // the host mirror first (once per host·commit in this process) so podSourceScript finds it instead of fetching
1999
2119
  // from GitHub. Best effort: a failed seed only logs; the Job is applied either way.
@@ -2034,13 +2154,47 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2034
2154
  // TA-POD-WARMBOOT-PARITY (GATE-POD-RESULT-MARKER parity · #27815): this launch's marker is the child's last line.
2035
2155
  const resultMarkerLine = resultMarkerOn ? (await import('./pod-result-marker-wait.js')).podResultMarkerShellLine(launchRunId) ?? undefined : undefined;
2036
2156
  if (resultMarkerLine) markerToken = launchRunId;
2037
- const job = podJobManifest({ name, namespace, fallbackChain, ...(resultMarkerLine ? { resultMarkerLine } : {}), image: jobImage, workIdentity, ...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}), repoUrl, ...(options.source ? { source: options.source } : {}), ...(options.repairCommitOnly ? { repairCommitOnly: options.repairCommitOnly } : {}), ...(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, ...(roleCodexCredential ? { reviewerCodexAuth: true } : {}), ...(bedrockSpec ? { bedrock: bedrockSpec } : {}), ...(zaiSpec ? { zai: zaiSpec } : {}) }); // kubectl 주입(=시험)이면 docker 를 부르지 않는다
2157
+ // POD-GROK-VALIDITY-FIT — without a relay the Pod cannot renew the copy, so the Job ends before the token does.
2158
+ // Measured right before the Job is applied (review r2): setup between the credential check and here takes time.
2159
+ if (grokSubscription) {
2160
+ const shippedExpiresAtMs = shippedGrokExpiresAtMs((creds as { grokAuth: string }).grokAuth);
2161
+ const fit = fitPodDeadlineToGrok({ requestedSeconds: jobDeadlineSeconds, expiresAtMs: shippedExpiresAtMs, nowMs: (options.now ?? Date.now)(), relay: Boolean(credentialRelay) });
2162
+ if (fit.refused) {
2163
+ debug.log('self-implement.pod', 'grok-deadline-refused', { job: name, requestedSeconds: jobDeadlineSeconds, availableSeconds: fit.availableSeconds, minJobSeconds: POD_GROK_MIN_JOB_SECONDS, marginMs: POD_GROK_EXPIRY_MARGIN_MS });
2164
+ cleanupSecret();
2165
+ return { exitCode: 1, output: '', error: { code: 'pod-grok-expiring', message: `grok: 구독 access 토큰 남은 시간 ${formatGrokRemaining(fit.availableSeconds * 1000 + POD_GROK_EXPIRY_MARGIN_MS)} < Pod 발사 기준 ${formatGrokRemaining(POD_GROK_MIN_VALIDITY_MS)} — 발사 직전 재검증 · 다음: 호스트에서 grok login --device-auth 후 다시` } };
2166
+ }
2167
+ debug.log('self-implement.pod', fit.fitted ? 'grok-deadline-fitted' : 'grok-deadline-kept', { job: name, requestedSeconds: jobDeadlineSeconds, deadlineSeconds: fit.deadlineSeconds, availableSeconds: fit.availableSeconds, relay: Boolean(credentialRelay), marginMs: POD_GROK_EXPIRY_MARGIN_MS });
2168
+ jobDeadlineSeconds = fit.deadlineSeconds;
2169
+ }
2170
+ const job = podJobManifest({ name, namespace, fallbackChain, ...(resultMarkerLine ? { resultMarkerLine } : {}), image: jobImage, workIdentity, ...(env.ELANOUS_TASK_BOUND_PR && /^[1-9]\d*$/.test(env.ELANOUS_TASK_BOUND_PR) && Number.isSafeInteger(Number(env.ELANOUS_TASK_BOUND_PR)) ? { boundPrNumber: Number(env.ELANOUS_TASK_BOUND_PR) } : {}), ...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}), repoUrl, ...(options.source ? { source: options.source } : {}), ...(options.repairCommitOnly ? { repairCommitOnly: options.repairCommitOnly } : {}), ...(hostMirror ? { hostMirror } : {}), args: jobArgs, passEnv: jobPassEnv, deadlineSeconds: jobDeadlineSeconds, ...(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, ...(roleCodexCredential ? { reviewerCodexAuth: true } : {}), ...(bedrockSpec ? { bedrock: bedrockSpec } : {}), ...(zaiSpec ? { zai: zaiSpec } : {}), ...(zaiFallbackSpec ? { zaiFallback: zaiFallbackSpec } : {}) }); // kubectl 주입(=시험)이면 docker 를 부르지 않는다
2038
2171
  const carriedBranch = goalDoc ? 'goal-doc' as const : env.ELANOUS_POD_AUTHOR_ON_POD === '1' && !shard ? 'author' as const : undefined;
2039
2172
  const carriedChildLlm = carriedBranch ? podDelegatedChildLlm(jobArgs) : undefined;
2173
+ jobApplyStartedAt = Date.now();
2040
2174
  const a = kubectl(['apply', '-f', '-'], JSON.stringify(job));
2041
2175
  zaiPendingApply.delete(name); // apply 뒤엔 Job 라벨이 센다(성공) · 실패면 셀 것이 없다
2042
2176
  if (a.status !== 0) { cleanupSecret(); return { exitCode: 1, output: a.stderr, error: { code: 'pod-apply', message: a.stderr.trim() } }; }
2043
2177
  releaseAdmission?.applied?.(name, context, namespace);
2178
+ // The injected observer does not acquire a production lease. The gate consumer
2179
+ // must compare the Job result and explicitly finalize before enabling replay.
2180
+ if (!oomRetried && input.warmWorkerCommand && options.warmPodRequest) {
2181
+ setImmediate(() => {
2182
+ try {
2183
+ const request = options.warmPodRequest!({ command: input.warmWorkerCommand! });
2184
+ void Promise.resolve(request)
2185
+ .then((result) => debug.log('pod.warm', 'request-observation', {
2186
+ spaceId: input.spaceId, status: result.status, reason: result.reason, execution: 'fresh-job',
2187
+ }))
2188
+ .catch((error) => debug.log('pod.warm', 'request-unavailable', {
2189
+ spaceId: input.spaceId, reason: error instanceof Error ? error.message : String(error), execution: 'fresh-job',
2190
+ }, { level: 'warn' }));
2191
+ } catch (error) {
2192
+ debug.log('pod.warm', 'request-unavailable', {
2193
+ spaceId: input.spaceId, reason: error instanceof Error ? error.message : String(error), execution: 'fresh-job',
2194
+ }, { level: 'warn' });
2195
+ }
2196
+ });
2197
+ }
2044
2198
  // Logged only once the Job is applied — a failed apply carried nothing.
2045
2199
  if (carriedBranch && carriedChildLlm) debug.log('self-implement.pod', 'child-llm-carried', { spaceId: input.spaceId, job: name, branch: carriedBranch, provider: carriedChildLlm.provider, model: carriedChildLlm.model ?? null });
2046
2200
  if (options.source?.kind === 'bundle') {
@@ -2068,6 +2222,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2068
2222
  }
2069
2223
  // ☸️ P2: 비밀의 소유자 = Job — 호스트가 죽어도 Job 의 TTL 삭제와 함께 k8s 가 비밀을 거둔다(자격 사본이 클러스터에 남지 않는다).
2070
2224
  const uid = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.metadata.uid}']).stdout.trim();
2225
+ lifecycleJobUid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(uid) ? uid : undefined;
2071
2226
  if (uid) {
2072
2227
  const owned = kubectl(['-n', namespace, 'patch', 'secret', `${name}-creds`, '--type=merge', '-p', JSON.stringify({ metadata: { ownerReferences: [{ apiVersion: 'batch/v1', kind: 'Job', name, uid }] } })]);
2073
2228
  if (owned.status !== 0) debug.log('self-implement.pod', 'secret-owner-failed', { job: name, stderr: owned.stderr.trim() }, { level: 'warn' });
@@ -2384,11 +2539,33 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2384
2539
  childError: childFailure?.error ?? (disposition?.stage ? 'result-without-error' : 'no-result-line') } : {}) },
2385
2540
  state === 'failed' && !oomKilled && failedReason !== 'DeadlineExceeded' ? { compact: { stringMax: 500 } } : undefined);
2386
2541
  // POD-LIFECYCLE-STAGES: one `pod.lifecycle stages` line — clone · mirror · run come from the Pod's own
2387
- // `ELANOUS_POD_STAGE` markers (SI-POD-STAGE-MARKERS), read from the «full» Job log only. ⛔ No `--tail=400` fallback:
2542
+ // `ELANOUS_POD_STAGE` markers (SI-POD-STAGE-MARKERS), read from that Pod's full named log. ⛔ No `--tail=400` fallback:
2388
2543
  // a tail can lose the real `run start` and pair a child-printed look-alike with the real `run end` (review mf) —
2389
2544
  // when the full log cannot be read, every stage stays «missing».
2545
+ let k8sTiming: ReturnType<typeof siTaskPodK8sTiming> = {};
2546
+ try {
2547
+ const childRunLabel = k8sLabelValue(liveChildRunId);
2548
+ if (childRunLabel) {
2549
+ const pods = kubectl(['-n', namespace, 'get', 'pods', '-l', `elanous.child-run=${childRunLabel}`, '-o', 'json']);
2550
+ if (pods.status === 0) k8sTiming = siTaskPodK8sTiming(pods.stdout, childRunLabel, name, lifecycleJobUid);
2551
+ }
2552
+ } catch { /* observation only: keep each unavailable timestamp missing */ }
2553
+ let lifecyclePodStages: Record<string, number> = {};
2554
+ let lifecycleDepsSkipped: { at: number; reason: string } | undefined;
2555
+ if (k8sTiming.podName && k8sTiming.podUid) {
2556
+ try {
2557
+ // The stage markers and UID must come from exactly the same Pod. `logs job/<name>`
2558
+ // can choose another Pod when a Job has more than one attempt.
2559
+ const podLogs = kubectl(['-n', namespace, 'logs', k8sTiming.podName, '-c', 'child']);
2560
+ if (podLogs.status === 0) {
2561
+ lifecyclePodStages = parseSiTaskPodStages(podLogs.stdout);
2562
+ lifecycleDepsSkipped = parseSiTaskDepsSkipped(podLogs.stdout);
2563
+ }
2564
+ } catch { /* only this Pod's markers may fill lifecycle stages */ }
2565
+ }
2390
2566
  emitPodLifecycle(siTaskPodLifecycleEvent({ runId: liveChildRunId, podJob: name, host: member?.context ?? null, watchStart: waitStartedAt, watchEnd: Date.now(),
2391
- podStages: collection.podStages ?? {}, outcome: oomKilled ? 'oom' : state }));
2567
+ createStart: jobApplyStartedAt,
2568
+ ...k8sTiming, podStages: lifecyclePodStages, depsSkipped: lifecycleDepsSkipped, outcome: oomKilled ? 'oom' : state }));
2392
2569
  if (oomKilled && reattach && !oomRetried && (!reattachedMemoryLimit || memoryGi(reattachedMemoryLimit) === null)) {
2393
2570
  return { exitCode: 1, output: '', error: { code: 'pod-memory-unavailable', message: `Job ${name} 실제 메모리 한도를 확인할 수 없다` } };
2394
2571
  }
@@ -2440,6 +2617,14 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2440
2617
  try { const { appendGoalExecutionRecord } = await import('../../self-implement/orchestrator.js'); appendGoalExecutionRecord(goalFile, record); }
2441
2618
  catch (error) { debug.log('self-implement.pod', 'goal-record-unavailable', { job: name, childRunId: liveChildRunId, reason: error instanceof Error ? error.message : String(error) }); }
2442
2619
  }
2620
+ // The host still has the complete Pod log here. The CLI only retains a short stdout tail,
2621
+ // so preserve the parsed child facts in the parent ledger before that tail is returned.
2622
+ if (state === 'failed' || state === 'aborted') {
2623
+ // Every terminal attempt writes a marker, including one with no parseable child facts.
2624
+ // The next attempt must never inherit an earlier Pod's classification.
2625
+ try { appendRunLedgerEntry({ runId: ledgerRunId, event: 'pod-child-evidence', data: { childEvidence: disposition?.childEvidence ?? null, childRunId: liveChildRunId, job: name } }, ledgerDir); }
2626
+ catch (error) { debug.log('self-implement.pod', 'child-evidence-write-failed', { job: name, childRunId: liveChildRunId, reason: error instanceof Error ? error.message : String(error) }, { level: 'warn' }); }
2627
+ }
2443
2628
  const terminalRecord = classifyPodTerminal({ childRunId: liveChildRunId, state, disposition, env,
2444
2629
  prBody: options.draftResidue ? undefined : podTerminalPrBody(disposition),
2445
2630
  goalText: parentGoal ?? input.feature, at: new Date().toISOString() });
@@ -2450,7 +2635,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2450
2635
  const tail = podRunResultLine(logs, salvage);
2451
2636
  if (state === 'aborted') return { exitCode: null, output: tail, error: { code: 'aborted', message: 'aborted — Job deleted' }, ...(disposition ? { disposition } : {}) };
2452
2637
  const deadlineExceeded = state === 'failed' && failedReason === 'DeadlineExceeded';
2453
- const deadlineSeconds = options.deadlineSeconds ?? POD_JOB_DEADLINE_SECONDS;
2638
+ const deadlineSeconds = jobDeadlineSeconds;
2454
2639
  if (deadlineExceeded) {
2455
2640
  debug.log('self-implement.pod', 'deadline-exceeded', {
2456
2641
  job: name,