elanous 0.2.31 → 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 (715) 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/{LSXfY0u9QtfDbejY0Ukf_ → 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-0a07363b130182a1.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-df3445b207ceceab.js +1 -0
  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/_next/static/css/b5d88eba78a3d7bf.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +26 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/bin/elanous.mjs +9 -2
  279. package/docs/goal-context/README.md +1 -0
  280. package/graphs/default-loop.yaml +20 -3
  281. package/graphs/document-loop.yaml +21 -2
  282. package/graphs/implement-loop.yaml +11 -0
  283. package/graphs/journey/SCENARIOS.md +33 -0
  284. package/graphs/journey/recipes.yaml +1 -0
  285. package/graphs/journey/ta-journey.yaml +84 -0
  286. package/graphs/journey/units/author/author.yaml +20 -0
  287. package/graphs/journey/units/author/recipes.yaml +2 -0
  288. package/graphs/journey/units/green/green.yaml +20 -0
  289. package/graphs/journey/units/green/recipes.yaml +2 -0
  290. package/graphs/journey/units/pr/pr.yaml +20 -0
  291. package/graphs/journey/units/pr/recipes.yaml +2 -0
  292. package/graphs/journey/units/remember/recipes.yaml +2 -0
  293. package/graphs/journey/units/remember/remember.yaml +20 -0
  294. package/graphs/operate-loop.yaml +21 -2
  295. package/graphs/overlays/stop-heal-ladder.yaml +1 -1
  296. package/graphs/release-rehearsal/recipes.yaml +1 -1
  297. package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
  298. package/graphs/research-loop.yaml +23 -2
  299. package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
  300. package/graphs/units/dispatch-pod/recipes.yaml +14 -0
  301. package/graphs/units/entry/entry.yaml +50 -0
  302. package/graphs/units/entry/recipes.yaml +14 -0
  303. package/graphs/units/harvest/harvest.yaml +25 -0
  304. package/graphs/units/harvest/recipes.yaml +4 -0
  305. package/graphs/units/land/land.yaml +45 -0
  306. package/graphs/units/land/recipes.yaml +3 -0
  307. package/graphs/units/recipes.yaml +7 -0
  308. package/graphs/units/recover.yaml +39 -0
  309. package/graphs/units/reflect/recipes.yaml +3 -0
  310. package/graphs/units/reflect/reflect.yaml +15 -0
  311. package/graphs/units/task-agent-recover-review.yaml +17 -0
  312. package/graphs/units/task-agent-recover-wait.yaml +17 -0
  313. package/graphs/units/verbs/make-doc.yaml +34 -0
  314. package/graphs/units/verbs/recipes.yaml +33 -0
  315. package/graphs/units/verbs/verify.yaml +55 -0
  316. package/graphs/work/recipes.yaml +2 -0
  317. package/graphs/work/research-report.yaml +28 -0
  318. package/package.json +1 -1
  319. package/scripts/ci-typecheck-changed.ts +95 -17
  320. package/scripts/docs/generate-graph-anatomy.ts +19 -2
  321. package/scripts/graph-harvest-unit.ts +22 -0
  322. package/scripts/graph-units/journey-stub.ts +6 -0
  323. package/scripts/graph-units/land-enqueue.ts +78 -0
  324. package/scripts/graph-units/recover-plan.ts +15 -0
  325. package/scripts/graph-units/reflect-node.ts +88 -0
  326. package/scripts/graph-units/ta-journey-observe.ts +109 -0
  327. package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
  328. package/scripts/graph-units/verbs/verify-stage.ts +75 -0
  329. package/scripts/graph-units/verbs-envelope.ts +139 -0
  330. package/scripts/hq/standby-snapshot.ts +25 -0
  331. package/scripts/measure-si-task-cpu.ts +143 -0
  332. package/scripts/public-export.ts +43 -1
  333. package/scripts/ratchets/test-interference-patterns.allowlist.txt +0 -2
  334. package/scripts/ratchets/train-side-invariants.sh +45 -0
  335. package/scripts/release-loop/auto-approve-node.ts +30 -16
  336. package/scripts/release-loop/gate-closure.ts +5 -1
  337. package/scripts/release-loop/gate-diff.ts +1 -1
  338. package/scripts/release-loop/gate-node.ts +498 -31
  339. package/scripts/release-loop/gate-partial.ts +3 -3
  340. package/scripts/release-loop/gate-radius-shadow.ts +138 -0
  341. package/scripts/release-loop/gate-traffic-mode.ts +128 -0
  342. package/scripts/release-loop/gate-triage-node.ts +5 -2
  343. package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
  344. package/scripts/release-loop/known-issues-node.ts +77 -8
  345. package/scripts/release-loop/preflight.ts +93 -7
  346. package/scripts/release-loop/prepare-node.ts +102 -4
  347. package/scripts/release-loop/publish-node.ts +60 -9
  348. package/scripts/release-loop/resume-cap.ts +56 -0
  349. package/scripts/release-loop/resume-release.ts +114 -15
  350. package/scripts/release-loop/resume.ts +24 -1
  351. package/scripts/release-loop/tui-sim-node.ts +8 -2
  352. package/scripts/release-loop/unattended-release.ts +8 -2
  353. package/src/acp/core-turn-bridge.ts +36 -9
  354. package/src/acp/elanous-extensions.ts +3 -0
  355. package/src/acp/reasoning-thought-buffer.ts +45 -0
  356. package/src/acp/server.ts +3 -0
  357. package/src/acp/tool-trace.ts +186 -11
  358. package/src/agent/self-ambient-cache.ts +156 -0
  359. package/src/agent/self-ambient.ts +8 -1
  360. package/src/agent/task-notification.ts +5 -0
  361. package/src/agent-substrate/acp-reviewer.ts +52 -12
  362. package/src/agent-substrate/pr-reviewer.ts +3 -1
  363. package/src/agent-substrate/review-finding-key.ts +53 -0
  364. package/src/agent-substrate/self-review-cli.ts +126 -5
  365. package/src/ask-user-question/pending-questions.ts +1 -1
  366. package/src/ask-user-question/tool.ts +22 -0
  367. package/src/autopilot/build/llm-conflict-merge.ts +56 -10
  368. package/src/autopilot/pr-manager.ts +213 -46
  369. package/src/capture/frame-state-detect.ts +39 -0
  370. package/src/capture/tui-self-report.ts +134 -6
  371. package/src/chat/index.ts +61 -15
  372. package/src/chat/pickers/modal-runtime.ts +6 -0
  373. package/src/chat/pickers/modals.ts +8 -2
  374. package/src/chat/tool-render/dispatch.ts +62 -10
  375. package/src/cli/ask-bare.ts +1 -0
  376. package/src/cli/control-cli.ts +24 -7
  377. package/src/cli/guardian-cli.ts +10 -0
  378. package/src/cli/import-cli.ts +12 -0
  379. package/src/cli/light-entry-route.ts +35 -0
  380. package/src/cli/llm-detect-cli.ts +23 -1
  381. package/src/cli/log-event-names.ts +10 -0
  382. package/src/cli/msg-cli.ts +1 -0
  383. package/src/cli/pod-cli.ts +14 -3
  384. package/src/cli/pr-cli.ts +140 -41
  385. package/src/cli/pr-land-base-read.ts +36 -0
  386. package/src/cli/pr-land-heavy-remote.ts +81 -25
  387. package/src/cli/pr-land-overlap-evidence.ts +200 -18
  388. package/src/cli/pr-land-pod-shadow-job.ts +26 -3
  389. package/src/cli/pr-land-recovery.ts +64 -0
  390. package/src/cli/pr-land-refusal.ts +20 -5
  391. package/src/cli/pty-takeover-cli.ts +94 -19
  392. package/src/cli/release-cli.ts +120 -33
  393. package/src/cli/release-run-if-ready.ts +29 -28
  394. package/src/cli/release-single-flight.ts +178 -0
  395. package/src/cli/seat-cli.ts +37 -0
  396. package/src/cli/setup-cli.ts +40 -1
  397. package/src/cli/sim-cli.ts +18 -0
  398. package/src/cli/tasks-cli.ts +149 -5
  399. package/src/context-bus/ops-events.ts +6 -2
  400. package/src/control/control-status.ts +8 -3
  401. package/src/control-plane/ledger.ts +5 -3
  402. package/src/control-plane/server.ts +5 -3
  403. package/src/core-turn/run-core-turn.ts +1 -0
  404. package/src/core-turn/run-goal-loop.ts +21 -0
  405. package/src/core-turn/short-question.ts +5 -1
  406. package/src/core-turn/types.ts +3 -0
  407. package/src/dashboard/acp-active-model.ts +42 -1
  408. package/src/dashboard/background-jobs-status.ts +66 -0
  409. package/src/dashboard/index.ts +153 -111
  410. package/src/dashboard/input/agent-wake.ts +242 -0
  411. package/src/dashboard/input/chat-main-entry-runtime.ts +5 -0
  412. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
  413. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  414. package/src/dashboard/input/external-input-host.ts +23 -9
  415. package/src/dashboard/input/mouse-wiring.ts +108 -11
  416. package/src/dashboard/input/seat-autowake.ts +56 -3
  417. package/src/dashboard/log-click-runtime.ts +118 -2
  418. package/src/dashboard/seat-boot-preamble.ts +1 -1
  419. package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
  420. package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
  421. package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
  422. package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
  423. package/src/dashboard/turn-preamble.ts +163 -41
  424. package/src/dashboard/turn-session-layers.ts +4 -2
  425. package/src/dashboard/turn-start-segments.ts +222 -0
  426. package/src/dashboard/turn-stream-formatter.ts +34 -1
  427. package/src/dashboard/turn-stream-runtime.ts +2 -0
  428. package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
  429. package/src/display/prompt-row-owner.ts +146 -0
  430. package/src/display/resize-listener.ts +33 -2
  431. package/src/domains/guardian-tick.ts +54 -2
  432. package/src/domains/outbound-alert.ts +3 -2
  433. package/src/extractors.ts +3 -1
  434. package/src/fold-stack.ts +4 -2
  435. package/src/git-fs/index.ts +263 -36
  436. package/src/git-fs/retry.ts +4 -0
  437. package/src/git-fs/runner.ts +2 -0
  438. package/src/graph-runner/runner.ts +114 -44
  439. package/src/grok/credential.ts +5 -0
  440. package/src/harness/gate-reserve.ts +87 -0
  441. package/src/harness/harness-cli-command.ts +39 -10
  442. package/src/harness/harness-incidents.ts +17 -0
  443. package/src/harness/harness-pod-dispatch.ts +38 -1
  444. package/src/harness/harness-queue.ts +15 -0
  445. package/src/harness/harness-salvage-cli.ts +14 -2
  446. package/src/index.ts +198 -12
  447. package/src/input/external-input-queue.ts +34 -9
  448. package/src/intake-plane/already-built-hint.ts +89 -0
  449. package/src/knowhow/pack.ts +199 -0
  450. package/src/light-cli.ts +95 -0
  451. package/src/llm/route-decision.ts +36 -0
  452. package/src/llm/tool-loop-steered-rejection.ts +8 -0
  453. package/src/llm-request-shape.ts +209 -0
  454. package/src/llm.ts +221 -276
  455. package/src/loops/budget.ts +95 -0
  456. package/src/loops/msg-wake.ts +8 -2
  457. package/src/loops/orchestrator/tick.ts +24 -2
  458. package/src/loops/orchestrator/traffic.ts +132 -1
  459. package/src/maturity/feature-maturity.ts +1 -1
  460. package/src/mss/logging/log-store.ts +4 -5
  461. package/src/mss/logging/render-categories.ts +5 -0
  462. package/src/nexus/api/graphs-api.ts +22 -3
  463. package/src/nexus/api/http-server.ts +1 -1
  464. package/src/nexus/api/ops-api.ts +12 -0
  465. package/src/oauth/claude-pty-maturity.ts +66 -0
  466. package/src/oauth/codex-access-mirror.ts +55 -0
  467. package/src/oauth/fallback-chain.ts +1 -1
  468. package/src/onboarding/first-run.ts +5 -3
  469. package/src/onboarding/non-interactive.ts +64 -13
  470. package/src/onboarding.ts +10 -2
  471. package/src/ops/overview-collect.ts +36 -1
  472. package/src/ops/overview.ts +70 -2
  473. package/src/pr-tool/census.ts +41 -8
  474. package/src/pr-tool/inflight-registry.ts +296 -0
  475. package/src/prompt-library/gpt6-family-addendum.ts +14 -1
  476. package/src/pty-shell/herdr-agent-report.ts +442 -0
  477. package/src/pty-shell/pty-control-ipc.ts +5 -5
  478. package/src/pty-shell/pty-manifest.ts +12 -3
  479. package/src/pty-shell/pty-write-outcome.ts +24 -6
  480. package/src/pty-shell/tui-run-state.ts +151 -6
  481. package/src/release-loop/checklist.ts +79 -5
  482. package/src/release-loop/feature-store.ts +19 -2
  483. package/src/release-loop/placement.ts +10 -3
  484. package/src/release-loop/rehearsal.ts +205 -25
  485. package/src/release-loop/rubric.ts +16 -2
  486. package/src/seat-loop/traffic-signal.ts +2 -1
  487. package/src/self-dev/ask-launch-flow.ts +13 -0
  488. package/src/self-dev/draft-residue.ts +243 -24
  489. package/src/self-dev/draft-sweep.ts +52 -3
  490. package/src/self-dev/graph-journey-nodes.ts +10 -6
  491. package/src/self-dev/graph-journey-route.ts +60 -6
  492. package/src/self-dev/orchestrate.ts +79 -3
  493. package/src/self-dev/run-supervisor.ts +107 -12
  494. package/src/self-dev/run-types.ts +5 -1
  495. package/src/self-dev/shard-plan.ts +11 -3
  496. package/src/self-dev/shard-run.ts +103 -10
  497. package/src/self-implement/elanous-tui-spawn.ts +14 -0
  498. package/src/self-implement/follow-up-placement.ts +79 -0
  499. package/src/self-implement/gate-artifacts.ts +15 -4
  500. package/src/self-implement/gate-baseline.ts +145 -10
  501. package/src/self-implement/gate-cli.ts +7 -2
  502. package/src/self-implement/gate-remote.ts +35 -6
  503. package/src/self-implement/goal-author-identity.ts +66 -0
  504. package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
  505. package/src/self-implement/goal-author.ts +4 -120
  506. package/src/self-implement/graph-overlay-yaml.ts +17 -2
  507. package/src/self-implement/graph-unit-flatten.ts +103 -0
  508. package/src/self-implement/graph-unit-resolver.ts +107 -0
  509. package/src/self-implement/graph-yaml.ts +151 -1
  510. package/src/self-implement/headless-elanous-driver.ts +1 -0
  511. package/src/self-implement/host-regate.ts +36 -4
  512. package/src/self-implement/knowhow-pack.ts +103 -0
  513. package/src/self-implement/orchestrator.ts +109 -11
  514. package/src/self-implement/pod-warm-pool-profile.ts +45 -0
  515. package/src/self-implement/review-mustfix-class.ts +203 -0
  516. package/src/self-implement/run-ledger.ts +16 -14
  517. package/src/self-implement/run-stop.ts +8 -2
  518. package/src/self-implement/seams.ts +32 -1
  519. package/src/self-implement/stop-autoheal.ts +25 -1
  520. package/src/session/chat.ts +27 -0
  521. package/src/session-runtime/index.ts +22 -267
  522. package/src/session-runtime/retry-policy.ts +2 -1
  523. package/src/shell-runner/background-surface.ts +15 -5
  524. package/src/skills/tools/agent.ts +39 -6
  525. package/src/skills/tools/list-dir.ts +11 -0
  526. package/src/skills/tools/schedule-wakeup.ts +457 -0
  527. package/src/skills/tools/shell.ts +245 -3
  528. package/src/status/bar.ts +26 -0
  529. package/src/steward/digest-delivery.ts +118 -0
  530. package/src/steward/hold-hygiene.ts +120 -0
  531. package/src/steward/release-day.ts +7 -3
  532. package/src/steward/triage.ts +47 -4
  533. package/src/surface/shell-runner-boot.ts +5 -2
  534. package/src/task-agent/harvest-unit.ts +141 -0
  535. package/src/task-agent/live-moves.ts +98 -12
  536. package/src/task-agent/parent-host.ts +93 -3
  537. package/src/task-agent/postland-card.ts +80 -1
  538. package/src/task-agent/rejudge-on-head.ts +112 -26
  539. package/src/task-agent/repair-branch-cas.ts +4 -1
  540. package/src/task-agent/repair-cycle.ts +16 -3
  541. package/src/task-agent/run-identity.ts +4 -3
  542. package/src/task-agent/shadow.ts +12 -2
  543. package/src/task-agent/task-hand.ts +76 -5
  544. package/src/task-agent/work-order-build.ts +22 -0
  545. package/src/task-orchestrator/surfaces/pod-account-broker.ts +39 -3
  546. package/src/task-orchestrator/surfaces/pod-command-job.ts +67 -12
  547. package/src/task-orchestrator/surfaces/pod-lease.ts +98 -0
  548. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +1 -1
  549. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
  550. package/src/task-orchestrator/surfaces/pod-pool.ts +76 -18
  551. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +10 -6
  552. package/src/task-orchestrator/surfaces/pod-source-receive.ts +54 -4
  553. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +548 -0
  554. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +389 -0
  555. package/src/task-orchestrator/surfaces/pod-warm-worker-runner.ts +90 -0
  556. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +158 -3
  557. package/src/task-orchestrator/surfaces/self-implement-pod.ts +230 -43
  558. package/src/task-orchestrator/surfaces/self-implement.ts +83 -2
  559. package/src/tool-runtime/truncation-store.ts +4 -0
  560. package/src/tui/chat/execution-badge.ts +5 -1
  561. package/src/tui/input-lag-probe.ts +230 -0
  562. package/src/tui-client/dashboard-session.ts +10 -1
  563. package/src/tui.ts +4 -0
  564. package/src/user-config/coercion.ts +36 -0
  565. package/src/user-config.ts +18 -41
  566. package/src/ux-sim/scenario.ts +314 -0
  567. package/src/version/packed-revision.json +1 -1
  568. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
  571. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
  572. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
  573. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
  577. package/apps/pwa/out/_next/static/chunks/1834-50625904996a8fa8.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
  579. package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
  580. package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
  587. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
  588. package/apps/pwa/out/_next/static/chunks/3267c0e6.d34854e7b3984a6e.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +0 -34
  591. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
  595. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
  599. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
  600. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
  602. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
  605. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
  610. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
  612. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
  619. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
  620. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
  622. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
  627. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
  628. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
  635. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2ebb8fd59b9461f9.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/setup/page-521ee23ac8c0abfa.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-149dc1caba411bb9.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
  706. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
  713. package/apps/pwa/out/_next/static/css/3f5fc6f96e2cf7b2.css +0 -1
  714. package/src/cli/g6a-registration-probe.ts +0 -16
  715. /package/apps/pwa/out/_next/static/{LSXfY0u9QtfDbejY0Ukf_ → 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';
@@ -43,8 +44,9 @@ export const POD_LOGS_KEEP_BYTES = 4_500_000;
43
44
  * POD-NORESULT ⓑ (10-07 · 28 failed rc=2 Jobs read back): every child printed its result line, but one
44
45
  * (si-task-71f68d57f6b7, image 0.2.15) had stderr lines (`[graph] collect fail`) after it, so the old
45
46
  * «last line only» check skipped the flatten and the host kept `ok:false` with no stage or PR number.
46
- * Scan back to the newest child result line instead; still append exactly one line. */
47
- const POD_RESULT_FLATTEN = `bun -e 'const fs=require("fs");const p="/tmp/si.out";const lines=fs.readFileSync(p,"utf8").trimEnd().split("\\n");for(let i=lines.length-1;i>=0;i--){const l=lines[i].trim();if(!l.startsWith("{"))continue;let o;try{o=JSON.parse(l)}catch{continue}if(!o||o.kind!=="self")continue;if(o.result&&typeof o.result==="object"&&!Array.isArray(o.result))fs.appendFileSync(p,"\\n"+JSON.stringify({...o.result,...(typeof o.ok==="boolean"?{ok:o.ok}:{})})+"\\n");break}'`;
47
+ * Scan back to a terminal child result; an interim JSON row or successful row on rc≠0 cannot hide a later failure.
48
+ * Keep this shell command on one physical line: Job command extraction consumes it as one line. */
49
+ export const POD_RESULT_FLATTEN = `ELANOUS_CHILD_RC="$rc" bun -e ' const fs=require("fs"); const p="/tmp/si.out"; const lines=fs.readFileSync(p,"utf8").trimEnd().split("\\n"); const failed=Number(process.env.ELANOUS_CHILD_RC)!==0; let terminal=null; let appendTerminal=false; let successIndex=-1; for(let i=lines.length-1;i>=0;i--){ const l=lines[i].trim(); if(!l.startsWith("{"))continue; let o; try{o=JSON.parse(l)}catch{continue} if(!o||typeof o!=="object"||Array.isArray(o))continue; const nested=o.kind==="self"&&o.result&&typeof o.result==="object"&&!Array.isArray(o.result); const flat=nested ? {...o.result,...(typeof o.ok==="boolean"?{ok:o.ok}:{})} : o.kind===undefined?o:null; if(!flat||typeof flat.ok!=="boolean"||typeof flat.stage!=="string"||!flat.stage||flat.stage==="running")continue; if(failed&&flat.ok===true){successIndex=i;break;} terminal=flat; appendTerminal=i!==lines.length-1||flat!==o; break; } let reason=""; let reasonIndex=-1; if(failed){ for(let i=successIndex>=0?successIndex+1:0;i<lines.length;i++){ const l=lines[i].trim(); if(/골 완료 경계 누락|self-implement PR guard 실패|draft PR 생성 실패/u.test(l)){ reason=l;reasonIndex=i; }else if(/^(Error:|❌)/u.test(l)&&(!reason||lines.slice(reasonIndex+1,i).some(x=>x.trim().startsWith("[retry]")||x.trim().startsWith("재시도:")))){ reason=l;reasonIndex=i; } } } if(terminal){ if(appendTerminal)fs.appendFileSync(p,"\\n"+JSON.stringify(terminal)+"\\n"); }else if(failed){ if(reason)fs.appendFileSync(p,"\\n"+JSON.stringify({stage:reason.includes("골 완료 경계 누락")?"preflight-blocked":"error",ok:false,error:lines.slice(reasonIndex).join("\\n").trim().slice(0,4000)})+"\\n"); else if(successIndex>=0)fs.appendFileSync(p,"\\n"+JSON.stringify({stage:"error",ok:false,error:"child exited rc="+process.env.ELANOUS_CHILD_RC+" after a success result without a terminal failure result"})+"\\n"); }'`;
48
50
 
49
51
  export const POD_JOB_DEADLINE_SECONDS = 10_800;
50
52
 
@@ -96,9 +98,15 @@ import { classifyPodExit, extractPodFailureReason, podTerminalRow, type PodExitC
96
98
  import { kubectlTransientReason, retryKubectlTransient } from './kubectl-transient-retry.js';
97
99
  import { OLD_DOOR_STAMP_ENV } from '../../self-dev/old-door.js';
98
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';
99
104
 
100
105
  export type Kubectl = (args: readonly string[], input?: string) => { status: number | null; stdout: string; stderr: string };
101
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
+
102
110
  // gh auth login may reject installation tokens when validating /user. Its config is
103
111
  // still the credential source for gh and setup-git's helper. Install it privately
104
112
  // on that failure; rename keeps concurrent readers from seeing a partial token.
@@ -147,6 +155,11 @@ export interface PodSpawnOptions {
147
155
  seedMirror?: (o: { host: string; commit: string; cwd: string }) => Promise<MirrorSeedResult | undefined>;
148
156
  /** Git tree that has the pinned commit for the mirror seed (default: process.cwd()). */
149
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;
150
163
  /** SI-SEED-DEFAULT — resolves a default source's branch tip for the mirror seed (test seam · default
151
164
  * {@link resolveDefaultSourceHead}; none with an injected kubectl unless given). */
152
165
  resolveSourceHead?: (o: { repoUrl: string; base?: string; cwd: string }) => Promise<{ sha?: string; reason?: string }>;
@@ -240,11 +253,11 @@ export interface PodSpawnOptions {
240
253
  memoryAdvice?: () => PodMemoryAdvice;
241
254
  }
242
255
 
243
- export function defaultKubectl(args: readonly string[], input?: string): { status: number | null; stdout: string; stderr: string } {
256
+ export function defaultKubectl(args: readonly string[], input?: string, timeoutMs = 120_000): { status: number | null; stdout: string; stderr: string } {
244
257
  // 셸 프록시가 kubectl 의 로컬 API 요청을 가로챈다(2026-09-25 실측) — 자식 env 에서 뺀다.
245
258
  const env = { ...process.env };
246
259
  for (const k of ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy', 'ALL_PROXY', 'all_proxy']) delete env[k];
247
- const r = spawnSync('kubectl', [...args], { encoding: 'utf8', input, env, timeout: 120_000, maxBuffer: LEASE_KUBECTL_MAX_BUFFER });
260
+ const r = spawnSync('kubectl', [...args], { encoding: 'utf8', input, env, timeout: timeoutMs, maxBuffer: LEASE_KUBECTL_MAX_BUFFER });
248
261
  const error = (r.error as NodeJS.ErrnoException | undefined)?.code === 'ENOBUFS'
249
262
  ? `kubectl 출력 너무 큼 (ENOBUFS; maxBuffer=${LEASE_KUBECTL_MAX_BUFFER} bytes)`
250
263
  : r.error ? String(r.error) : '';
@@ -422,7 +435,7 @@ async function defaultHqLeaseHolder(): Promise<boolean> {
422
435
  }
423
436
 
424
437
  /** 호스트 계정 → refresh 없는 사본(elanous 저장소 ⊕ codex auth.json) ⊕ gh 토큰. */
425
- 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 } {
426
439
  // 경로는 해석기로(격리 게이트 · 2026-09-25) — 손으로 `~/.elanous/auth.json` 을 조립하면 test↔prod 격리가 새는 자리가 된다.
427
440
  const store = JSON.parse(readFileSync(storePath, 'utf8')) as { version?: number; providers: Record<string, Record<string, unknown>> };
428
441
  // ⭐ 기본 계정은 정본 키가 `openai-codex`(이름 없음)이고 홈을 안 적는다 — 기본 위치로 푼다(회전 후보와 같은 해석).
@@ -430,22 +443,70 @@ export function hostCredentials(account: string, storePath: string = authStorePa
430
443
  const entry = store.providers[storeKey] as { tokens: Record<string, unknown>; lastRefresh?: string; authMode?: string; codexHome?: string } | undefined;
431
444
  const codexHome = entry?.codexHome ?? (entry && account === 'default' ? resolveCodexAccount(envLiteral({ CODEX_HOME: process.env.CODEX_HOME })).home : undefined);
432
445
  if (!entry || !codexHome) throw new Error(`${storeKey} 계정이 없거나 codexHome 을 모른다`);
433
- const codex = JSON.parse(readFileSync(join(codexHome, 'auth.json'), 'utf8')) as { tokens: Record<string, unknown> };
434
- const access = String(codex.tokens.access_token ?? '');
435
- const exp = Number(JSON.parse(Buffer.from(access.split('.')[1] ?? '', 'base64url').toString('utf8') || '{}').exp ?? 0);
436
- if (exp * 1000 - Date.now() < 3 * 3600_000) throw new PodCodexExpiringError(account, Math.round(((exp * 1000 - Date.now()) / 3_600_000) * 10) / 10);
437
- const elanousAuth = JSON.stringify({
438
- version: store.version ?? 1,
439
- // ⭐ P4(2026-09-26): elanous 사본도 «방금 검사한» codex 홈의 토큰으로 싣는다 — 두 저장소는 따로 갱신된다.
440
- // 🩸 실측: third 는 elanous 쪽 토큰이 4시간 전에 만료됐고 codex 홈 쪽은 235시간 남아 있었다 → Pod 가 갱신 400 으로 첫 호출 전에 죽었다(할당량 소진으로 오분류).
441
- providers: { 'openai-codex': { tokens: { ...entry.tokens, accessToken: access, expiresAt: exp * 1000, refreshToken: '' }, lastRefresh: entry.lastRefresh, authMode: entry.authMode, chatGPT: { accountId: codex.tokens.account_id } } },
442
- });
443
- const codexAuth = JSON.stringify({ ...codex, tokens: { ...codex.tokens, refresh_token: '' } });
444
- 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; }
445
509
  }
446
-
447
- /** A Pod gets a refresh-less access copy, so the copy must outlive the Job: same rule as the Codex path (3 h). */
448
- export const POD_GROK_MIN_VALIDITY_MS = 3 * 3600_000;
449
510
  /** PODCRED1 (10-05): an App installation token lives ~60 min and the host renews it in the Pod at the ten-minute
450
511
  * boundary; below this remaining life at launch the token is observed (`github-app-short-lived`). */
451
512
  export const POD_APP_TOKEN_MIN_START_MS = 20 * 60_000;
@@ -465,13 +526,21 @@ export function hostGrokCredentials(opts: {
465
526
  home?: string; env?: NodeJS.ProcessEnv; apiKeyOptIn?: boolean; ghToken?: () => string;
466
527
  /** Test seams — the host refresh (read-only `grok models`) and the expiry probe. */
467
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;
468
531
  } = {}): { grokAuth?: string; grokApiKey?: string; ghToken: string } {
469
532
  let credential = resolveGrokCredential({ home: opts.home, env: opts.env });
470
533
  if (credential?.kind === 'subscription') {
471
- 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 } : {}) }));
472
536
  if (expiring()) {
473
537
  try { (opts.refresh ?? (() => { refreshGrokSubscriptionToken({ home: opts.home }); }))(); } catch { /* judged below */ }
474
- 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
+ }
475
544
  credential = resolveGrokCredential({ home: opts.home, env: opts.env });
476
545
  if (credential?.kind !== 'subscription') throw new Error('grok: 갱신 뒤 구독 자격을 다시 읽지 못했다');
477
546
  }
@@ -553,9 +622,12 @@ export function grokLaunchReadiness(opts: { home?: string; env?: NodeJS.ProcessE
553
622
  }
554
623
 
555
624
  /** The one launch line for a skipped grok copy — the reader sees why grok left this run's chain. */
556
- export function podGrokSkippedLine(skip: { reason: PodGrokSkipReason; expiresAt: string | null }): string {
625
+ export function podGrokSkippedLine(skip: { reason: PodGrokSkipReason; expiresAt: string | null }, now?: () => number): string {
557
626
  const why = skip.reason === 'missing' ? '구독 자격 없음' : skip.reason === 'expiring' ? '만료 임박' : '만료 임박 · 호스트 갱신 실패';
558
- 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}`;
559
631
  }
560
632
 
561
633
  /** 키 캐시 관례: `~/.cache/<env 이름 소문자>`(예: OPENROUTER_API_KEY → ~/.cache/openrouter_api_key · src/config.ts 와 같다). */
@@ -768,7 +840,7 @@ export const POD_ATTEMPT_ANNOTATION = 'elanous.dev/attempt';
768
840
  export function podRunLabels(o: { runId?: string; parentRunId?: string }): Record<string, string> {
769
841
  const run = k8sLabelValue(o.parentRunId ?? o.runId);
770
842
  const child = k8sLabelValue(o.runId);
771
- return { ...(run ? { 'elanous.run': run } : {}), ...(child && child !== run ? { 'elanous.child-run': child } : {}) };
843
+ return { ...(run ? { 'elanous.run': run } : {}), ...(child ? { 'elanous.child-run': child } : {}) };
772
844
  }
773
845
 
774
846
  /** Pod 메모리 «등급» — 대표 09-27: PWA Pod 골이 16Gi 에서 OOM 으로 죽는다 ⇒ «high» 등급을 옵션으로 고른다.
@@ -997,7 +1069,7 @@ export function podSigtermTrapScript(seqFile: string = POD_USAGE_PARTIAL_SEQ_FIL
997
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`;
998
1070
  }
999
1071
 
1000
- 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> {
1001
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'))) {
1002
1074
  throw new Error('repair commit-only requires matching PR source and no PR/merge flags');
1003
1075
  }
@@ -1056,6 +1128,9 @@ export function podJobManifest(o: { name: string; namespace: string; image: stri
1056
1128
  siTaskPodStageShell('clone', 'start'),
1057
1129
  podSourceScript(o.source ?? { kind: 'default' }, o.repoUrl, undefined, { stageMarkers: true }),
1058
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`,
1059
1134
  ...(o.repairCommitOnly ? [`[ "$(git rev-parse HEAD)" = '${o.repairCommitOnly.baseHead}' ] || { echo 'ELANOUS_POD_REPAIR_FAILED source-head-mismatch'; exit 8; }`] : []),
1060
1135
  ...(goalPath ? [
1061
1136
  `mkdir -p -- "$(dirname -- ${goalPath})" && cp -- /creds/goal-doc ${goalPath} || exit 6`,
@@ -1080,7 +1155,7 @@ export function podJobManifest(o: { name: string; namespace: string; image: stri
1080
1155
  ? `echo "ELANOUS_AUTHOR_ON_POD started host=$(hostname) at=$(date -u +%Y-%m-%dT%H:%M:%SZ)"; author_t0=$(date +%s); ${o.authorGrade === 'lite' || o.authorGrade === 'full' ? `ELANOUS_AUTHOR_GRADE=${o.authorGrade} ` : ''}elanous harness say --substrate local --json${quotedAsk}${quotedChildLlm} -- "$(cat /creds/feature)" > /tmp/si.out 2>&1 & si_pid=$!; wait "$si_pid"; rc=$?; ${RUN_END}; echo "ELANOUS_AUTHOR_ON_POD finished host=$(hostname) rc=$rc seconds=$(( $(date +%s) - author_t0 ))"; ${POD_RESULT_FLATTEN}`
1081
1156
  : goalPath
1082
1157
  ? `elanous harness ask ${goalPath} --json${quotedAsk}${quotedChildLlm} > /tmp/si.out 2>&1 & si_pid=$!; wait "$si_pid"; rc=$?; ${RUN_END}; ${POD_RESULT_FLATTEN}`
1083
- : `export ${OLD_DOOR_STAMP_ENV}=self-implement; elanous self implement "$(cat /creds/feature)" --json ${quoted} > /tmp/si.out 2>&1 & si_pid=$!; wait "$si_pid"; rc=$?; ${RUN_END}`,
1158
+ : `export ${OLD_DOOR_STAMP_ENV}=self-implement; elanous self implement "$(cat /creds/feature)" --json ${quoted} > /tmp/si.out 2>&1 & si_pid=$!; wait "$si_pid"; rc=$?; ${RUN_END}; ${POD_RESULT_FLATTEN}`,
1084
1159
  'cat /tmp/si.out',
1085
1160
  '[ -f scripts/usage-rollup.ts ] && bun scripts/usage-rollup.ts --since 12h || echo "ELANOUS_USAGE_ROLLUP {\"measured\":false,\"reason\":\"no rollup script\"}"',
1086
1161
  // A long run's log export can pass the 5MB artifact limit; skipping it whole left no window into why a
@@ -1150,7 +1225,7 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1150
1225
  return {
1151
1226
  apiVersion: 'batch/v1',
1152
1227
  kind: 'Job',
1153
- 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' } : {}) },
1154
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' } : {}) } } : {}) },
1155
1230
  spec: {
1156
1231
  backoffLimit: 0,
@@ -1158,7 +1233,7 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1158
1233
  activeDeadlineSeconds: o.deadlineSeconds,
1159
1234
  template: {
1160
1235
  // ⭐ Pod 라벨 — local 팔만 `elanous.egress/local-llm` 을 단다. docker/h1/policy-local-llm.yaml 이 그 라벨에만 호스트 LLM 포트 «하나»를 연다.
1161
- 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' } : {}) } },
1162
1237
  spec: {
1163
1238
  restartPolicy: 'Never',
1164
1239
  securityContext: { runAsUser: 1000, fsGroup: 1000 },
@@ -1174,6 +1249,9 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1174
1249
  ...(o.runId ? [{ name: 'ELANOUS_RUN_ID', value: o.runId }] : []),
1175
1250
  ...(o.parentRunId ? [{ name: 'ELANOUS_PARENT_RUN_ID', value: o.parentRunId }] : []),
1176
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) }] : []),
1254
+ ...(o.workIdentity?.slotId ? [{ name: 'ELANOUS_POD_SLOT_ID', value: o.workIdentity.slotId }] : []),
1177
1255
  { name: 'ELANOUS_SUBSTRATE', value: 'pod' },
1178
1256
  ...Object.entries(controlInboxEnv(POD_CONTROL_INBOX_DIR)).map(([name, value]) => ({ name, value })),
1179
1257
  // ⭐ 런 출처(🅣 RFC run-origin §A3 · #20457/#20468 칸 이름) — Pod 는 자기 elanous_id 를 쓰지 않고 «띄운 감독기»의 hostId 를 물려받는다.
@@ -1187,7 +1265,7 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
1187
1265
  ...Object.entries(o.armEnv ?? {}).map(([name, value]) => ({ name, value })),
1188
1266
  ...o.passEnv.map((key) => ({ name: key, valueFrom: { secretKeyRef: { name: `${o.name}-creds`, key: `env-${key}` } } })),
1189
1267
  ...(o.bedrock ? bedrockPodEnv(o.bedrock) : []),
1190
- ...(o.zai ? zaiPodEnv(o.zai) : []),
1268
+ ...(o.zai || o.zaiFallback ? zaiPodEnv(o.zai ?? o.zaiFallback!) : []),
1191
1269
  ],
1192
1270
  volumeMounts: [{ name: 'creds', mountPath: '/creds', readOnly: true }, ...(o.hostMirror ? [{ name: 'host-mirror', mountPath: '/host-mirror', readOnly: true }] : [])],
1193
1271
  }],
@@ -1340,9 +1418,9 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1340
1418
  const timer = setTimeout(() => {
1341
1419
  if (stalledStages.has(stage)) return;
1342
1420
  stalledStages.add(stage);
1343
- const pool = options.pool as { waitReason?: () => string | null } | undefined;
1421
+ const pool = options.pool as { waitReason?: (memoryLimit?: string) => string | null } | undefined;
1344
1422
  debug.log('harness.launch', 'launch-stalled', { spaceId: input.spaceId, runId: childRunId, stage, waitedSec: Math.round((Date.now() - started) / 1000),
1345
- 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' });
1346
1424
  }, stallMs);
1347
1425
  (timer as { unref?: () => void }).unref?.();
1348
1426
  return () => clearTimeout(timer);
@@ -1385,7 +1463,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1385
1463
  const acquireAdmission = async (): Promise<boolean> => {
1386
1464
  if (!options.pool || typeof options.pool.acquireAdmission !== 'function') return true;
1387
1465
  const stop = watchStall('admission');
1388
- try { releaseAdmission = await options.pool.acquireAdmission(input.signal, after); return true; }
1466
+ try { releaseAdmission = await options.pool.acquireAdmission(input.signal, after, { memoryLimit }); return true; }
1389
1467
  catch (error) {
1390
1468
  // A predecessor closed without merging is not a cancellation: surface it so the queue owner is notified.
1391
1469
  if (error instanceof Error && error.message.startsWith('pod lease predecessor blocked')) admissionBlocked = error.message;
@@ -1430,7 +1508,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1430
1508
  const cleanupSecret = () => { kubectl(['-n', namespace, 'delete', 'secret', `${name}-creds`, '--ignore-not-found']); };
1431
1509
  let repairResultAnnounced = false;
1432
1510
  let repairArtifactReady = false;
1433
- 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> } => {
1434
1512
  let full: ReturnType<Kubectl>;
1435
1513
  try {
1436
1514
  full = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
@@ -1440,10 +1518,12 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1440
1518
  debug.log('self-implement.pod', unavailableEvent, { job: name, reason: error instanceof Error ? error.message : String(error) });
1441
1519
  return { status: 'unavailable', childLedgerIncomplete: false, samples: [] };
1442
1520
  }
1443
- 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];
1444
1522
  // #28246 names why the mirror was skipped on the line before `VIA github`; carry it on the same event.
1445
1523
  const mirrorSkip = /^ELANOUS_POD_SOURCE_MIRROR_SKIP (no-mount|rev-parse-failed|clone-failed)\r?$/m.exec(full.stdout)?.[1];
1446
- 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 } : {}) });
1447
1527
  let ledgerIncomplete = false;
1448
1528
  let childLedgerIncomplete = false;
1449
1529
  let artifactIncomplete = false;
@@ -1476,7 +1556,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1476
1556
  record('self-implement.pod', 'repair-artifact-incomplete', { job: name, reason: error instanceof Error ? error.message : String(error) });
1477
1557
  }
1478
1558
  }
1479
- 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) };
1480
1560
  };
1481
1561
  let retryAccount: string | undefined;
1482
1562
  let retrySamples: ReturnType<typeof parseMemSamples> = [];
@@ -1588,6 +1668,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1588
1668
  }
1589
1669
  bedrockSpec = checked.spec;
1590
1670
  }
1671
+ let jobDeadlineSeconds = options.deadlineSeconds ?? POD_JOB_DEADLINE_SECONDS;
1591
1672
  const creds = grok
1592
1673
  ? (options.grokCredentials ?? (() => hostGrokCredentials({ env, apiKeyOptIn: options.grokApiKeyOptIn })))()
1593
1674
  : apiKeyChild ? { ghToken: (options.openrouterGhToken ?? defaultGhToken)() }
@@ -1785,7 +1866,38 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1785
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);
1786
1867
  const hostFallbackNames = (options.fallbackConfig ?? getUserConfig)().llm.fallbackChain;
1787
1868
  const normalizedFallback = normalizeFallbackChain(hostFallbackNames);
1788
- 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 };
1789
1901
  debug.log('self-implement.pod', 'fallback-chain-carried', {
1790
1902
  job: name, source: fallbackChain.source, steps: fallbackChain.steps,
1791
1903
  ...(normalizedFallback.dropped.length ? { droppedCount: normalizedFallback.dropped.length } : {}),
@@ -1828,9 +1940,12 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1828
1940
  let existingExecutionKey: string | undefined;
1829
1941
  let existingAttempt = NaN;
1830
1942
  let existingChildScript = '';
1943
+ let jobApplyStartedAt: number | undefined;
1944
+ let lifecycleJobUid: string | undefined;
1831
1945
  const existing = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.metadata.uid} {.status.conditions[*].type}']);
1832
1946
  const [existingUid = '', ...existingConditions] = existing.status === 0 ? existing.stdout.trim().split(/\s+/u) : [];
1833
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;
1834
1949
  let reattach = hasExistingJob && !/Failed|FailureTarget/.test(existingConditions.join(' '));
1835
1950
  const failedExisting = hasExistingJob && /Failed|FailureTarget/.test(existingConditions.join(' '));
1836
1951
  if (hasExistingJob) {
@@ -1992,6 +2107,13 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
1992
2107
  slotId: env.ELANOUS_POD_SLOT_ID,
1993
2108
  work: !goalDoc && env.ELANOUS_POD_AUTHOR_ON_POD === '1' && !shard ? 'authoring' : (oomRetried ? retryTier : memoryTier) === 'lite' ? 'lite' : 'harness',
1994
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
+ }
1995
2117
  // TA-POD-WARMBOOT-PARITY (GATE-WARM-BOOT parity · #27805): a commit-pinned source on a pool host — put that commit into
1996
2118
  // the host mirror first (once per host·commit in this process) so podSourceScript finds it instead of fetching
1997
2119
  // from GitHub. Best effort: a failed seed only logs; the Job is applied either way.
@@ -2032,13 +2154,47 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2032
2154
  // TA-POD-WARMBOOT-PARITY (GATE-POD-RESULT-MARKER parity · #27815): this launch's marker is the child's last line.
2033
2155
  const resultMarkerLine = resultMarkerOn ? (await import('./pod-result-marker-wait.js')).podResultMarkerShellLine(launchRunId) ?? undefined : undefined;
2034
2156
  if (resultMarkerLine) markerToken = launchRunId;
2035
- 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 를 부르지 않는다
2036
2171
  const carriedBranch = goalDoc ? 'goal-doc' as const : env.ELANOUS_POD_AUTHOR_ON_POD === '1' && !shard ? 'author' as const : undefined;
2037
2172
  const carriedChildLlm = carriedBranch ? podDelegatedChildLlm(jobArgs) : undefined;
2173
+ jobApplyStartedAt = Date.now();
2038
2174
  const a = kubectl(['apply', '-f', '-'], JSON.stringify(job));
2039
2175
  zaiPendingApply.delete(name); // apply 뒤엔 Job 라벨이 센다(성공) · 실패면 셀 것이 없다
2040
2176
  if (a.status !== 0) { cleanupSecret(); return { exitCode: 1, output: a.stderr, error: { code: 'pod-apply', message: a.stderr.trim() } }; }
2041
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
+ }
2042
2198
  // Logged only once the Job is applied — a failed apply carried nothing.
2043
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 });
2044
2200
  if (options.source?.kind === 'bundle') {
@@ -2066,6 +2222,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2066
2222
  }
2067
2223
  // ☸️ P2: 비밀의 소유자 = Job — 호스트가 죽어도 Job 의 TTL 삭제와 함께 k8s 가 비밀을 거둔다(자격 사본이 클러스터에 남지 않는다).
2068
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;
2069
2226
  if (uid) {
2070
2227
  const owned = kubectl(['-n', namespace, 'patch', 'secret', `${name}-creds`, '--type=merge', '-p', JSON.stringify({ metadata: { ownerReferences: [{ apiVersion: 'batch/v1', kind: 'Job', name, uid }] } })]);
2071
2228
  if (owned.status !== 0) debug.log('self-implement.pod', 'secret-owner-failed', { job: name, stderr: owned.stderr.trim() }, { level: 'warn' });
@@ -2382,11 +2539,33 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2382
2539
  childError: childFailure?.error ?? (disposition?.stage ? 'result-without-error' : 'no-result-line') } : {}) },
2383
2540
  state === 'failed' && !oomKilled && failedReason !== 'DeadlineExceeded' ? { compact: { stringMax: 500 } } : undefined);
2384
2541
  // POD-LIFECYCLE-STAGES: one `pod.lifecycle stages` line — clone · mirror · run come from the Pod's own
2385
- // `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:
2386
2543
  // a tail can lose the real `run start` and pair a child-printed look-alike with the real `run end` (review mf) —
2387
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
+ }
2388
2566
  emitPodLifecycle(siTaskPodLifecycleEvent({ runId: liveChildRunId, podJob: name, host: member?.context ?? null, watchStart: waitStartedAt, watchEnd: Date.now(),
2389
- podStages: collection.podStages ?? {}, outcome: oomKilled ? 'oom' : state }));
2567
+ createStart: jobApplyStartedAt,
2568
+ ...k8sTiming, podStages: lifecyclePodStages, depsSkipped: lifecycleDepsSkipped, outcome: oomKilled ? 'oom' : state }));
2390
2569
  if (oomKilled && reattach && !oomRetried && (!reattachedMemoryLimit || memoryGi(reattachedMemoryLimit) === null)) {
2391
2570
  return { exitCode: 1, output: '', error: { code: 'pod-memory-unavailable', message: `Job ${name} 실제 메모리 한도를 확인할 수 없다` } };
2392
2571
  }
@@ -2438,6 +2617,14 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2438
2617
  try { const { appendGoalExecutionRecord } = await import('../../self-implement/orchestrator.js'); appendGoalExecutionRecord(goalFile, record); }
2439
2618
  catch (error) { debug.log('self-implement.pod', 'goal-record-unavailable', { job: name, childRunId: liveChildRunId, reason: error instanceof Error ? error.message : String(error) }); }
2440
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
+ }
2441
2628
  const terminalRecord = classifyPodTerminal({ childRunId: liveChildRunId, state, disposition, env,
2442
2629
  prBody: options.draftResidue ? undefined : podTerminalPrBody(disposition),
2443
2630
  goalText: parentGoal ?? input.feature, at: new Date().toISOString() });
@@ -2448,7 +2635,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
2448
2635
  const tail = podRunResultLine(logs, salvage);
2449
2636
  if (state === 'aborted') return { exitCode: null, output: tail, error: { code: 'aborted', message: 'aborted — Job deleted' }, ...(disposition ? { disposition } : {}) };
2450
2637
  const deadlineExceeded = state === 'failed' && failedReason === 'DeadlineExceeded';
2451
- const deadlineSeconds = options.deadlineSeconds ?? POD_JOB_DEADLINE_SECONDS;
2638
+ const deadlineSeconds = jobDeadlineSeconds;
2452
2639
  if (deadlineExceeded) {
2453
2640
  debug.log('self-implement.pod', 'deadline-exceeded', {
2454
2641
  job: name,