elanous 0.2.34 → 0.2.35

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 (611) 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/{L04y73dlwKeTW-GetaTF3 → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{5014f970-22bef0b5210f7d60.js → 0368f25d-ad84af92fefee68f.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/{2124.ed5bf480cea7f85b.js → 1530.0e612369b6fd7ea0.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +41 -0
  9. package/apps/pwa/out/_next/static/chunks/1674.2a65fd5668e1cc5f.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +24 -0
  11. package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +74 -0
  12. package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.js → 2018.a741297bce759490.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +148 -0
  23. package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +34 -0
  25. package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +77 -0
  26. package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +62 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +90 -0
  31. package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{1644.35dd25240ae24e4b.js → 3408.21d1570602f4b6c0.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{3121.779fafe3e44612c5.js → 3589.5444a06bcf6e775c.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/359-2250789a2d3499e7.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{9131-fce7256c4180c4a5.js → 3677-4215f826f6aa68e5.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +79 -0
  40. package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +122 -0
  42. package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4346.8601952e73bf5803.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/{6053-d893974de92e6198.js → 4441-875b97f5821ed58a.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +286 -0
  46. package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +24 -0
  49. package/apps/pwa/out/_next/static/chunks/{1895-60ed0e341c658bd4.js → 4705-194e64e47ca0fbdb.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.js → 4718-17d2af636796a330.js} +3 -3
  51. package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{7431.3051e9b8a4372d2d.js → 5101.e32282718f99ed6f.js} +2 -2
  57. package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +23 -0
  61. package/apps/pwa/out/_next/static/chunks/{2987-30cf9c2eb7b8bdd5.js → 5483-dd5d7697f6bdb106.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +94 -0
  63. package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/56d372f2.681ab4ec4c998fae.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/{7386.5d8e7e42e818dfb6.js → 5852.db1f7449f4f74612.js} +2 -2
  67. package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/{3110.0a7065f25c841818.js → 6236.e18cced2d5ba6afb.js} +3 -3
  74. package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +8 -0
  75. package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +27 -0
  78. package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +93 -0
  80. package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +149 -0
  87. package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +104 -0
  88. package/apps/pwa/out/_next/static/chunks/{7005.1623d2aea78eb85f.js → 7385.50a308a477bdfc21.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.js → 7644.17e37ba6f1d4226e.js} +4 -4
  90. package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{7193-cf355cca5ba6c5d5.js → 8437-8d5492094b166cfa.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/{2554.3b5e200f5f5cfcd6.js → 8444.4c26b379ca2b9596.js} +4 -4
  100. package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +226 -0
  101. package/apps/pwa/out/_next/static/chunks/8557-e7898769499cd56f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +64 -0
  104. package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{2547.dd27303624cb4da8.js → 8637.47f5b35afcae5e6b.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{9550.d5f76828f972058c.js → 9214.63a510d39178e997.js} +2 -2
  111. package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +115 -0
  112. package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{8548.036c344973968847.js → 938.66ad1ef0e5abae1c.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/{3414.172ad4ca2d9b08e8.js → 9512.5a76207a730e0491.js} +2 -2
  115. package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{6740.43de73fc427c9fe2.js → 9952.5daf5f94063a2b3e.js} +1 -1
  120. package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/{page-d7bff0f0905a662c.js → page-26e6c18a1a750cf6.js} +1 -1
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-47c5d4db587266bd.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/{page-df3445b207ceceab.js → page-dc0a532f5b9196ec.js} +1 -1
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{9a8cb466.cc9fc9e6e46038aa.js → b2f6ba4d.fb56fdbbf798df33.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/b6705a4f-b9a9047de9eecfd0.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{4fa33ebd.21c1bd5b294496e6.js → cbe38a15.5a032598e39970c6.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{abb4b98b.163e0f56e84ae35d.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.js → da5176c6.6773b6c5994e1d99.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +1 -0
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/bin/elanous.mjs +3 -2
  278. package/catalog/providers/opengateway.yaml +25 -0
  279. package/docs/goal-context/01-goal-authoring-checks.md +8 -0
  280. package/docs/goal-context/03-verification-menu.md +24 -0
  281. package/docs/goal-context/04-mock-scenarios.md +100 -0
  282. package/docs/goal-context/README.md +4 -0
  283. package/graphs/catalog/catalog.yaml +1 -1
  284. package/graphs/default-loop.yaml +57 -3
  285. package/graphs/document-loop.yaml +51 -3
  286. package/graphs/implement-loop.yaml +53 -4
  287. package/graphs/journey/ta-journey.yaml +11 -1
  288. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  289. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  290. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  291. package/graphs/operate-loop.yaml +51 -3
  292. package/graphs/research-loop.yaml +137 -3
  293. package/graphs/test-diet/test-diet.yaml +3 -0
  294. package/package.json +1 -1
  295. package/scripts/coord-role-pack.ts +19 -6
  296. package/scripts/hq/standby-snapshot.ts +17 -12
  297. package/scripts/release-loop/docs-land-node.ts +21 -5
  298. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  299. package/scripts/release-loop/gate-node.ts +181 -22
  300. package/scripts/release-loop/gate-partial.ts +65 -11
  301. package/scripts/release-loop/gate-radius-live.ts +177 -0
  302. package/scripts/release-loop/gate-radius-shadow.ts +1 -1
  303. package/scripts/release-loop/node-verdict.ts +12 -1
  304. package/scripts/release-loop/npm-publish-node.ts +66 -12
  305. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  306. package/scripts/release-loop/pwa-remote.ts +166 -0
  307. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  308. package/scripts/release-loop/resume-release.ts +41 -4
  309. package/scripts/release-loop/unattended-release.ts +2 -0
  310. package/scripts/test-diet/lib.ts +6 -1
  311. package/scripts/test-diet/node.ts +194 -13
  312. package/scripts/ux-sim.ts +39 -0
  313. package/src/agent/self-ambient-cache.ts +8 -0
  314. package/src/agent-substrate/acp-reviewer.ts +39 -4
  315. package/src/agent-substrate/pr-reviewer.ts +17 -0
  316. package/src/agent-substrate/self-review-cli.ts +62 -13
  317. package/src/autopilot/pr-manager.ts +215 -36
  318. package/src/budget/run-usage-rollup.ts +1 -0
  319. package/src/chat/index.ts +0 -2
  320. package/src/chat/pickers/modal-runtime.ts +10 -27
  321. package/src/cli/agent-cli.ts +13 -2
  322. package/src/cli/doctor-cli.ts +4 -1
  323. package/src/cli/light-entry-route.ts +46 -6
  324. package/src/cli/pod-cli.ts +77 -3
  325. package/src/cli/pr-cli.ts +5 -2
  326. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  327. package/src/cli/release-checklist-read-cli.ts +79 -0
  328. package/src/cli/release-cli.ts +72 -102
  329. package/src/cli/remote-resolve.ts +1 -1
  330. package/src/cli/root-tui-entry.ts +48 -0
  331. package/src/cli/sim-cli.ts +22 -0
  332. package/src/cli/tasks-cli.ts +540 -31
  333. package/src/cli/usage-cli.ts +13 -11
  334. package/src/clipboard/history.ts +179 -13
  335. package/src/config.ts +8 -1
  336. package/src/dashboard/chat/acp-chat.ts +8 -0
  337. package/src/dashboard/index.ts +78 -10
  338. package/src/dashboard/render/theme-resolver.ts +33 -4
  339. package/src/domains/schedule-registry.ts +16 -2
  340. package/src/git-fs/idle-refresh.ts +76 -0
  341. package/src/git-fs/index.ts +18 -7
  342. package/src/git-fs/worktree.ts +42 -4
  343. package/src/graph-kinds/registry.ts +2 -2
  344. package/src/graph-runner/runner.ts +153 -10
  345. package/src/grok/credential.ts +10 -3
  346. package/src/harness/harness-cli-command.ts +112 -28
  347. package/src/harness/harness-incidents.ts +33 -0
  348. package/src/harness/launch-utterance-ledger.ts +208 -0
  349. package/src/impl-discipline/detector.ts +16 -4
  350. package/src/impl-discipline/system-prompt.ts +11 -0
  351. package/src/impl-discipline/types.ts +2 -2
  352. package/src/index.ts +496 -143
  353. package/src/intake-plane/already-built-hint.ts +4 -2
  354. package/src/intake-plane/requirement-funnel.ts +29 -1
  355. package/src/light-cli.ts +27 -11
  356. package/src/llm/opengateway-models.ts +11 -0
  357. package/src/llm/provider-credentials.ts +14 -0
  358. package/src/llm/provider-detect.ts +8 -1
  359. package/src/llm/runtime-model-family.ts +2 -1
  360. package/src/llm.ts +213 -56
  361. package/src/model-tier/llm-tier-map.ts +15 -1
  362. package/src/native-tool-catalog.ts +15 -1
  363. package/src/nexus/api/loop-resources.ts +13 -1
  364. package/src/oauth/codex.ts +7 -0
  365. package/src/ops/overview-collect.ts +18 -3
  366. package/src/ops/overview.ts +20 -7
  367. package/src/pr-tool/census.ts +261 -27
  368. package/src/pty-shell/pty-manifest.ts +7 -0
  369. package/src/release-loop/checklist.ts +24 -0
  370. package/src/release-loop/landed-but-yellow.ts +129 -5
  371. package/src/release-loop/light-rc.ts +1 -0
  372. package/src/release-loop/rehearsal.ts +2 -2
  373. package/src/repl/index.ts +174 -17
  374. package/src/repl/ops-msg-bridge.ts +32 -0
  375. package/src/self-dev/ask-launch-flow.ts +44 -5
  376. package/src/self-dev/cli-help-text.ts +17 -0
  377. package/src/self-dev/dev-cli.ts +11 -9
  378. package/src/self-dev/draft-residue.ts +37 -1
  379. package/src/self-dev/draft-sweep.ts +137 -11
  380. package/src/self-dev/draft-triage-rules.ts +107 -0
  381. package/src/self-dev/fleet-reduce.ts +3 -2
  382. package/src/self-dev/graph-front-nodes.ts +112 -0
  383. package/src/self-dev/graph-journey-nodes.ts +1 -0
  384. package/src/self-dev/harness-run-cli.ts +3 -15
  385. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  386. package/src/self-dev/review-provider-fallback.ts +35 -1
  387. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  388. package/src/self-dev/shard-aggregate.ts +42 -5
  389. package/src/self-dev/shard-run.ts +8 -1
  390. package/src/self-implement/blocked-draft-policy.ts +20 -0
  391. package/src/self-implement/classify-shadow.ts +3 -7
  392. package/src/self-implement/doctor-visit.ts +18 -1
  393. package/src/self-implement/gate-baseline.ts +56 -17
  394. package/src/self-implement/gate-cli.ts +1 -0
  395. package/src/self-implement/gate-remote.ts +31 -20
  396. package/src/self-implement/goal-author-decompose.ts +275 -47
  397. package/src/self-implement/goal-author.ts +250 -0
  398. package/src/self-implement/goal-elaborate.ts +295 -0
  399. package/src/self-implement/goal-refine.ts +270 -0
  400. package/src/self-implement/graph-overlay-yaml.ts +14 -3
  401. package/src/self-implement/orchestrator.ts +152 -45
  402. package/src/self-implement/rework-budget-judgment.ts +5 -8
  403. package/src/self-implement/run-stop.ts +10 -1
  404. package/src/self-implement/running-runs.ts +29 -1
  405. package/src/self-implement/scope-adjacency.ts +113 -0
  406. package/src/self-implement/seams.ts +127 -24
  407. package/src/self-implement/stop-autoheal.ts +87 -1
  408. package/src/session-runtime/index.ts +1 -1
  409. package/src/setup/llm-env-detect.ts +5 -0
  410. package/src/skills/tools/agent.ts +140 -14
  411. package/src/skills/tools/msg-ask.ts +100 -0
  412. package/src/skills/tools/ops-ledger.ts +2 -1
  413. package/src/steward/hold-hygiene.ts +24 -6
  414. package/src/steward/triage-budget.ts +194 -0
  415. package/src/steward/triage.ts +20 -3
  416. package/src/task-agent/actions.ts +69 -1
  417. package/src/task-agent/green-sweep.ts +4 -0
  418. package/src/task-agent/live-moves.ts +160 -4
  419. package/src/task-agent/parent-host.ts +123 -3
  420. package/src/task-agent/shadow.ts +7 -1
  421. package/src/task-agent/task-hand.ts +54 -41
  422. package/src/task-agent/tier-split.ts +127 -0
  423. package/src/task-agent/work-order-build.ts +2 -0
  424. package/src/task-agent/work-order.ts +3 -2
  425. package/src/task-orchestrator/generator-prompt.ts +60 -11
  426. package/src/task-orchestrator/surfaces/pod-account-broker.ts +33 -0
  427. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  428. package/src/task-orchestrator/surfaces/pod-command-job.ts +45 -7
  429. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  430. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  431. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
  432. package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
  433. package/src/task-orchestrator/surfaces/pod-source-receive.ts +18 -0
  434. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  435. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
  436. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
  437. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +37 -5
  438. package/src/task-orchestrator/surfaces/self-implement-pod.ts +368 -36
  439. package/src/task-orchestrator/surfaces/self-implement.ts +23 -0
  440. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  441. package/src/tui/README.md +2 -0
  442. package/src/tui/chat/background-job-status.ts +54 -0
  443. package/src/tui/chat/log-view.ts +80 -0
  444. package/src/tui/entry.ts +406 -0
  445. package/src/tui/input/composer.ts +144 -0
  446. package/src/tui/seat-mail-boot.ts +59 -0
  447. package/src/tui/slash/compact.ts +100 -0
  448. package/src/tui/slash/new-session.ts +35 -0
  449. package/src/tui-client/local-chat-turn.ts +239 -0
  450. package/src/tui-client/local-harness-command.ts +63 -0
  451. package/src/tui-client/local-provider-command.ts +184 -0
  452. package/src/user-config.ts +4 -2
  453. package/src/ux-sim/event-monkey.ts +378 -0
  454. package/src/ux-sim/fake-bin.ts +42 -7
  455. package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
  456. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  457. package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
  458. package/src/version/packed-revision.json +1 -1
  459. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +0 -79
  460. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
  463. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
  465. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
  467. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
  468. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +0 -34
  479. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/3498.cf2a15a8a9e5b926.js +0 -226
  485. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +0 -32
  487. package/apps/pwa/out/_next/static/chunks/3837.722e053fb9f321ad.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
  490. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
  491. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
  492. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
  493. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
  494. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
  497. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
  504. package/apps/pwa/out/_next/static/chunks/5446.edf141cff9ef647d.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
  506. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
  517. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
  520. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +0 -41
  527. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
  530. package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
  533. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
  547. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
  549. package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
  603. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/ffdc3a04.b9c23c1b28dd4a96.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
  611. /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → T1mBQqmkwKDLGtyisDCOd}/_ssgManifest.js +0 -0
@@ -4,7 +4,7 @@ import { appendFileSync, chmodSync, copyFileSync, existsSync, mkdirSync, mkdtemp
4
4
  import { hostname, tmpdir } from 'node:os';
5
5
  import { createHash, randomUUID } from 'node:crypto';
6
6
  import { dirname, join, resolve } from 'node:path';
7
- import { debug } from '../../src/debug/log.js';
7
+ import { debug, redactSecretText } from '../../src/debug/log.js';
8
8
  import { registerStandaloneLogSink } from '../../src/domains/standalone-log-sink.js';
9
9
  import { landingFreezeMessage, readLandingFreeze } from '../../src/release-loop/landing-freeze.js';
10
10
  import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/resolve.js';
@@ -13,8 +13,12 @@ import { diffFailures, junitFailures, parseFailures, parseTimedOutFailures } fro
13
13
  import { loadEnvKnownFailures, splitKnownEnv } from './env-known-failures';
14
14
  import { loadGateBatchSafe } from './gate-batch-safe';
15
15
  import { baselineFromCutLogs } from './baseline-from-logs';
16
- import { mergePartialFailures, readPartialPlan, testFileOfId, verifyDocsOnlyCarry } from './gate-partial';
16
+ import { mergePartialFailures, readPartialPlanResult, testFileOfId, verifyDocsOnlyCarry } from './gate-partial';
17
17
  import { planGateRadiusShadow, shadowActual, writeGateRadiusShadow, type GateRadiusShadowPlan } from './gate-radius-shadow';
18
+ import { planHardRehearsalRadius, partialGateImagesMatch, preflightGateImageDigest } from './gate-radius-live';
19
+ import { actualGatePodImageDigest, gateBaselineReceipt, gateEnvFingerprint, gateGraphPins, gateSourcePins,
20
+ POD_SWEEP_INTEGRATION_ONLY } from './gate-baseline-receipt';
21
+ export { POD_SWEEP_INTEGRATION_ONLY } from './gate-baseline-receipt';
18
22
  import { logPlanWalltime, planDurations, readFileMemory } from './shard-plan';
19
23
  import { defaultGateHostMirrorReaders, resolveGateHostMirror, type GateHostMirror, type GateHostMirrorReaders } from './gate-host-mirror';
20
24
  import { isGateSpawnLaneFile, planGateSpawnSeparatedShards } from './spawn-lane';
@@ -67,6 +71,8 @@ export function warmCommandMatchesRequest(command: WarmWorkerCommand, request: O
67
71
  }
68
72
 
69
73
  interface CommandResult { rc: number; output: string; passedIds?: string[]; stalledEnv?: Array<{ file: string; reason: 'no-output' }>; timedOut?: boolean;
74
+ /** Identity and complete selected inventory of this Pod sweep; only the producer may issue it. */
75
+ podSweep?: { id: string; shards: number; files: string[] };
70
76
  /** Complete, source-bound one-file Job result for shadow comparison; absent means unmeasured. */
71
77
  warmReference?: WarmWorkerFileResult | null;
72
78
  warmAttemptId?: string;
@@ -75,6 +81,13 @@ interface CommandResult { rc: number; output: string; passedIds?: string[]; stal
75
81
  abortedShards?: number;
76
82
  /** Each contributing Pod leaf already passed failuresOf; repeated printed ids cannot add new failures. */
77
83
  validatedShards?: boolean }
84
+ function redactedGateLogTail(input: string): string {
85
+ // Redact before trimming: a truncated token might no longer match the redaction rule.
86
+ const bytes = Buffer.from(redactSecretText(input), 'utf8');
87
+ let start = Math.max(0, bytes.length - 16_384);
88
+ while (start < bytes.length && (bytes[start]! & 0xc0) === 0x80) start++;
89
+ return bytes.subarray(start).toString('utf8');
90
+ }
78
91
  export interface GateRunner {
79
92
  command(cmd: string, args: string[], cwd: string, limitMs?: number): Promise<CommandResult>;
80
93
  localCommand(cmd: string, args: string[], cwd: string, limitMs?: number): Promise<CommandResult>;
@@ -93,6 +106,10 @@ export interface GateRunner {
93
106
  }
94
107
  export interface GateOptions {
95
108
  commit: string;
109
+ /** The graph run that launched this gate; direct hard rehearsal instead pins source bytes explicitly. */
110
+ graphRunId?: string;
111
+ /** Only a direct hard rehearsal may pin graph bytes from its measured Git commit. */
112
+ rehearsalBaseline?: boolean;
96
113
  forceFreeze?: boolean;
97
114
  version: string;
98
115
  baselineVersion?: string;
@@ -154,6 +171,9 @@ export interface GateOptions {
154
171
  liveLog?: (job: { name: string; context?: string }) => string | null;
155
172
  /** false = the stop did not take; the watch asks again every poll until it does (void = taken). */
156
173
  stopJob?: (job: { name: string; context?: string }) => boolean | void;
174
+ /** Failure-only Pod status and log reader; injected tests never call the live cluster. */
175
+ failureEvidence?: (job: { name: string; context?: string }) => { podName?: string; termination?: { reason?: string; message?: string; exitCode?: number; finishedAt?: string }; logTail?: string; error?: string };
176
+ failureKubectl?: typeof defaultKubectl;
157
177
  /** How often the stall watch reads the live log (ms); omitted = {@link GATE_POD_STALL_POLL_MS}. */
158
178
  stallPollMs?: number;
159
179
  /** GATE-POD-STALL-FAILFAST ① — seconds a shard may go without its part logs growing once test output began, before
@@ -218,6 +238,10 @@ export interface GateResult {
218
238
  /** GATE-POD-STALL-FAILFAST — the shard (and its one fresh retry) printed no test output within the stall window: unmeasured. */
219
239
  stall?: { seconds: number; sinceCheckoutMs: number } }>;
220
240
  partialSummary?: { pass: number; fail: number; errors: number; ran: number; files: number };
241
+ /** Number of complete shards retained when an incomplete sweep is resumed. */
242
+ preservedShardCount?: number;
243
+ /** Completed shard measurements retained when another shard stalled, so same-commit resume can reuse them safely. */
244
+ partialFailures?: SweepFailures;
221
245
  /** GATE-PARTIAL — this verdict re-ran only these files and carried the prior gate's results for the rest. */
222
246
  partial?: { priorCommit: string; files: number };
223
247
  /** GATE-INTRO-RECHECK — new failures that were only the «timed out» shape and passed one isolated re-run with a
@@ -971,7 +995,7 @@ export function readShardArtifacts(dir: string, parts: readonly (readonly string
971
995
  export const gateUnfinishedHint = (relativePath: string, bytes: number) => `[gate] unfinished: ${relativePath} · ${bytes}B (진행 중 part 출력은 그 파일)`;
972
996
 
973
997
  // review-model-ab: Pod 에서 출력 없이 멈춤 2/2(10-04 0.2.11 · 로컬 단독 4/0 · 1.7s) — GATE-STALL 수리 전까지 Pod 밖.
974
- export const POD_SWEEP_INTEGRATION_ONLY: readonly string[] = ['scripts/install.test.ts', 'scripts/review-model-ab.test.ts'];
998
+ // The shared exclusion list lives in gate-baseline-receipt so radius verification uses the producer's rule.
975
999
  /** Nightly-only whole-repository cases; gate runs the fixture cases in these same files. */
976
1000
  export const GATE_NIGHTLY_AUDITS: readonly string[] = [
977
1001
  // Replaces F12's real-repo bucket B apps/pwa scope check and its whole-repo export partition check.
@@ -1132,7 +1156,8 @@ export function readIsolatedRun(run: CommandResult, label: string, file: string)
1132
1156
  }
1133
1157
 
1134
1158
  class StalledPodShards extends Error {
1135
- constructor(readonly stalledShards: NonNullable<GateResult['stalledShards']>, readonly partialSummary: NonNullable<GateResult['partialSummary']>, readonly abortedShards = 0) {
1159
+ constructor(readonly stalledShards: NonNullable<GateResult['stalledShards']>, readonly partialSummary: NonNullable<GateResult['partialSummary']>,
1160
+ readonly partialFailures: SweepFailures, readonly preservedShardCount: number, readonly abortedShards = 0) {
1136
1161
  const unmeasured = stalledShards.filter((item) => item.stall);
1137
1162
  const exitCode = stalledShards.filter((item) => item.reason === 'exit-code');
1138
1163
  super(`pod sweep incomplete: stalled shards ${stalledShards.map(({ shard }) => shard).join(', ')}`
@@ -1142,6 +1167,23 @@ class StalledPodShards extends Error {
1142
1167
  }
1143
1168
  }
1144
1169
 
1170
+ /** Read completed shard failures without letting one malformed shard hide the stalled-shard verdict. */
1171
+ export function partialFailuresOf(runs: readonly (CommandResult & { files: number })[]): SweepFailures {
1172
+ return runs.reduce<SweepFailures>((sum, run) => {
1173
+ try {
1174
+ const parsed = failuresOf({ rc: run.rc, output: run.output, validatedShards: true }, `pod partial shard ${run.files}`);
1175
+ sum.failures.push(...parsed.failures);
1176
+ sum.errors.push(...parsed.errors);
1177
+ } catch (error) {
1178
+ debug.log('release-loop.gate', 'pod-partial-failures-unreadable', {
1179
+ files: run.files,
1180
+ reason: error instanceof Error ? error.message : String(error),
1181
+ }, { level: 'warn' });
1182
+ }
1183
+ return sum;
1184
+ }, { failures: [], errors: [] });
1185
+ }
1186
+
1145
1187
  class WarmRecheckIncomplete extends Error {
1146
1188
  constructor(message: string, readonly file: string, readonly shadow: WarmShadowObservation) { super(message); }
1147
1189
  }
@@ -1292,6 +1334,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1292
1334
  }
1293
1335
  : localCommand);
1294
1336
  const podSweep = async (tree: string, logDir: string | undefined, pod: NonNullable<GateOptions['pod']>, only?: readonly string[]): Promise<CommandResult> => {
1337
+ const sweepId = randomUUID();
1295
1338
  const shardCount = pod.shards ?? 24;
1296
1339
  const isolationConcurrency = pod.isolationConcurrency ?? 4;
1297
1340
  // GATE-TIMEOUT-HEAL ①: the configured value is the floor; each shard's own deadline is shardDeadlineSeconds(planned).
@@ -1434,6 +1477,33 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1434
1477
  }
1435
1478
  return '';
1436
1479
  };
1480
+ const failureEvidence = pod.failureEvidence ?? ((job: { name: string; context?: string }) => {
1481
+ if (!job.context) return { error: '수거 실패 · Job 배치 context 없음' };
1482
+ const prefix = ['--context', job.context, '--request-timeout=5s', '-n', 'elanous-test'];
1483
+ const errors: string[] = [];
1484
+ let termination: { reason?: string; message?: string; exitCode?: number; finishedAt?: string } | undefined;
1485
+ let podName: string | undefined;
1486
+ let latestEndedAt = -Infinity;
1487
+ const status = (pod.failureKubectl ?? defaultKubectl)([...prefix, 'get', 'pods', '-l', `job-name=${job.name}`, '-o', 'json']);
1488
+ if (status.status !== 0) errors.push(`Pod 상태: ${status.stderr.trim() || `kubectl rc=${status.status}`}`);
1489
+ else try {
1490
+ const pods = JSON.parse(status.stdout) as { items?: Array<{ metadata?: { name?: string; creationTimestamp?: string }; status?: { containerStatuses?: Array<{ name?: string; state?: { terminated?: typeof termination } }> } }> };
1491
+ for (const item of pods.items ?? []) {
1492
+ const child = item.status?.containerStatuses?.find((container) => container.name === 'child');
1493
+ const ended = child?.state?.terminated;
1494
+ if (!ended || !item.metadata?.name) continue;
1495
+ const endedAt = Date.parse(ended.finishedAt ?? item.metadata.creationTimestamp ?? '');
1496
+ const rank = Number.isFinite(endedAt) ? endedAt : -Infinity;
1497
+ if (!termination || rank > latestEndedAt) { podName = item.metadata.name; termination = ended; latestEndedAt = rank; }
1498
+ }
1499
+ if (!termination) errors.push('Pod 상태: child 종료 사유 없음');
1500
+ } catch (error) { errors.push(`Pod 상태 JSON: ${String(error)}`); }
1501
+ const logs = podName ? (pod.failureKubectl ?? defaultKubectl)([...prefix, 'logs', `pod/${podName}`, '-c', 'child', '--tail=100']) : undefined;
1502
+ if (!logs) errors.push('로그: 종료된 Pod 이름 없음');
1503
+ else if (logs.status !== 0) errors.push(`로그: ${logs.stderr.trim() || `kubectl rc=${logs.status}`}`);
1504
+ return { ...(podName ? { podName } : {}), ...(termination ? { termination } : {}), ...(logs?.status === 0 ? { logTail: logs.stdout } : {}),
1505
+ ...(errors.length ? { error: `수거 실패 · ${errors.join(' · ')}` } : {}) };
1506
+ });
1437
1507
  type ShardRun = { output: string; rc: number; pass: number; fail: number; errors: number; ran: number; files: number; passedIds: string[] };
1438
1508
  type ShardReason = NonNullable<GateResult['stalledShards']>[number]['reason'];
1439
1509
  // 깊이 끝 OOM 조각은 «조각 전체»를 파일 하나씩 격리한다 — 상한 40 이면 나머지가 못 잰 채 남았다(09-30 ① 7번 조각 110 파일).
@@ -1513,6 +1583,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1513
1583
  const stamp = (phase: string) => { phaseTimes[phase] = new Date().toISOString(); };
1514
1584
  let podStages: Record<string, number> | undefined;
1515
1585
  let podLifecycle: Record<string, string> | undefined;
1586
+ let imageDigest: string | null = null;
1516
1587
  let podJobName: string | undefined;
1517
1588
  let batchArtifactsComplete = true;
1518
1589
  let junit: string | undefined;
@@ -1522,6 +1593,13 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1522
1593
  let lastFile: string | undefined;
1523
1594
  let jobFailed = false;
1524
1595
  let jobError = '';
1596
+ let failureCapture: ReturnType<NonNullable<NonNullable<GateOptions['pod']>['failureEvidence']>> | undefined;
1597
+ let jobNameForCapture: string | undefined;
1598
+ let jobContextForCapture: string | undefined;
1599
+ const captureFailure = () => {
1600
+ try { failureCapture = failureEvidence({ name: jobNameForCapture ?? 'unplaced', context: jobContextForCapture }); }
1601
+ catch (error) { failureCapture = { error: `수거 실패 · ${String(error)}` }; }
1602
+ };
1525
1603
  /** GATE-MULTI-HOST — the member this shard's Job was placed on (recorded in the shard json / log / board). */
1526
1604
  let placedOn: string | undefined;
1527
1605
  let timedOut = false;
@@ -1572,6 +1650,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1572
1650
  // The admission wait is not the shard's run time: deadline/timeout judgment and the measured duration start here.
1573
1651
  start = Date.now();
1574
1652
  const jobName = `gate-${randomUUID()}`;
1653
+ jobNameForCapture = jobName;
1575
1654
  // The member's context is known once the Job is placed; the live log is read (and the Job stopped) there.
1576
1655
  let jobContext: string | undefined;
1577
1656
  const liveJob = () => ({ name: jobName, ...(jobContext ? { context: jobContext } : {}) });
@@ -1593,8 +1672,15 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1593
1672
  } : {}) }) : undefined;
1594
1673
  const placed = admitted.release;
1595
1674
  const job = await podCommand({
1675
+ provenanceGate: true,
1676
+ provenance: { actorKind: process.env.ELANOUS_SEAT ? 'seat' : 'loop', actor: process.env.ELANOUS_SEAT || 'release-loop',
1677
+ character: 'gate-shard-runner', launchHost: hostname(), entrance: process.env.ELANOUS_RELEASE_ENTRANCE?.trim() || 'release-run',
1678
+ kind: 'gate-shard', run: process.env.ELANOUS_RUN_ID || sweepId, phase: 'release-gate', requestedAt: new Date().toISOString(),
1679
+ graphNode: 'gate', version: pod.shardsFile?.version, commit, shard: `${shard + 1}-of-${shards.length}`,
1680
+ reason: `release gate shard ${shard + 1}/${shards.length}`, pool: pod.pool, cpuReq: cpu.request,
1681
+ memReq: memoryLimit ?? POD_ISOLATION_MEMORY_LIMIT, warmReused: false },
1596
1682
  pool: pod.pool, poolScheduler: trackedPool(shard, depth > 0 || branch !== '', (member) => {
1597
- stamp('poolPlaced'); jobContext = member.context; placedOn = member.context; placed();
1683
+ stamp('poolPlaced'); jobContext = member.context; jobContextForCapture = member.context; placedOn = member.context; placed();
1598
1684
  if (branch === '-tail') tailPlacedHost = member.context;
1599
1685
  }, skipMembers), clone: true, source: { kind: 'commit', sha: commit }, deadlineSeconds: shardDeadline,
1600
1686
  ...gateHostMirror(pod),
@@ -1609,13 +1695,20 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1609
1695
  }).finally(() => watch?.stop());
1610
1696
  stamp('jobReturned');
1611
1697
  podJobName = job.job;
1698
+ // poolOverride is the injected scheduler used by isolated tests; it has no authenticated kubectl
1699
+ // context. Those sweeps intentionally cannot mint a valid baseline receipt (missing observed digest).
1700
+ // Production pool sweeps always use this Kubernetes lookup; lookup failure is receipt-invalid only.
1612
1701
  if (!poolOverride && placedOn) {
1613
1702
  try {
1614
1703
  const got = defaultKubectl(['--context', placedOn, '-n', 'elanous-test', 'get', 'pods', '-l', `job-name=${job.job}`, '-o', 'json']);
1615
- if (got.status === 0) podLifecycle = readGatePodLifecycle(got.stdout);
1704
+ if (got.status === 0) {
1705
+ podLifecycle = readGatePodLifecycle(got.stdout);
1706
+ imageDigest = actualGatePodImageDigest(got.stdout);
1707
+ }
1616
1708
  } catch { /* timings never change the verdict */ }
1617
1709
  }
1618
1710
  jobExitCode = job.exitCode;
1711
+ if (job.exitCode !== 0) captureFailure();
1619
1712
  batchArtifactDir = job.artifactsDir;
1620
1713
  const read = readShardArtifacts(job.artifactsDir, parts);
1621
1714
  batchArtifactsComplete = !batchIsolation || parts.every((_, index) =>
@@ -1649,6 +1742,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1649
1742
  } catch (error) {
1650
1743
  jobFailed = true;
1651
1744
  jobError = error instanceof Error ? error.message : String(error);
1745
+ if (!failureCapture) captureFailure();
1652
1746
  }
1653
1747
  // A launch that failed before placement still gives its admission back (release is idempotent).
1654
1748
  admitted?.release();
@@ -1683,9 +1777,20 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1683
1777
  if (unfinishedLog !== undefined) writeFileSync(unfinishedDestination, unfinishedLog, { mode: 0o600 });
1684
1778
  else rmSync(unfinishedDestination, { force: true });
1685
1779
  writeFileSync(join(logDir, `pod-${shard}${branch}.json`), JSON.stringify({ durationMs, rc: rc ?? null,
1686
- ...(stall ? { reason: 'stall', finishedFiles: 0, stallSeconds: stall.seconds, sinceCheckoutMs: stall.sinceCheckoutMs } : timedOut ? { reason: 'timeout', finishedFiles: finished.length } : {}), files: paths, plannedSeconds: estimated(paths), deadlineSeconds: shardDeadline, shardCount: shards.length, commit, runKey, attemptId, ...(parentAttempt ? { parentAttempt } : {}), jobExitCode: jobExitCode ?? null, jobFailed, ...(placedOn ? { host: placedOn } : {}),
1780
+ ...(stall ? { reason: 'stall', finishedFiles: 0, stallSeconds: stall.seconds, sinceCheckoutMs: stall.sinceCheckoutMs } : timedOut ? { reason: 'timeout', finishedFiles: finished.length } : {}), files: paths, plannedSeconds: estimated(paths), deadlineSeconds: shardDeadline, shardCount: shards.length, sweepId, commit, runKey, attemptId, ...(parentAttempt ? { parentAttempt } : {}), jobExitCode: jobExitCode ?? null, jobFailed, ...(placedOn ? { host: placedOn } : {}),
1687
1781
  ...(Object.keys(phaseTimes).length ? { phaseTimes } : {}), ...(podStages ? { podStages } : {}),
1688
1782
  ...(podLifecycle && Object.keys(podLifecycle).length ? { podLifecycle } : {}),
1783
+ ...(failureCapture ? { failureCapture: {
1784
+ ...(failureCapture.podName ? { podName: failureCapture.podName } : {}),
1785
+ ...(failureCapture.termination ? { termination: {
1786
+ ...failureCapture.termination,
1787
+ ...(failureCapture.termination.reason ? { reason: redactSecretText(failureCapture.termination.reason) } : {}),
1788
+ ...(failureCapture.termination.message ? { message: redactSecretText(failureCapture.termination.message) } : {}),
1789
+ } } : {}),
1790
+ ...(failureCapture.logTail !== undefined ? { logTail: redactedGateLogTail(failureCapture.logTail) } : {}),
1791
+ ...(failureCapture.error ? { error: redactSecretText(failureCapture.error) } : {}),
1792
+ } } : {}),
1793
+ ...(imageDigest ? { imageDigest } : {}),
1689
1794
  ...(fileSeconds !== undefined ? { fileSeconds, testSeconds } : {}), ...(testWallSeconds !== undefined ? { testWallSeconds } : {}),
1690
1795
  ...(podOverheadSeconds !== undefined ? { podOverheadSeconds } : {}),
1691
1796
  ...(unfinishedLogBytes !== undefined ? { unfinishedLogBytes } : {}),
@@ -1963,10 +2068,15 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
1963
2068
  stallSeconds, measuredFiles: total.files }, { level: 'warn' });
1964
2069
  // An unmeasured (stalled) shard is never handed to the host re-run as an environment stall: the gate fails now.
1965
2070
  if (abortedShards) debug.log('release-loop.gate', 'pod-sweep-aborted', { shards: abortedShards, midRunStallSeconds }, { level: 'warn' });
1966
- if (stalledShards.some((item) => item.reason !== 'no-output' || item.files.length !== 1 || item.stall)) throw new StalledPodShards(stalledShards, total, abortedShards);
2071
+ if (stalledShards.some((item) => item.reason !== 'no-output' || item.files.length !== 1 || item.stall)) {
2072
+ const measuredFailures = partialFailuresOf(measured);
2073
+ throw new StalledPodShards(stalledShards, total, measuredFailures,
2074
+ results.filter((item) => item.stalled.length === 0).length, abortedShards);
2075
+ }
1967
2076
  if (total.ran === 0 && total.errors === 0 && !stalledShards.length) throw new Error('sweep incomplete: no tests ran');
1968
2077
  const outputs = measured.map((run) => run.output.replace(/(?:^|\n)\s*\d+ (?:pass|fail|errors?)\s*(?=\n|$)/g, '\n').replace(/Ran \d+ tests? across \d+ files?\.?/g, ''));
1969
2078
  return { rc: total.fail + total.errors ? 1 : 0, output: outputs.join('\n') + `\n${total.pass} pass\n${total.fail} fail\n${total.errors} errors\nRan ${total.ran} tests across ${total.files} files.\n`, validatedShards: true,
2079
+ podSweep: { id: sweepId, shards: shards.length, files: assignable },
1970
2080
  passedIds: [...new Set(measured.flatMap((run) => run.passedIds))].sort(),
1971
2081
  stalledEnv: stalledShards.flatMap((item) => item.files.map((file) => ({ file, reason: 'no-output' as const }))),
1972
2082
  ...(abortedShards ? { abortedShards } : {}) };
@@ -2002,6 +2112,12 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
2002
2112
  cachePrefix: bunCache ? podBunCacheVolume(bunCache).shellPrefix : '', installSlots, parallelParts: files.length > 1 ? 2 : 1,
2003
2113
  partLimitSeconds, sourceBinding: { cutSha: commit, attemptId }, ...(relaxed ? { testTimeoutMs: GATE_TIMEOUT_RECHECK_MS } : {}) });
2004
2114
  const job = await podCommand({ pool: pod.pool, ...(poolOverride ? { poolScheduler: poolOverride } : {}), clone: true,
2115
+ provenanceGate: true,
2116
+ provenance: { actorKind: process.env.ELANOUS_SEAT ? 'seat' : 'loop', actor: process.env.ELANOUS_SEAT || 'release-loop',
2117
+ character: 'gate-shard-runner', launchHost: hostname(), entrance: 'release-recheck', kind: 'gate-recheck',
2118
+ run: process.env.ELANOUS_RUN_ID || attemptId, phase: 'release-gate', requestedAt: new Date().toISOString(),
2119
+ graphNode: 'gate-triage', commit, reason: `release gate recheck ${files.length} files`, pool: pod.pool,
2120
+ memReq: POD_ISOLATION_MEMORY_LIMIT, warmReused: false },
2005
2121
  source: { kind: 'commit', sha: commit }, deadlineSeconds, ...(bunCache ? { bunCache } : {}), ...gateHostMirror(pod),
2006
2122
  ...(installSlots > 0 ? { installSlots: POD_INSTALL_SLOTS_HOST_PATH } : {}), ...(pod.cpu ? { cpu: pod.cpu } : {}),
2007
2123
  memoryLimit: POD_ISOLATION_MEMORY_LIMIT, name: `gate-recheck-${randomUUID()}`, command: ['bash', '-lc', shell] });
@@ -2295,7 +2411,8 @@ export function saveBaselineFileCache(ledger: string, commit: string, rows: Base
2295
2411
  } finally { if (existsSync(temp)) rmSync(temp); }
2296
2412
  }
2297
2413
 
2298
- export async function judgeGate(opts: GateOptions, runner: GateRunner = createGateRunner(opts.repo ?? process.cwd(), opts.remote)): Promise<GateResult> {
2414
+ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGateRunner(opts.repo ?? process.cwd(), opts.remote),
2415
+ imageProbe: typeof preflightGateImageDigest = preflightGateImageDigest): Promise<GateResult> {
2299
2416
  const start = Date.now();
2300
2417
  if (opts.pod?.warmReplay) opts = { ...opts, pod: { ...opts.pod,
2301
2418
  warmShadowScope: { requested: false, attempts: 0 } } };
@@ -2340,6 +2457,8 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
2340
2457
  || (opts.baselineVersion && !versionPattern.test(opts.baselineVersion))
2341
2458
  || (opts.baselineCommit && !sha.test(opts.baselineCommit))) throw new Error('invalid commit or version');
2342
2459
  if (!opts.baselineVersion) throw new Error('previous release version required (--baseline-version)');
2460
+ if (opts.rehearsalBaseline && (opts.graphRunId || !opts.pod || !/-rc\.\d+$/.test(opts.version)))
2461
+ throw new Error('rehearsal baseline requires a direct Pod gate with an isolated rc version');
2343
2462
  // Observation only. Failure to plan cannot change the gate selector or verdict.
2344
2463
  try { radiusShadow = planGateRadiusShadow({ repo, ledgerRoot: ledger, version: opts.version,
2345
2464
  baselineVersion: opts.baselineVersion, forCommit: opts.commit, instanceRoot: root,
@@ -2388,12 +2507,31 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
2388
2507
  for (const dir of [cutTree, join(cutTree, 'apps/pwa')]) check(await runner.command('bun', ['install'], dir), `bun install ${dir}`);
2389
2508
  // GATE-PARTIAL: a plan made by `release resume --from gate --partial` for exactly this commit re-runs only its files.
2390
2509
  // Its logs go to cut-partial/ — the full cut/ logs stay whole (the next release reads them as a baseline source).
2391
- const partial = readPartialPlan(roots, opts.version, opts.commit);
2392
- if (partial) debug.log('release-loop.gate', 'partial-regate', { version: opts.version, priorCommit: partial.priorCommit, commit: opts.commit, files: partial.files.length });
2510
+ const partialRead = readPartialPlanResult(roots, opts.version, opts.commit);
2511
+ const explicitPartial = partialRead.plan;
2512
+ const rehearsalStampPresent = ['hard-5h', 'hard-mid'].some((step) =>
2513
+ existsSync(join(root, 'release', opts.version, 'rehearsal', `${step}.json`)));
2514
+ const currentImage = !explicitPartial && opts.graphRunId && opts.pod && rehearsalStampPresent
2515
+ ? imageProbe(opts.pod.pool) : null;
2516
+ const radius = !explicitPartial && opts.graphRunId && opts.pod && rehearsalStampPresent
2517
+ ? planHardRehearsalRadius({ root, repo, version: opts.version, forCommit: opts.commit,
2518
+ graphPins: gateGraphPins(root, opts.graphRunId), envFingerprint: gateEnvFingerprint(process.env), imageDigest: currentImage })
2519
+ : null;
2520
+ if (radius) debug.log('release-loop.gate', 'radius-live-plan', { version: opts.version, reason: radius.reason,
2521
+ files: radius.plan?.files.length ?? null, rehearsalRunId: radius.rehearsalRunId ?? null });
2522
+ let partial = explicitPartial ?? radius?.plan ?? null;
2523
+ debug.log('release-loop.gate', partial ? 'partial-regate' : 'partial-fallback', {
2524
+ version: opts.version, priorCommit: partial?.priorCommit ?? null, commit: opts.commit,
2525
+ planKind: partial?.kind ?? 'full', remeasureFileCount: partial?.files.length ?? 0,
2526
+ preservedShardCount: partial?.kind === 'recheck' && 'preservedShardCount' in partial
2527
+ && typeof partial.preservedShardCount === 'number' ? partial.preservedShardCount : 0,
2528
+ fallbackReason: partial ? undefined : partialRead.fallbackReason,
2529
+ });
2393
2530
  if (partial?.kind === 'carry') {
2531
+ const carryPriorCommit = partial.priorCommit;
2394
2532
  // The plan alone is not evidence: the old cut and its verdict must still be complete and clean at this SHA.
2395
- if (!verifyDocsOnlyCarry(repo, partial.priorCommit, opts.commit))
2396
- throw new Error(`carry plan diff is not docs-only: ${partial.priorCommit}..${opts.commit}`);
2533
+ if (!verifyDocsOnlyCarry(repo, carryPriorCommit, opts.commit))
2534
+ throw new Error(`carry plan diff is not docs-only: ${carryPriorCommit}..${opts.commit}`);
2397
2535
  const trusted = roots.some((location) => {
2398
2536
  const dir = join(location, 'release', opts.version);
2399
2537
  const failuresPath = join(dir, 'gate-failures.json');
@@ -2401,11 +2539,11 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
2401
2539
  if (!existsSync(failuresPath) || !existsSync(verdictPath)) return false;
2402
2540
  const failures = JSON.parse(readFileSync(failuresPath, 'utf8')) as { commit?: unknown; failures?: unknown; errors?: unknown };
2403
2541
  const verdict = JSON.parse(readFileSync(verdictPath, 'utf8')) as { commit?: unknown; outcome?: unknown };
2404
- return failures.commit === partial.priorCommit && Array.isArray(failures.failures) && failures.failures.length === 0
2542
+ return failures.commit === carryPriorCommit && Array.isArray(failures.failures) && failures.failures.length === 0
2405
2543
  && (failures.errors === undefined || (Array.isArray(failures.errors) && failures.errors.length === 0))
2406
- && verdict.commit === partial.priorCommit && verdict.outcome === 'ok';
2544
+ && verdict.commit === carryPriorCommit && verdict.outcome === 'ok';
2407
2545
  });
2408
- if (!trusted) throw new Error(`carry plan has no complete clean gate at ${partial.priorCommit}`);
2546
+ if (!trusted) throw new Error(`carry plan has no complete clean gate at ${carryPriorCommit}`);
2409
2547
  }
2410
2548
  // GATE-SKIP-KNOWN-RETRY — the ids the verdict will not count as introduced (the recorded baseline ⊕ env-known), read
2411
2549
  // before the sweep so a shard failing only with them skips its isolation retries. No recorded baseline = no skip.
@@ -2420,12 +2558,23 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
2420
2558
  } catch (error) { debug.log('release-loop.gate', 'known-failures-unavailable', { error: String(error) }); }
2421
2559
  }
2422
2560
  const durationSource = join(ledger, 'release', opts.baselineVersion, 'gate-logs', 'cut');
2423
- const cutRun = partial?.kind === 'carry' ? undefined : await runner.sweep(cutTree, join(root, 'release', opts.version, 'gate-logs', partial ? 'cut-partial' : 'cut'),
2561
+ const runCut = (selected: typeof partial) => selected?.kind === 'carry' ? undefined : runner.sweep(cutTree,
2562
+ join(root, 'release', opts.version, 'gate-logs', selected ? 'cut-partial' : 'cut'),
2424
2563
  opts.pod ? { ...opts.pod, durationSource, ...(knownFailures.length ? { knownFailures } : {}), onSelectionTimed: ({ ms }) => { result.selectionMs = ms; },
2425
2564
  // GATE-LIVE-OBS: the release ledger's shards.json (UX #24782) — never the run tree's universe; an explicit
2426
2565
  // --ledger-root (tests) keeps it in that ledger.
2427
2566
  shardsFile: { path: opts.ledgerRoot ? gateShardsPath(opts.version, opts.ledgerRoot) : gateShardsPath(opts.version), version: opts.version } } : undefined,
2428
- partial?.files);
2567
+ selected?.files);
2568
+ let cutRun = await runCut(partial);
2569
+ const radiusSelectionMatched = partial?.files && cutRun?.podSweep?.files
2570
+ && JSON.stringify([...partial.files].sort()) === JSON.stringify([...cutRun.podSweep.files].sort());
2571
+ if (radius?.plan && (!radiusSelectionMatched
2572
+ || !partialGateImagesMatch(root, opts.version, currentImage!, opts.commit, cutRun?.podSweep))) {
2573
+ debug.log('release-loop.gate', 'radius-live-image-drift', { version: opts.version,
2574
+ rehearsalRunId: radius.rehearsalRunId, action: 'full-sweep' }, { level: 'warn' });
2575
+ partial = null;
2576
+ cutRun = await runCut(null);
2577
+ }
2429
2578
  cutSweepRc = cutRun?.rc ?? null;
2430
2579
  cutSweepUsable = !!cutRun && (cutRun.rc === 0 || cutRun.rc === 1) && !cutRun.timedOut
2431
2580
  && !cutRun.abortedShards && !cutRun.stalledEnv?.length;
@@ -2816,6 +2965,8 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
2816
2965
  if (error instanceof StalledPodShards) {
2817
2966
  result.stalledShards = error.stalledShards;
2818
2967
  result.partialSummary = error.partialSummary;
2968
+ result.partialFailures = error.partialFailures;
2969
+ result.preservedShardCount = error.preservedShardCount;
2819
2970
  if (error.abortedShards) result.abortedShards = error.abortedShards;
2820
2971
  }
2821
2972
  } finally {
@@ -2866,6 +3017,13 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
2866
3017
  };
2867
3018
  const observed = { ...(result.selectionMs !== undefined ? { selectionMs: result.selectionMs } : {}),
2868
3019
  ...(result.warmShadow?.length ? { warmShadow: result.warmShadow } : {}) };
3020
+ // Receipt is advisory for a later radius gate. Missing identity makes reuse invalid, never this gate's verdict.
3021
+ const baselineReceipt = gateBaselineReceipt({ root, version: opts.version, commit: opts.commit,
3022
+ graphPins: gateGraphPins(root, opts.graphRunId) ?? (opts.rehearsalBaseline ? gateSourcePins(repo, opts.commit) : null),
3023
+ envFingerprint: gateEnvFingerprint(process.env),
3024
+ fullSweep: result.outcome === 'ok' && cutSweepUsable && !result.partial && !!cutFailures
3025
+ && !result.rcNonzeroNoFailures.length && !result.stalledShards?.length && !result.stalledEnv.length
3026
+ && !result.unmeasuredRecheckFiles?.length && !result.unmeasuredErrors?.length });
2869
3027
  try {
2870
3028
  for (const location of roots) {
2871
3029
  const path = verdictFile(location, opts.version);
@@ -2878,7 +3036,7 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
2878
3036
  try {
2879
3037
  const warmHistory = readWarmVerdictHistory(path) ?? [];
2880
3038
  writeFileSync(temp, JSON.stringify({ version: opts.version, commit: opts.commit,
2881
- outcome: result.outcome, ...ids, ...observed,
3039
+ outcome: result.outcome, ...ids, ...observed, baselineReceipt,
2882
3040
  ...(opts.pod?.warmReplay ? { baselineCommit, warmHistory } : {}) }, null, 2) + '\n', { mode: 0o600 });
2883
3041
  chmodSync(temp, 0o600);
2884
3042
  renameSync(temp, path);
@@ -2894,7 +3052,7 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
2894
3052
  try {
2895
3053
  const warmHistory = readWarmVerdictHistory(path) ?? [];
2896
3054
  writeFileSync(temp, JSON.stringify({ version: opts.version, commit: opts.commit,
2897
- outcome: result.outcome, ...ids, ...observed,
3055
+ outcome: result.outcome, ...ids, ...observed, baselineReceipt,
2898
3056
  ...(opts.pod?.warmReplay ? { baselineCommit, warmHistory } : {}) }, null, 2) + '\n', { mode: 0o600 });
2899
3057
  chmodSync(temp, 0o600);
2900
3058
  renameSync(temp, path);
@@ -3023,6 +3181,7 @@ export function parseOptions(args: string[], env: NodeJS.ProcessEnv): GateOption
3023
3181
  const arg = args[i];
3024
3182
  if (arg === '--help') return 'help';
3025
3183
  if (arg === '--json') continue;
3184
+ if (arg === '--rehearsal-baseline') { opts.rehearsalBaseline = true; continue; }
3026
3185
  // Applied after the loop and only to a Pod gate — on its own it must not turn a local gate into a Pod one (review r5).
3027
3186
  if (arg === '--fresh-shards') { freshShards = true; continue; }
3028
3187
  if (arg === '--rehearsal-tui') { opts.rehearsalTui = true; continue; }
@@ -3085,7 +3244,7 @@ export async function runGateNode(argv: string[], env: NodeJS.ProcessEnv, runner
3085
3244
  debug.log('release-loop.gate', 'executor', { version: opts.version, ...placement, requested: opts.executor ?? null });
3086
3245
  }
3087
3246
  if (opts === 'help') {
3088
- console.log('Usage: bun scripts/release-loop/gate-node.ts --commit <sha> --version <v> [--baseline-version <prev>] [--baseline-commit <sha>] [--remote <ssh-host>] [--remote-mirror <path>] [--pod-pool <pool>] [--pod-shards <n>] [--pod-shard-timeout-seconds <n>] [--recheck-file-limit <n>] [--fresh-shards] [--executor <pod|host>] [--json]\nWithout flags, input.commit, input.version and input.previousVersion come from the JSON file at ELANOUS_GRAPH_CONTEXT.\n--executor host (input.gateExecutor) ignores every pod option and sweeps on --remote (input.gateRemote, required).');
3247
+ console.log('Usage: bun scripts/release-loop/gate-node.ts --commit <sha> --version <v> [--baseline-version <prev>] [--baseline-commit <sha>] [--remote <ssh-host>] [--remote-mirror <path>] [--pod-pool <pool>] [--pod-shards <n>] [--pod-shard-timeout-seconds <n>] [--recheck-file-limit <n>] [--fresh-shards] [--executor <pod|host>] [--rehearsal-baseline] [--json]\nWithout flags, input.commit, input.version and input.previousVersion come from the JSON file at ELANOUS_GRAPH_CONTEXT.\n--executor host (input.gateExecutor) ignores every pod option and sweeps on --remote (input.gateRemote, required).\n--rehearsal-baseline pins source graph bytes only for a direct Pod gate on an isolated rc version.');
3089
3248
  return 0;
3090
3249
  }
3091
3250
  version = opts.version;
@@ -3098,7 +3257,7 @@ export async function runGateNode(argv: string[], env: NodeJS.ProcessEnv, runner
3098
3257
  throw new Error('release gate host reservation requires graph runId and pinned state root');
3099
3258
  const releaseHosts = context && hosts.length
3100
3259
  ? reserveReleaseGateHosts(reservationRoot!, context.runId!, hosts) : () => undefined;
3101
- try { result = await judge(opts, runner); }
3260
+ try { result = await judge(context?.runId ? { ...opts, graphRunId: context.runId } : opts, runner); }
3102
3261
  finally { releaseHosts(); }
3103
3262
  } catch (error) {
3104
3263
  result = { outcome: 'error', commit: '', introduced: [], preexisting: 0, fixed: 0, knownEnv: 0, knownEnvCleared: [], stalledEnv: [], rcNonzeroNoFailures: [], durationMs: Date.now() - start, error: String(error) };
@@ -27,7 +27,13 @@ export interface PartialPlan {
27
27
 
28
28
  /** G1: a second measurement of only the failed files on the very same release commit.
29
29
  * This is deliberately separate from PartialPlan, which compares two different commits. */
30
- export interface RecheckPlan extends PartialPlan { kind: 'recheck' }
30
+ export interface RecheckPlan extends PartialPlan {
31
+ kind: 'recheck';
32
+ /** Files from shards that could not produce a measurement; completed shard results remain in priorFailures/errors. */
33
+ stalledFiles?: string[];
34
+ /** Count of complete shards whose measurements are preserved in this recheck. */
35
+ preservedShardCount?: number;
36
+ }
31
37
 
32
38
  const FULL_SHA = /^[0-9a-f]{40}$/i;
33
39
  const RELEASE_VERSION = /^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/;
@@ -92,13 +98,49 @@ function validateRecheckPlan(raw: Partial<RecheckPlan>, version: string, path: s
92
98
  typeof raw.forCommit !== 'string' || !FULL_SHA.test(raw.forCommit) || raw.priorCommit !== raw.forCommit ||
93
99
  !Array.isArray(raw.priorFailures) || !raw.priorFailures.every((id) => typeof id === 'string') ||
94
100
  !Array.isArray(raw.priorErrors) || !raw.priorErrors.every((id) => typeof id === 'string') ||
95
- !Array.isArray(raw.files) || !raw.files.length || !raw.files.every((file) => typeof file === 'string')) invalid();
101
+ !Array.isArray(raw.files) || !raw.files.length || !raw.files.every((file) => typeof file === 'string') ||
102
+ (raw.preservedShardCount !== undefined && (!Number.isSafeInteger(raw.preservedShardCount) || raw.preservedShardCount < 0))) invalid();
96
103
  let expected: string[] = [];
97
- try { expected = [...new Set([...raw.priorFailures!, ...raw.priorErrors!].map(testFileOfId))].sort(); }
104
+ try {
105
+ const measuredFiles = [...raw.priorFailures!, ...raw.priorErrors!].map(testFileOfId);
106
+ const stalledFiles = raw.stalledFiles === undefined ? [] : raw.stalledFiles;
107
+ if (!Array.isArray(stalledFiles) || !stalledFiles.every((file) => typeof file === 'string' && TEST_FILE.test(file) && !file.split('/').includes('..'))) invalid();
108
+ if (raw.stalledFiles !== undefined && stalledFiles.some((file) => measuredFiles.includes(file))) invalid();
109
+ expected = [...new Set(stalledFiles)].sort();
110
+ // Legacy plans recheck every prior failed file. Stalled plans re-run only files from incomplete shards; all
111
+ // completed shard outcomes, including runtime errors, are preserved for the combined verdict.
112
+ if (raw.stalledFiles === undefined) expected = [...new Set(measuredFiles)].sort();
113
+ }
98
114
  catch { invalid(); }
99
115
  if (JSON.stringify(raw.files) !== JSON.stringify(expected)) invalid();
100
116
  }
101
117
 
118
+ /** Plan a same-commit retry after a Pod sweep reports stalled shards. Reuse completed outcomes and rerun stalled files. */
119
+ export function planStalledShardRecheck(input: { version: string; measuredCommit: string; forCommit: string;
120
+ failures: readonly string[]; errors: readonly string[]; stalledFiles: readonly string[]; preservedShardCount?: number;
121
+ existsAtCommit: (file: string) => boolean }):
122
+ { ok: true; plan: RecheckPlan } | { ok: false; reason: string } {
123
+ if (!RELEASE_VERSION.test(input.version)) return { ok: false, reason: 'invalid release version' };
124
+ if (!FULL_SHA.test(input.measuredCommit) || !FULL_SHA.test(input.forCommit)) return { ok: false, reason: 'commit is not a full sha' };
125
+ if (input.measuredCommit !== input.forCommit) return { ok: false, reason: 'recheck requires the same commit' };
126
+ try { [...input.failures, ...input.errors].forEach(testFileOfId); }
127
+ catch (error) { return { ok: false, reason: String(error instanceof Error ? error.message : error) }; }
128
+ const stalledFiles = [...new Set(input.stalledFiles)].sort();
129
+ if (!stalledFiles.length) return { ok: false, reason: 'no stalled test files to recheck' };
130
+ if (stalledFiles.some((file) => !TEST_FILE.test(file) || file.split('/').includes('..'))) return { ok: false, reason: 'unsafe stalled test path' };
131
+ const measuredFiles = [...new Set([...input.failures, ...input.errors].map(testFileOfId))];
132
+ if (stalledFiles.some((file) => measuredFiles.includes(file)))
133
+ return { ok: false, reason: 'stalled file overlaps a completed shard result' };
134
+ const files = stalledFiles;
135
+ try {
136
+ const missing = files.find((file) => !input.existsAtCommit(file));
137
+ if (missing) return { ok: false, reason: `failed test file missing at commit: ${missing}` };
138
+ } catch (error) { return { ok: false, reason: `test file existence unreadable: ${String(error)}` }; }
139
+ return { ok: true, plan: { kind: 'recheck', version: input.version, priorCommit: input.measuredCommit,
140
+ forCommit: input.forCommit, files, stalledFiles, ...(input.preservedShardCount === undefined ? {} : { preservedShardCount: input.preservedShardCount }),
141
+ priorFailures: [...input.failures], priorErrors: [...input.errors] } };
142
+ }
143
+
102
144
  export const partialPlanPath = (root: string, version: string) => join(root, 'release', version, 'gate-partial.json');
103
145
  /** The same test-file set the gate sweep runs (`git ls-files` filtered by this suffix). */
104
146
  const TEST_FILE = /^(?:[\w.-]+\/)*[\w.-]+\.test\.(?:tsx?|jsx?|mts|cts)$/;
@@ -182,24 +224,32 @@ export function clearPartialPlan(root: string, version: string): void {
182
224
  }
183
225
 
184
226
  /** The plan for exactly this commit, or null. A malformed plan is an error (never silently a full or partial gate). */
185
- export function readPartialPlan(roots: readonly string[], version: string, commit: string): PartialPlan | null {
227
+ export function readPartialPlanResult(roots: readonly string[], version: string, commit: string):
228
+ { plan: PartialPlan | null; fallbackReason: string | null } {
229
+ let fallbackReason: string | null = 'no-applicable-plan';
186
230
  for (const root of roots) {
187
231
  const path = partialPlanPath(root, version);
188
232
  if (!existsSync(path)) continue;
189
233
  const raw = JSON.parse(readFileSync(path, 'utf8')) as Partial<PartialPlan>;
234
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error(`invalid gate partial plan: ${path}`);
190
235
  if ((raw as Partial<RecheckPlan>).kind !== undefined && (raw as Partial<RecheckPlan>).kind !== 'recheck' && raw.kind !== 'carry')
191
236
  throw new Error(`invalid gate partial plan: ${path}`);
192
- // Until the gate consumer connects G1, the opt-in recheck plan is a shadow record.
193
- // A legacy full gate may run, but it must never interpret a same-commit recheck as a changed-tip partial gate.
237
+ // Only a well-formed stalled-shard recheck for this exact release commit enters the same-commit consumer path.
194
238
  if ((raw as Partial<RecheckPlan>).kind === 'recheck') {
195
- validateRecheckPlan(raw as Partial<RecheckPlan>, version, path);
239
+ const recheck = raw as Partial<RecheckPlan>;
240
+ validateRecheckPlan(recheck, version, path);
241
+ if (recheck.forCommit === commit && recheck.stalledFiles !== undefined)
242
+ return { plan: recheck, fallbackReason: null };
243
+ if (recheck.forCommit === commit) { fallbackReason = 'recheck-not-stalled-only'; continue; }
244
+ fallbackReason = 'plan-commit-mismatch';
196
245
  continue;
197
246
  }
198
247
  if (raw.version !== version || typeof raw.priorCommit !== 'string' || !/^[0-9a-f]{40}$/i.test(raw.priorCommit)
199
248
  || typeof raw.forCommit !== 'string' || !/^[0-9a-f]{40}$/i.test(raw.forCommit) || raw.priorCommit === raw.forCommit
200
249
  || !Array.isArray(raw.files) || (raw.files.length === 0) !== (raw.kind === 'carry')
201
250
  || !raw.files.every((file) => typeof file === 'string' && TEST_FILE.test(file) && !file.split('/').includes('..'))
202
- || !Array.isArray(raw.priorFailures) || !Array.isArray(raw.priorErrors)) throw new Error(`invalid gate partial plan: ${path}`);
251
+ || !Array.isArray(raw.priorFailures) || !Array.isArray(raw.priorErrors))
252
+ throw new Error(`invalid gate partial plan: ${path}`);
203
253
  if (raw.kind === 'carry' && (raw.priorFailures.length || raw.priorErrors.length)) throw new Error(`invalid gate partial plan: ${path}`);
204
254
  // Every prior failure's file is re-run (planPartialRegate guarantees it) — a plan that would carry a failure it did
205
255
  // not re-run is malformed, not «partial».
@@ -208,10 +258,14 @@ export function readPartialPlan(roots: readonly string[], version: string, commi
208
258
  try { failureFiles = [...raw.priorFailures, ...raw.priorErrors].map((id) => testFileOfId(String(id))); }
209
259
  catch { throw new Error(`invalid gate partial plan: ${path}`); }
210
260
  if (failureFiles.some((file) => !rerun.has(file))) throw new Error(`invalid gate partial plan (prior failure not re-run): ${path}`);
211
- if (raw.forCommit !== commit) continue;
212
- return raw as PartialPlan;
261
+ if (raw.forCommit !== commit) { fallbackReason = 'plan-commit-mismatch'; continue; }
262
+ return { plan: raw as PartialPlan, fallbackReason: null };
213
263
  }
214
- return null;
264
+ return { plan: null, fallbackReason };
265
+ }
266
+
267
+ export function readPartialPlan(roots: readonly string[], version: string, commit: string): PartialPlan | null {
268
+ return readPartialPlanResult(roots, version, commit).plan;
215
269
  }
216
270
 
217
271
  /** Cut failures after a partial re-run: prior results for files not re-run ⊕ this run's results for the re-run files. */