elanous 0.2.36 → 0.2.38

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 (741) 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/{uC-N0emedeNOFuaBQFv-I → RrjXTwz-urRAbChP1bX02}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{9250-072df22eaadaa6b5.js → 1026-44010f405704050c.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +27 -0
  6. package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{4304.e9b2512834a9e23e.js → 1632.7d87f998e714bede.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1938.0e6c60ee91c4d7f5.js +148 -0
  14. package/apps/pwa/out/_next/static/chunks/{7784.1f0ac4a16d190cf4.js → 2104.70e086d5174a4736.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{6566.926a1d1b7c911442.js → 214.186a430da28338f1.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +93 -0
  18. package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +104 -0
  19. package/apps/pwa/out/_next/static/chunks/{5711.957b095705c12560.js → 2415.738b777642a02233.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/{4286.b70c4520306817e8.js → 3086.fb14b60ce98b53d3.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/{3148-98efd4869d660a87.js → 3124-561f7f037943cde2.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +24 -0
  31. package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{3727.7949ccaacaa71242.js → 3291.f6c1005387d514bd.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +36 -0
  34. package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +287 -0
  38. package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/{8904.7d51af2dc033965c.js → 3528.e4b8ab70d339f965.js} +2 -2
  40. package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +94 -0
  45. package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3f0de3de-2340c532c00395db.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/{3031-85328a92fcce4da6.js → 4199-f7c6eb40cd0322f8.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +32 -0
  57. package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +90 -0
  58. package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +79 -0
  60. package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +74 -0
  63. package/apps/pwa/out/_next/static/chunks/5041-5aada92ca215ffdd.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{528.38ce20ef8aa251ff.js → 5203.51e5d8b5f1dcfe53.js} +16 -16
  65. package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +286 -0
  68. package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{2683.c9773a0c589b031b.js → 5307.d7328020227880c2.js} +4 -4
  70. package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +8 -0
  73. package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/{552.b7d061ad91eeac51.js → 5638.107314dc479e2f37.js} +2 -2
  75. package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6142.913b44e260a3f925.js +64 -0
  80. package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/{6925.562d532110879886.js → 6493.27ad77de7aac7966.js} +1 -1
  84. package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +62 -0
  88. package/apps/pwa/out/_next/static/chunks/{275-02ea4c2a33980422.js → 7161-8f22db3ec5ed005e.js} +3 -3
  89. package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{3136.30aaaa5fa03662a3.js → 7488.966b116789f3d41a.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/{4116.a84a92a2492c080e.js → 7524.ce973525d30b3d52.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +77 -0
  95. package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{3324.a09703033abcbd2f.js → 7628.6b16863ac3972333.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{3410.7f9af5ab77cbe65f.js → 7954.4f7a8832663ee979.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/{771.c3cdb6c1f7f47c02.js → 8019.21ca554a821dad01.js} +16 -16
  102. package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/{4615.8525eb0add35eba6.js → 8487.291666583bebe640.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/8509.3a54d4e61893d7cb.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{6943.c6b24124853a47b2.js → 8879.ac06755bcf3e44a1.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +149 -0
  111. package/apps/pwa/out/_next/static/chunks/{575.d929793a53f27c4b.js → 8911.bf5e712acb25fb6c.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/{9f31e478.fefcbcd3c388ebc5.js → 8994d93e.33ba491f95345fc2.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/{da5ecc5c-b005ad8cac737d57.js → 89d6c04f-6b8ab341748e468a.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/{599.c39c571b6733f2a2.js → 9223.cbcc88e0e9950426.js} +2 -2
  115. package/apps/pwa/out/_next/static/chunks/9299.24e2a7d9b6d1f91b.js +226 -0
  116. package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +24 -0
  117. package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{8037.e254fd797aa224d1.js → 9581.da63ddf41acfad46.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +2 -0
  121. package/apps/pwa/out/_next/static/chunks/{ceba0382.650712b56b85b582.js → 9fe1b809.738da85c8b17e3fb.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-866aac5ff226a7f3.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/{page-e7abc34a48a6f71e.js → page-291ab19fe2acb173.js} +1 -1
  153. package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/{page-c15958835534404b.js → page-6b140f77593576eb.js} +1 -1
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{3a3d9966.cc4d4585a2708e7c.js → b7459770.6539b11860eb8a9c.js} +7 -7
  174. package/apps/pwa/out/_next/static/chunks/{053a429e.9a63436527cc751c.js → b7478fef.5917716286213fcc.js} +3 -3
  175. package/apps/pwa/out/_next/static/chunks/bb6987f9.3647e1a23b0e3217.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/{2812ca6a.3b9f4a7a08885744.js → de8b930d.d94c0f42acf807fc.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{873d6c12.09bd499f57171543.js → eaad0cba.771200940c529df7.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-4b12a946f352cee2.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +1 -0
  184. package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
  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 +23 -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/graphs/drafts/recipes.yaml +27 -7
  279. package/graphs/release/recipes.yaml +9 -0
  280. package/graphs/release/release-loop.yaml +26 -18
  281. package/graphs/work/draft-close.yaml +54 -0
  282. package/graphs/work/green-close.yaml +37 -0
  283. package/graphs/work/recipes.yaml +46 -1
  284. package/graphs/work/run-research.yaml +35 -0
  285. package/package.json +1 -1
  286. package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
  287. package/scripts/ask-op-inbox-once.ts +17 -0
  288. package/scripts/boundary-proof-mapping-audit.ts +88 -0
  289. package/scripts/brand/check.ts +13 -4
  290. package/scripts/codex-fallback-live-probe.ts +17 -15
  291. package/scripts/fleet/node-setup.sh +32 -2
  292. package/scripts/fleet/run-light-worker.sh +9 -0
  293. package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
  294. package/scripts/gate-0226-failure-census.ts +546 -0
  295. package/scripts/goals/authoring-metrics.ts +258 -0
  296. package/scripts/graph-units/draft-close-node.ts +222 -0
  297. package/scripts/hook-order-sweep.ts +7 -4
  298. package/scripts/intake-collect-telegram-saved-stage.ts +48 -0
  299. package/scripts/land-global-checks.ts +69 -1
  300. package/scripts/measure-nl-routing-corpus.ts +207 -2
  301. package/scripts/provision-export-redactions.ts +15 -0
  302. package/scripts/public-copy-lint.ts +122 -0
  303. package/scripts/public-export.ts +69 -2
  304. package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
  305. package/scripts/ratchets/train-side-invariants.sh +7 -1
  306. package/scripts/release-loop/cut-branch.ts +61 -12
  307. package/scripts/release-loop/docs-node.ts +140 -0
  308. package/scripts/release-loop/gate-closure.ts +48 -0
  309. package/scripts/release-loop/gate-diff.ts +2 -1
  310. package/scripts/release-loop/gate-node.ts +161 -25
  311. package/scripts/release-loop/gate-partial.ts +82 -3
  312. package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
  313. package/scripts/release-loop/gate-radius-live.ts +4 -2
  314. package/scripts/release-loop/known-issues-node.ts +6 -4
  315. package/scripts/release-loop/notes-repair.ts +216 -0
  316. package/scripts/release-loop/prepare-node.ts +61 -5
  317. package/scripts/release-loop/resume-cap.ts +2 -1
  318. package/scripts/release-loop/resume-release.ts +406 -7
  319. package/scripts/release-loop/resume-test-traffic.ts +10 -0
  320. package/scripts/release-loop/resume.ts +13 -5
  321. package/scripts/release-loop/traffic-node.ts +12 -4
  322. package/scripts/release-loop/traffic-transition.ts +53 -13
  323. package/scripts/release-loop/version-node.ts +109 -15
  324. package/scripts/train/green-leg.ts +176 -0
  325. package/scripts/tui-continue-real-evidence.ts +47 -0
  326. package/scripts/ux-sim.ts +1 -1
  327. package/scripts/video-pipeline.ts +2 -2
  328. package/src/acp/client.ts +31 -5
  329. package/src/acp/core-turn-bridge.ts +12 -1
  330. package/src/acp/stderr-summary.ts +49 -0
  331. package/src/agent/monad-agent-turn.ts +1 -0
  332. package/src/agent/run-context.ts +1 -1
  333. package/src/agent/task-notification.ts +3 -1
  334. package/src/agent/terminal-surface.ts +217 -0
  335. package/src/agent-substrate/pr-reviewer.ts +11 -3
  336. package/src/agent-substrate/review-observation.ts +10 -0
  337. package/src/agent-substrate/self-review-cli.ts +537 -57
  338. package/src/auto-research/question-ladder-contract.ts +137 -0
  339. package/src/auto-research/research-turn.ts +134 -0
  340. package/src/autopilot/discovery/doc-lint.ts +1 -1
  341. package/src/autopilot/lineage/sources.ts +1 -1
  342. package/src/autopilot/pr-manager.ts +64 -13
  343. package/src/boot/daemon-runtime.ts +35 -3
  344. package/src/boot/daemon-tools/pty-shell.ts +2 -1
  345. package/src/bots/screen-probe.ts +1 -1
  346. package/src/budget/run-usage-rollup.ts +12 -7
  347. package/src/budget/unified-usage.ts +20 -0
  348. package/src/capture/tui-self-report.ts +42 -5
  349. package/src/chat/index.ts +1 -0
  350. package/src/chat/tool-render/dispatch.ts +8 -1
  351. package/src/cli/autopilot-cli.ts +24 -9
  352. package/src/cli/decisions-cli.ts +7 -4
  353. package/src/cli/doctor-cli.ts +116 -7
  354. package/src/cli/guardian-cli.ts +3 -1
  355. package/src/cli/intake-cli.ts +48 -12
  356. package/src/cli/lesson-cli.ts +69 -9
  357. package/src/cli/logs-cli.ts +357 -2
  358. package/src/cli/memory-cli.ts +30 -1
  359. package/src/cli/msg-cli.ts +15 -11
  360. package/src/cli/pr-granularity.ts +5 -3
  361. package/src/cli/pr-land-overlap-evidence.ts +38 -5
  362. package/src/cli/pr-land-refusal.ts +1 -1
  363. package/src/cli/pty-takeover-cli.ts +58 -5
  364. package/src/cli/release-checklist-read-cli.ts +112 -4
  365. package/src/cli/release-cli.ts +89 -18
  366. package/src/cli/review-carry.ts +77 -0
  367. package/src/cli/self-update.ts +24 -6
  368. package/src/cli/self-utterances-cli.ts +13 -16
  369. package/src/cli/tasks-card-show.ts +31 -1
  370. package/src/cli/tasks-cli.ts +370 -33
  371. package/src/cli/tasks-read-cli.ts +13 -5
  372. package/src/cli/usage-cli.ts +12 -10
  373. package/src/context-bus/claude-memory-import.ts +99 -0
  374. package/src/context-bus/context-now.ts +86 -2
  375. package/src/context-bus/long-term-memory.ts +125 -0
  376. package/src/core-turn/run-core-turn.ts +9 -2
  377. package/src/core-turn/run-goal-loop.ts +5 -2
  378. package/src/core-turn/types.ts +5 -0
  379. package/src/dashboard/chat/acp-chat.ts +9 -0
  380. package/src/dashboard/index.ts +115 -30
  381. package/src/dashboard/input/agent-wake.ts +43 -0
  382. package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
  383. package/src/dashboard/input/terminal-modal-router.ts +8 -159
  384. package/src/dashboard/replay-preview.ts +25 -0
  385. package/src/dashboard/side-basic-runtime.ts +61 -0
  386. package/src/dashboard/slash-runtime/dashboard-handlers.ts +19 -8
  387. package/src/dashboard/synchronized-frame-output.ts +74 -0
  388. package/src/dashboard/term-slash-runtime.ts +2 -0
  389. package/src/dashboard/turn-preamble.ts +28 -4
  390. package/src/display/coordinator.ts +45 -12
  391. package/src/display/resize-listener.ts +41 -20
  392. package/src/display/synchronized-output-region.ts +60 -0
  393. package/src/domains/guardian-tick.ts +9 -0
  394. package/src/domains/surface-events.ts +80 -1
  395. package/src/exec-requests/planner.ts +37 -2
  396. package/src/execution-loop/launch-gate.ts +4 -3
  397. package/src/git-fs/cli-stderr.ts +45 -0
  398. package/src/git-fs/gh-cli.ts +6 -3
  399. package/src/git-fs/git-cli.ts +11 -5
  400. package/src/git-fs/watcher.ts +27 -22
  401. package/src/git-fs/worktree.ts +19 -3
  402. package/src/graph-runner/graph-cli.ts +26 -2
  403. package/src/graph-runner/graph-grow.ts +37 -9
  404. package/src/graph-runner/graph-run-api.ts +3 -2
  405. package/src/graph-runner/runner.ts +34 -7
  406. package/src/graph-wizard/generate.ts +29 -6
  407. package/src/grok/credential.ts +107 -36
  408. package/src/harness/harness-cli-command.ts +179 -33
  409. package/src/harness/review-adapter.ts +26 -6
  410. package/src/hq/fence-wrapper.ts +1 -1
  411. package/src/hq/transfer.ts +1 -1
  412. package/src/index.ts +151 -18
  413. package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
  414. package/src/intake-plane/collect-telegram-saved.ts +54 -5
  415. package/src/interactive-terminal-modal.ts +3 -0
  416. package/src/keybindings.ts +17 -22
  417. package/src/llm/provider-credentials.ts +1 -1
  418. package/src/llm/route-decision.ts +13 -0
  419. package/src/llm-tool-name.ts +37 -0
  420. package/src/llm-tool-schema.ts +55 -0
  421. package/src/llm.ts +203 -21
  422. package/src/loops/checker.ts +100 -0
  423. package/src/loops/consensus.ts +26 -2
  424. package/src/loops/loop-cli.ts +9 -4
  425. package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
  426. package/src/loops/orchestrator/inbox-once.ts +28 -0
  427. package/src/loops/orchestrator/inbox.ts +130 -1
  428. package/src/loops/orchestrator/tick.ts +55 -7
  429. package/src/maturity/feature-maturity.ts +1 -0
  430. package/src/model-tier/llm-tier-map.ts +12 -17
  431. package/src/msg/msg-store.ts +17 -0
  432. package/src/native-tool-catalog.ts +1 -1
  433. package/src/nexus/api/channel-ask-op.ts +96 -0
  434. package/src/nexus/api/discord-trigger-bot.ts +28 -1
  435. package/src/nexus/api/graph-wizard-api.ts +27 -2
  436. package/src/nexus/api/grid.ts +24 -4
  437. package/src/nexus/api/http-server.ts +1 -1
  438. package/src/nexus/api/ops-api.ts +14 -6
  439. package/src/nexus/api/telegram-trigger-bot.ts +24 -0
  440. package/src/nexus/api/terminals.ts +28 -6
  441. package/src/nexus/state/state.ts +7 -1
  442. package/src/oauth/codex-account-store.ts +34 -1
  443. package/src/ops/loops-map.ts +46 -0
  444. package/src/ops/overview-cache.ts +22 -4
  445. package/src/ops/overview.ts +41 -5
  446. package/src/patents/ledger.ts +18 -1
  447. package/src/policy/llm-policy.ts +3 -1
  448. package/src/preview/terminal.ts +4 -2
  449. package/src/prompt-cache/anthropic.ts +2 -0
  450. package/src/prompt-enhance/enhance.ts +9 -4
  451. package/src/pty-shell/availability.ts +7 -0
  452. package/src/pty-shell/herdr-agent-report.ts +40 -31
  453. package/src/pty-shell/herdr-prune-stale.ts +17 -0
  454. package/src/pty-shell/herdr-sequence-lease.ts +60 -0
  455. package/src/pty-shell/pty-control-ipc.ts +187 -18
  456. package/src/pty-shell/pty-manifest.ts +16 -2
  457. package/src/pty-shell/registry.ts +25 -15
  458. package/src/pty-shell/tui-run-state.ts +235 -1
  459. package/src/release-loop/checklist.ts +50 -5
  460. package/src/release-loop/feature-store.ts +9 -9
  461. package/src/release-loop/gate-shards.ts +61 -0
  462. package/src/release-loop/landed-but-yellow.ts +93 -12
  463. package/src/release-loop/light-rc.ts +7 -4
  464. package/src/release-loop/rehearsal.ts +1 -1
  465. package/src/repl/index.ts +18 -0
  466. package/src/research/axis-fanout.ts +133 -0
  467. package/src/research/edge-decision.ts +88 -0
  468. package/src/research/output-router.ts +127 -0
  469. package/src/research-bridge/format.ts +16 -1
  470. package/src/research-bridge/index.ts +1 -0
  471. package/src/research-bridge/invoke.ts +41 -5
  472. package/src/seat-loop/seat-report.ts +1 -0
  473. package/src/self-dev/ask-launch-flow.ts +86 -10
  474. package/src/self-dev/decompose-proposal.ts +29 -18
  475. package/src/self-dev/decompose.ts +45 -9
  476. package/src/self-dev/dev-pipeline.ts +29 -7
  477. package/src/self-dev/draft-residue.ts +221 -2
  478. package/src/self-dev/draft-sweep.ts +254 -16
  479. package/src/self-dev/draft-triage-rules.ts +19 -5
  480. package/src/self-dev/orchestrate.ts +1 -0
  481. package/src/self-dev/review-provider-fallback.ts +45 -7
  482. package/src/self-dev/run-supervisor.ts +22 -7
  483. package/src/self-dev/shard-plan.ts +48 -0
  484. package/src/self-dev/shard-run.ts +310 -6
  485. package/src/self-implement/comment-only-source.ts +54 -0
  486. package/src/self-implement/doctor-visit.ts +108 -0
  487. package/src/self-implement/gate-artifacts.ts +6 -2
  488. package/src/self-implement/gate-baseline.ts +99 -1
  489. package/src/self-implement/gate-cli.ts +231 -82
  490. package/src/self-implement/gate-failure-signature.ts +44 -0
  491. package/src/self-implement/gate-remote.ts +30 -4
  492. package/src/self-implement/gate-scope.ts +13 -1
  493. package/src/self-implement/goal-author.ts +407 -21
  494. package/src/self-implement/goal-doc/section.ts +22 -0
  495. package/src/self-implement/goal-supervisor-fill.ts +110 -27
  496. package/src/self-implement/importer-test-index.ts +215 -2
  497. package/src/self-implement/knowhow-pack.ts +125 -12
  498. package/src/self-implement/l8-merge-queue.ts +198 -32
  499. package/src/self-implement/off-diff-evidence.ts +23 -0
  500. package/src/self-implement/orchestrator.ts +369 -33
  501. package/src/self-implement/pod-inplace-worktree.ts +82 -0
  502. package/src/self-implement/pod-warm-pool-profile.ts +2 -2
  503. package/src/self-implement/premise-review.ts +7 -5
  504. package/src/self-implement/review-round-brief.ts +300 -0
  505. package/src/self-implement/rework-policy.ts +14 -0
  506. package/src/self-implement/run-ledger.ts +428 -6
  507. package/src/self-implement/run-stop.ts +1 -1
  508. package/src/self-implement/running-runs.ts +17 -3
  509. package/src/self-implement/seams.ts +45 -16
  510. package/src/self-implement/self-implement-cli.ts +26 -2
  511. package/src/self-implement/stop-autoheal.ts +1 -0
  512. package/src/self-implement/test-seams.ts +13 -1
  513. package/src/self-implement/train-reach-grouping.ts +8 -2
  514. package/src/session/channel-ask-op-envelope.ts +36 -0
  515. package/src/session/channel-op-reply-route.ts +200 -0
  516. package/src/session/chat.ts +10 -1
  517. package/src/session/id-prefix.ts +60 -0
  518. package/src/session/index.ts +6 -0
  519. package/src/session-runtime/index.ts +18 -23
  520. package/src/skills/runner.ts +7 -3
  521. package/src/skills/tools/dev-harness.ts +2 -2
  522. package/src/skills/tools/pty.ts +5 -0
  523. package/src/skills/tools/schedule-wakeup.ts +1 -6
  524. package/src/status/bar.ts +3 -3
  525. package/src/status/metrics.ts +12 -1
  526. package/src/steward/rejudge-tick.ts +12 -5
  527. package/src/steward/resync-tick.ts +31 -4
  528. package/src/storage/file-lock.ts +17 -4
  529. package/src/task-agent/actions.ts +199 -4
  530. package/src/task-agent/adopt-pr.ts +63 -2
  531. package/src/task-agent/boundary-proof-mapping.ts +12 -0
  532. package/src/task-agent/boundary-proof-producer.ts +147 -0
  533. package/src/task-agent/completion-evidence.ts +2 -1
  534. package/src/task-agent/evidence-command-normalize.ts +42 -0
  535. package/src/task-agent/export-redactions-provision.ts +43 -0
  536. package/src/task-agent/green-close-recipe.ts +239 -0
  537. package/src/task-agent/green-sweep.ts +64 -10
  538. package/src/task-agent/live-moves.ts +48 -3
  539. package/src/task-agent/map-host-adapter.ts +134 -0
  540. package/src/task-agent/map-reduce.ts +158 -0
  541. package/src/task-agent/map-run-ledger.ts +226 -0
  542. package/src/task-agent/parent-host.ts +74 -17
  543. package/src/task-agent/rejudge-on-head.ts +72 -5
  544. package/src/task-agent/repair-cycle.ts +108 -8
  545. package/src/task-agent/repair-next-move.ts +12 -2
  546. package/src/task-agent/repair-worker.ts +37 -1
  547. package/src/task-agent/review-prior-fix.ts +12 -2
  548. package/src/task-agent/shadow.ts +188 -5
  549. package/src/task-agent/task-hand.ts +253 -20
  550. package/src/task-agent/task-parent-role-llm.ts +9 -0
  551. package/src/task-agent/tier-split.ts +40 -5
  552. package/src/task-agent/work-order.ts +53 -2
  553. package/src/task-orchestrator/dispatcher.ts +46 -1
  554. package/src/task-orchestrator/generator-prompt.ts +6 -0
  555. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
  556. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +31 -4
  557. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
  558. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
  559. package/src/task-orchestrator/surfaces/pod-pool.ts +77 -8
  560. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +15 -9
  561. package/src/task-orchestrator/surfaces/self-implement-pod.ts +338 -79
  562. package/src/task-orchestrator/surfaces/self-implement.ts +37 -2
  563. package/src/terminal/session-registry.ts +1 -0
  564. package/src/terminal/terminal-modal-router.ts +156 -0
  565. package/src/testing/linux-env.ts +177 -0
  566. package/src/tool-hints/gate.ts +6 -4
  567. package/src/tool-hints/signals.ts +33 -1
  568. package/src/tui/chat/background-job-status.ts +8 -2
  569. package/src/tui/chat/goal-interim.ts +5 -1
  570. package/src/tui/entry.ts +722 -30
  571. package/src/tui/input/at-picker.ts +55 -0
  572. package/src/tui/sidetab/attach.ts +304 -0
  573. package/src/tui/sidetab/list.ts +176 -0
  574. package/src/tui/sidetab/nl-tool.ts +136 -0
  575. package/src/tui/slash/resume-command.ts +23 -0
  576. package/src/tui/slash/resume.ts +38 -35
  577. package/src/tui/slash/signals.ts +114 -0
  578. package/src/tui/slash/term-next.ts +72 -0
  579. package/src/tui-client/local-chat-turn.ts +31 -9
  580. package/src/user-config.ts +30 -3
  581. package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
  582. package/src/ux-sim/classic-tui-seat-scenarios.ts +158 -4
  583. package/src/ux-sim/fake-gh.ts +174 -0
  584. package/src/ux-sim/fake-kubectl.ts +142 -0
  585. package/src/ux-sim/fake-llm.ts +17 -6
  586. package/src/ux-sim/next-tui-seat-scenarios.ts +176 -6
  587. package/src/ux-sim/resume-picker-device.ts +173 -0
  588. package/src/ux-sim/session-id-seed.ts +60 -0
  589. package/src/ux-sim/skills-tools-shell-device.ts +156 -0
  590. package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
  591. package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
  592. package/src/version/packed-revision.json +1 -1
  593. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +0 -287
  594. package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +0 -64
  600. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +0 -36
  601. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +0 -149
  604. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +0 -24
  609. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +0 -24
  612. package/apps/pwa/out/_next/static/chunks/2986.45d7652e4f13557e.js +0 -2
  613. package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +0 -226
  614. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +0 -8
  618. package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +0 -32
  619. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +0 -286
  621. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/3757-180308bc61021b05.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +0 -74
  625. package/apps/pwa/out/_next/static/chunks/3840-5825d56d46976a92.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +0 -104
  629. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +0 -148
  632. package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +0 -93
  634. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +0 -122
  636. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +0 -79
  641. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +0 -27
  653. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/7481.39f7a4654907bf6e.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/7891.03f910124a737985.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +0 -62
  664. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +0 -90
  666. package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +0 -94
  667. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +0 -77
  672. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/9514.131c52cc75fe6439.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/ccae1c4b-0cf414f5eff1b10d.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +0 -1
  739. package/scripts/migrate-monad-to-elanous.ts +0 -195
  740. package/scripts/rebrand-elanous.ts +0 -242
  741. /package/apps/pwa/out/_next/static/{uC-N0emedeNOFuaBQFv-I → RrjXTwz-urRAbChP1bX02}/_ssgManifest.js +0 -0
@@ -3,21 +3,32 @@
3
3
  // every later node reads the repaired commit without anyone hand-editing the run state.
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import { createHash } from 'node:crypto';
6
- import { constants, copyFileSync, existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
7
- import { join } from 'node:path';
6
+ import { accessSync, closeSync, constants, copyFileSync, existsSync, fstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, realpathSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
7
+ import { tmpdir } from 'node:os';
8
+ import { dirname, join, resolve } from 'node:path';
8
9
  import { debug } from '../../src/debug/log.js';
9
10
  import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/resolve.js';
10
11
  import { lastJsonObject, runGraph, verifyReleaseCommandRoot, verifyReleaseRecipeSnapshot, type GraphRunState } from '../../src/graph-runner/runner.js';
11
12
  import { withOpSeatFlock } from '../../src/steward/resync-tick.js';
12
13
  import { releaseRunUniverse } from './release-universe.js';
13
14
  import { isReleaseVersion } from './release-version.js';
14
- import { changedFilesBetween, clearPartialPlan, planPartialRegate, planStalledShardRecheck, writePartialPlan, writeRecheckPlan } from './gate-partial.js';
15
+ import { changedFilesBetween, clearPartialPlan, collectExecutedPodShardImages, planPartialRegate, planStalledShardRecheck, writePartialPlan, writeRecheckPlan } from './gate-partial.js';
15
16
  import { gitClosureTree, testsReachingChanged, TRACEABLE_RELEASE_JSON, type ClosureTree } from './gate-closure.js';
16
17
  import { releaseResumeAcceptedRegressions, releaseResumeGateExecutor, releaseResumeGatePodPool, releaseResumeWaiver, type AcceptedRegression } from './resume.js';
17
18
  import { reserveReleaseResumeAttempt } from './resume-cap.js';
19
+ import { cutReleaseBranch } from './cut-branch.js';
20
+ import { releaseLoopConfig } from './unattended-release.js';
21
+ import { trafficOptionsFromConfig } from './traffic-transition.js';
18
22
 
19
23
  const GRAPH = join(import.meta.dir, '../../graphs/release/release-loop.yaml');
20
24
 
25
+ /** Compare existing artifact paths by filesystem identity so macOS /var and /private/var aliases agree. */
26
+ function sameRealPath(left: unknown, right: unknown): boolean {
27
+ if (typeof left !== 'string' || typeof right !== 'string') return false;
28
+ try { return realpathSync(left) === realpathSync(right); }
29
+ catch { return false; }
30
+ }
31
+
21
32
  export interface ResumeReleaseDeps {
22
33
  root?: string;
23
34
  repo?: string;
@@ -37,6 +48,8 @@ export interface ResumeReleaseDeps {
37
48
  closureTree?: (commit: string) => ClosureTree;
38
49
  /** Source observation before the first resumed node. */
39
50
  onSource?: (line: string) => void;
51
+ /** Test seam; production resolves this from ELANOUS_RELEASE_TRAFFIC_FILE / release.loop.trafficFile. */
52
+ trafficFile?: string;
40
53
  }
41
54
 
42
55
  export interface ResumeReleaseOptions {
@@ -80,7 +93,7 @@ function safeRunId(runId: string): string {
80
93
  return runId;
81
94
  }
82
95
 
83
- /** Point the saved version-release output at the current release/<v> tip (fast-forward of the recorded commit only). */
96
+ /** Lower-level maintenance primitive; the resume entrypoints run verifyResumePreflight before calling it. */
84
97
  export function refreshReleaseBranchTip(runId: string, deps: ResumeReleaseDeps = {}, from?: string, waiverCommit?: string): TipRefresh {
85
98
  return refreshReleaseBranchTipInternal(runId, deps, from, waiverCommit, false);
86
99
  }
@@ -128,7 +141,7 @@ function refreshReleaseBranchTipInternal(runId: string, deps: ResumeReleaseDeps,
128
141
  }
129
142
  // A repair only appends (`cut-branch --append`): anything but a fast-forward is a different release.
130
143
  if (!(deps.isAncestor ?? ancestorRunner(deps.repo ?? process.cwd()))(recorded, to)) {
131
- throw new Error(`${branch} tip ${to} does not descend from the recorded release commit ${recorded} — refusing to resume`);
144
+ throw new Error(`${branch} tip ${to} does not descend from the recorded release commit ${recorded} — refusing to resume; remedy: inspect both commits and create a new release run from the intended pinned tip`);
132
145
  }
133
146
  // A new tip invalidates everything built from the old one (gate verdict, prepared archive, …): restart no later
134
147
  // than the first node that consumed the commit, so each of them runs again on the new tip.
@@ -174,6 +187,111 @@ function verifyResumeRecipePin(commandRoot: string, snapshot: GraphRunState['gra
174
187
  }
175
188
  }
176
189
 
190
+ /** Common read-only gate for dry-run and actual resume. Every rejection includes an operator action. */
191
+ function verifyResumePreflight(run: GraphRunState, opts: ResumeReleaseOptions, deps: ResumeReleaseDeps,
192
+ version: string, recordedCommit: string, currentTip: string, commandRoot: string): void {
193
+ let trafficFile = deps.trafficFile;
194
+ if (trafficFile === undefined) {
195
+ try { trafficFile = trafficOptionsFromConfig(process.env, releaseLoopConfig()).trafficFile; }
196
+ catch (error) { throw new Error(`cannot read release traffic configuration — remedy: repair release.loop.trafficFile in the active config before resuming`, { cause: error }); }
197
+ }
198
+ if (!trafficFile) throw new Error('release.loop.trafficFile is not configured — remedy: set release.loop.trafficFile or ELANOUS_RELEASE_TRAFFIC_FILE before resuming');
199
+ let fd: number | undefined;
200
+ try {
201
+ const path = resolve(trafficFile);
202
+ const info = statSync(path);
203
+ if (!info.isFile() || (info.mode & 0o222) === 0) throw new Error('not a writable regular file');
204
+ fd = openSync(path, constants.O_WRONLY);
205
+ if (!fstatSync(fd).isFile()) throw new Error('not a regular file');
206
+ accessSync(path, constants.R_OK | constants.W_OK);
207
+ } catch (error) {
208
+ throw new Error(`release traffic file is missing or not writable: ${trafficFile} (${error instanceof Error ? error.message : String(error)}) — remedy: create a regular writable traffic file and set release.loop.trafficFile`, { cause: error });
209
+ } finally { if (fd !== undefined) closeSync(fd); }
210
+
211
+ for (const path of [join(commandRoot, 'node_modules'), join(commandRoot, 'apps', 'pwa', 'node_modules')]) {
212
+ try { if (!statSync(path).isDirectory()) throw new Error('not a directory'); }
213
+ catch (error) { throw new Error(`release resume dependencies missing: ${path} — remedy: run bun install --frozen-lockfile at repository root and apps/pwa`, { cause: error }); }
214
+ }
215
+
216
+ const nodeOutput = (nodeId: string): Record<string, unknown> | undefined => {
217
+ const node = run.nodes.find((entry) => entry.nodeId === nodeId);
218
+ if (!node?.ok || typeof node.output !== 'string') return undefined;
219
+ try { return lastJsonObject(node.output) as Record<string, unknown> | undefined; } catch { return undefined; }
220
+ };
221
+ const recordedNodeOutput = (nodeId: string): Record<string, unknown> | undefined => {
222
+ const node = run.nodes.find((entry) => entry.nodeId === nodeId);
223
+ if (typeof node?.output !== 'string') return undefined;
224
+ try { return lastJsonObject(node.output) as Record<string, unknown> | undefined; } catch { return undefined; }
225
+ };
226
+ const roots = [...new Set([deps.root ?? effectiveInstanceRoot(), deps.ledgerRoot ?? releaseLedgerRoot()])];
227
+ for (const root of roots) {
228
+ const prepared = join(root, 'release', version, 'prepared');
229
+ if (existsSync(prepared)) {
230
+ const record = nodeOutput('prepare');
231
+ const output = record && typeof record.out === 'string' ? record : undefined;
232
+ const manifestPath = join(prepared, 'release.json');
233
+ let manifest: { version?: unknown; sourceCommit?: unknown } | undefined;
234
+ try { manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as typeof manifest; } catch { /* fail closed below */ }
235
+ const ownerPath = join(prepared, '.release-node-owner.json');
236
+ let owner: { runId?: unknown; commit?: unknown } | undefined;
237
+ let ownerReadable = !existsSync(ownerPath);
238
+ try { owner = JSON.parse(readFileSync(ownerPath, 'utf8')) as typeof owner; ownerReadable = true; } catch { /* old artifacts can be owned by the run ledger */ }
239
+ const ledgerOwns = output !== undefined && sameRealPath(output.out, prepared)
240
+ && output.commit === currentTip && output.outcome === 'ok';
241
+ const receiptOwns = owner ? owner.runId === opts.runId && owner.commit === currentTip : ownerReadable && ledgerOwns;
242
+ if (!ledgerOwns || manifest?.version !== version || manifest.sourceCommit !== currentTip || !receiptOwns) {
243
+ throw new Error(`prepared artifact is outside the current release run ledger: ${prepared} — remedy: preserve it, compare release.json and .release-node-owner.json with run ${opts.runId}, then resolve ownership before resume`);
244
+ }
245
+ }
246
+
247
+ const receiptPath = join(root, 'release', version, 'docs-branch-owner.json');
248
+ const docsBranch = `release-docs/${version}`;
249
+ let receipt: { owner?: { runId?: unknown; attempt?: unknown }; branch?: unknown; worktree?: unknown; outcome?: unknown; head?: unknown } | undefined;
250
+ try { receipt = JSON.parse(readFileSync(receiptPath, 'utf8')) as typeof receipt; } catch { /* no/invalid receipt is rejected if an artifact exists */ }
251
+ const docsRecord = recordedNodeOutput('docs');
252
+ const worktree = typeof docsRecord?.worktree === 'string' ? docsRecord.worktree : undefined;
253
+ let localBranch: string | undefined;
254
+ try { localBranch = (deps.git ?? gitRunner(deps.repo ?? process.cwd()))(['show-ref', '--verify', '--hash', `refs/heads/${docsBranch}`]).trim(); } catch { /* absent */ }
255
+ let docsWorktrees: string[] = [];
256
+ try {
257
+ const listing = (deps.git ?? gitRunner(deps.repo ?? process.cwd()))(['worktree', 'list', '--porcelain']);
258
+ docsWorktrees = listing.split(/\n\n+/).filter(Boolean).flatMap((entry) => {
259
+ const branch = /^branch (.+)$/m.exec(entry)?.[1];
260
+ const path = /^worktree (.+)$/m.exec(entry)?.[1];
261
+ return branch === `refs/heads/${docsBranch}` && path ? [path] : [];
262
+ });
263
+ } catch (error) {
264
+ throw new Error(`cannot inspect release worktrees for ${docsBranch} — remedy: restore read-only git access and retry resume`, { cause: error });
265
+ }
266
+ let remoteHead: string | undefined;
267
+ try {
268
+ const response = (deps.git ?? gitRunner(deps.repo ?? process.cwd()))(['ls-remote', '--heads', 'origin', `refs/heads/${docsBranch}`]);
269
+ const line = response.split(/\r?\n/).find((candidate) => candidate.trim().endsWith(`refs/heads/${docsBranch}`));
270
+ remoteHead = line?.trim().split(/\s+/)[0];
271
+ } catch (error) {
272
+ throw new Error(`cannot inspect docs branch ${docsBranch} — remedy: restore read-only git access and retry resume`, { cause: error });
273
+ }
274
+ const hasDocsArtifact = existsSync(receiptPath) || !!localBranch || !!remoteHead || docsWorktrees.length > 0;
275
+ const outputOwner = docsRecord?.artifactOwner as { runId?: unknown; attempt?: unknown } | undefined;
276
+ const receiptMatches = receipt?.branch === docsBranch && receipt.owner?.runId === opts.runId
277
+ && receipt.owner.attempt === outputOwner?.attempt && outputOwner?.runId === opts.runId
278
+ && typeof receipt.worktree === 'string' && sameRealPath(worktree, receipt.worktree)
279
+ && docsWorktrees.some((listedWorktree) => sameRealPath(listedWorktree, receipt.worktree));
280
+ if (hasDocsArtifact && !receiptMatches) {
281
+ throw new Error(`docs branch/worktree is outside the current release run ledger: ${docsBranch} — remedy: compare ${receiptPath} with the saved docs node output and resolve ownership before resume`);
282
+ }
283
+ if (receipt?.outcome === 'pushed' && (!/^[0-9a-f]{40}$/i.test(String(receipt.head ?? ''))
284
+ || remoteHead?.toLowerCase() !== String(receipt.head).toLowerCase())) {
285
+ throw new Error(`docs branch tip differs from the saved ownership receipt: ${docsBranch} — remedy: preserve the branch and worktree, compare the remote tip with ${receiptPath} and the saved docs node output, then resolve ownership before resume`);
286
+ }
287
+ }
288
+
289
+ const recorded = nodeOutput('version-release');
290
+ if (recorded?.branch !== `release/${version}` || recorded.commit !== recordedCommit || !/^[0-9a-f]{40}$/i.test(currentTip)) {
291
+ throw new Error(`release branch tip does not match the saved version-release ledger for ${version} — remedy: inspect the branch and saved run ${opts.runId}, then resume from a node before gate only after resolving the mismatch`);
292
+ }
293
+ }
294
+
177
295
  /** GATE-PARTIAL outcome of a resume — applied (plan written) or the reason it fell back to a full gate. `auto` marks the
178
296
  * default plan of `--from gate` (GATE-REUSE-BY-DIFF); `closure` is set when code changes were followed. */
179
297
  export type PartialOutcome = { requested: false }
@@ -182,7 +300,7 @@ export type PartialOutcome = { requested: false }
182
300
 
183
301
  /** Build (or clear) the partial re-gate plan for the new tip. Fail-closed: any doubt leaves a full gate.
184
302
  * GATE-REUSE-BY-DIFF: `--from gate` on a moved tip plans by default (`partial: undefined`); `partial: false` opts out. */
185
- function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean }, deps: ResumeReleaseDeps, dryRun = false): PartialOutcome {
303
+ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean; gateExecutor?: string }, deps: ResumeReleaseDeps, dryRun = false): PartialOutcome {
186
304
  const root = deps.root ?? effectiveInstanceRoot();
187
305
  // Any resume starts from no plan: one without a partial plan (from whatever node) never inherits an older plan.
188
306
  if (!dryRun) clearPartialPlan(root, tip.version);
@@ -220,7 +338,7 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
220
338
  for (const item of stalled) {
221
339
  if (!item || typeof item !== 'object' || !Array.isArray((item as { files?: unknown }).files)
222
340
  || !(item as { files: unknown[] }).files.every((file) => typeof file === 'string')
223
- || !['incomplete', 'no-output', 'job-failed', 'exit-code', 'unattributed', 'timeout'].includes(String((item as { reason?: unknown }).reason)))
341
+ || !['incomplete', 'no-output', 'job-failed', 'exit-code', 'unattributed', 'timeout', 'admission-timeout', 'admission-error'].includes(String((item as { reason?: unknown }).reason)))
224
342
  return fallback('stalled-shard record is malformed');
225
343
  stalledFiles.push(...(item as { files: string[] }).files);
226
344
  }
@@ -279,9 +397,16 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
279
397
  const jsonClosure = testsReachingChanged(tree, [TRACEABLE_RELEASE_JSON], tests, { cliEntries: CLI_ENTRIES });
280
398
  if (!jsonClosure.ok || jsonClosure.reached === 0) return fallback('known-issues JSON reaches no verified test — full gate');
281
399
  }
400
+ const priorCutLogs = [...new Set([deps.ledgerRoot ?? releaseLedgerRoot(), root])]
401
+ .map((location) => join(location, 'release', tip.version, 'gate-logs', 'cut'))
402
+ .find((dir) => existsSync(dir));
403
+ const savedInput = saved.input as { gateExecutor?: unknown; gatePodPool?: unknown };
404
+ const podGate = (opts.gateExecutor ?? savedInput.gateExecutor ?? (savedInput.gatePodPool ? 'pod' : undefined)) === 'pod';
405
+ const priorShards = priorCutLogs ? collectExecutedPodShardImages(priorCutLogs, tip.from) : undefined;
282
406
  const planned = planPartialRegate({ version: tip.version, priorCommit: tip.from, forCommit: tip.to, changedFiles: changed,
283
407
  priorFailures: prior.failures as string[], priorErrors: (prior.errors ?? []) as string[],
284
408
  existsAtTip: (file) => tracked.has(file),
409
+ ...(podGate ? { priorShards: priorShards ?? [] } : {}),
285
410
  closure: (changedCode) => testsReachingChanged(tree, changedCode, tests, { cliEntries: CLI_ENTRIES }) });
286
411
  if (!planned.ok) return fallback(planned.reason);
287
412
  if (planned.plan.files.length >= tests.length) return fallback(`every test is re-run (${tests.length}) — full gate`);
@@ -355,6 +480,7 @@ async function planResumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: Resu
355
480
  const tip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, true);
356
481
  verifyResumeRecipePin(opts.commandRoot ?? process.cwd(), savedRun.graphSnapshot, tip.version);
357
482
  const commandRoot = verifyReleaseCommandRoot(opts.commandRoot ?? process.cwd(), tip.to, deps.git);
483
+ verifyResumePreflight(savedRun, opts, deps, tip.version, tip.from, tip.to, commandRoot);
358
484
  const partial = preparePartial(tip, opts, deps, true);
359
485
  const fromIndex = savedRun.path.indexOf(opts.from);
360
486
  const gateIndex = savedRun.path.indexOf('gate');
@@ -410,6 +536,7 @@ async function resumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: ResumeRe
410
536
  const previewTip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, true);
411
537
  verifyResumeRecipePin(opts.commandRoot ?? process.cwd(), savedRun.graphSnapshot, previewTip.version);
412
538
  const commandRoot = verifyReleaseCommandRoot(opts.commandRoot ?? process.cwd(), previewTip.to, deps.git);
539
+ verifyResumePreflight(savedRun, opts, deps, previewTip.version, previewTip.from, previewTip.to, commandRoot);
413
540
  const tip = refreshReleaseBranchTipInternal(opts.runId, deps, opts.from, waiverCommit, false, previewTip.to);
414
541
  const partial = preparePartial(tip, opts, deps);
415
542
  // A failed preflight does not consume an observed release resume attempt.
@@ -429,3 +556,275 @@ async function resumeReleaseRunLocked(opts: ResumeReleaseOptions, deps: ResumeRe
429
556
  deps: { root: deps.root, ...(deps.runBash ? { runBash: deps.runBash } : {}) } });
430
557
  return { tip, partial, state };
431
558
  }
559
+
560
+ // RELEASE-RECOVER-ONE-CMD (0.2.36): a failed release run is repaired by three commands that used to be chained by
561
+ // hand (append dry-run → append → resume --from export-check). `release recover` runs them in that order, stops the
562
+ // moment one fails, and leaves every stage's result in the resume-attempts ledger.
563
+ export type RecoverStageName = 'append-dry-run' | 'append' | 'resume';
564
+ const RECOVER_STAGES: readonly RecoverStageName[] = ['append-dry-run', 'append', 'resume'];
565
+ /** The first node that consumes the cut — a moved tip must restart no later than here, so it is the default. */
566
+ const RECOVER_FIRST_NODE = 'export-check';
567
+
568
+ export interface RecoverReleaseOptions {
569
+ runId: string;
570
+ /** main commits that repair the cut — appended to release/<v> as a fast-forward only. */
571
+ pick: string[];
572
+ /** Node the resume restarts at — default `export-check`. */
573
+ from?: string;
574
+ commandRoot?: string;
575
+ partial?: boolean;
576
+ /** The checkout the append runs in (its `origin` remote); default the process cwd. */
577
+ repoRoot?: string;
578
+ }
579
+
580
+ export interface RecoverStageRecord {
581
+ stage: RecoverStageName; outcome: 'ok' | 'failed'; at: string; branch?: string; commit?: string | null;
582
+ from?: string; gatePlan?: 'not-run' | 'partial' | 'full'; status?: string; reason?: string;
583
+ /** The `--pick` list this recovery appended — a re-entry skips the append only for the same list. */
584
+ pick?: string[];
585
+ }
586
+
587
+ export interface RecoverReleaseResult {
588
+ runId: string; version: string; branch: string; fromNode: string; stages: RecoverStageRecord[];
589
+ resume?: { status: string; tip: TipRefresh; partial: PartialOutcome };
590
+ }
591
+
592
+ export interface RecoverReleaseDeps extends ResumeReleaseDeps {
593
+ /** `release cut-branch --append` — tests record the plan instead of pushing the branch. */
594
+ cutBranch?: typeof cutReleaseBranch;
595
+ }
596
+
597
+ /** A recovery that stopped at a stage: the stages after it never ran, and a human decides the next move. */
598
+ export class ReleaseRecoverStopped extends Error {
599
+ constructor(readonly stage: RecoverStageName, readonly stages: readonly RecoverStageRecord[],
600
+ readonly notRun: readonly RecoverStageName[], reason: string) {
601
+ super(`release recover ${stage} 단계에서 멈췄다: ${reason} — ${notRun.length
602
+ ? `${notRun.join(' · ')} 단계는 실행하지 않았다` : '뒤에 실행할 단계가 없다'} · 사람이 판단한다(단계 원장: release/<v>/resume-attempts/<runId>.json)`);
603
+ this.name = 'ReleaseRecoverStopped';
604
+ }
605
+ }
606
+
607
+ /** Append one stage result to the resume-attempts ledger. `attempts[]` keeps its shape — the stage results are added. */
608
+ function recordRecoverStage(entry: { root: string; runId: string; version: string; priorCountKnown: boolean; stage: RecoverStageRecord }): void {
609
+ const path = join(entry.root, 'release', entry.version, 'resume-attempts', `${entry.runId}.json`);
610
+ const saved = existsSync(path)
611
+ ? JSON.parse(readFileSync(path, 'utf8')) as { attempts?: unknown; recoveries?: unknown; priorCountKnown?: unknown }
612
+ : undefined;
613
+ if (saved !== undefined && (!saved || typeof saved !== 'object' || Array.isArray(saved) || !Array.isArray(saved.attempts)
614
+ || (saved.recoveries !== undefined && !Array.isArray(saved.recoveries)))) throw new Error('release resume attempts ledger invalid');
615
+ const next = { ...(saved ?? {}), version: entry.version, runId: entry.runId,
616
+ priorCountKnown: saved?.priorCountKnown ?? entry.priorCountKnown,
617
+ attempts: (saved?.attempts ?? []) as string[],
618
+ recoveries: [...((saved?.recoveries ?? []) as RecoverStageRecord[]), entry.stage] };
619
+ mkdirSync(dirname(path), { recursive: true });
620
+ const temporary = `${path}.${process.pid}.recover.tmp`;
621
+ writeFileSync(temporary, `${JSON.stringify(next)}\n`, { mode: 0o600 });
622
+ renameSync(temporary, path);
623
+ }
624
+
625
+ /**
626
+ * Repair a failed release run in one command: append dry-run (plan only) → append (fast-forward release/<v> onto the
627
+ * picked repairs) → resume --from export-check (preflight plan, then the graph). A failing stage stops the command:
628
+ * the later stages never run, and the stage results are already in the ledger for the human to read.
629
+ */
630
+ export async function recoverReleaseRun(opts: RecoverReleaseOptions, deps: RecoverReleaseDeps = {}): Promise<RecoverReleaseResult> {
631
+ if (!Array.isArray(opts.pick) || !opts.pick.length) throw new Error('release recover requires at least one --pick commit');
632
+ const root = releaseRunUniverse({ root: deps.root });
633
+ const statePath = join(root, 'graph-runs', 'release-loop', `${safeRunId(opts.runId)}.json`);
634
+ const savedRun = JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState;
635
+ if (savedRun.graphId !== 'release-loop' || savedRun.runId !== opts.runId) throw new Error(`run identity mismatch: ${statePath}`);
636
+ // The saved version-release record names what to repair: the release branch and the commit the run cut.
637
+ const versionRecord = savedRun.nodes.find((node) => node.nodeId === 'version-release');
638
+ const recorded = lastJsonObject(versionRecord?.output);
639
+ const version = typeof recorded?.version === 'string' ? recorded.version : '';
640
+ // RELEASE-RECOVER-BASE: a first recover that reached the resume left refreshed-tip lines in the
641
+ // version-release output, and `lastJsonObject` names the CURRENT branch tip. The append builds on the
642
+ // commit the run CUT — an ancestor of the picked repairs on origin/main — so walk to the FIRST JSON
643
+ // object of the output for that original cut. Without this, a second recover with a different --pick
644
+ // fails append-dry-run with «base … is not an ancestor of origin/main» and strands the new repair
645
+ // unpushed while the run looks recovered.
646
+ const firstCutObject = (text: unknown): { version?: unknown; commit?: unknown } | undefined => {
647
+ if (typeof text !== 'string') return undefined;
648
+ for (const line of text.split('\n')) {
649
+ const trimmed = line.trim();
650
+ if (!trimmed.startsWith('{')) continue;
651
+ try {
652
+ const parsed: unknown = JSON.parse(trimmed);
653
+ if (parsed && typeof parsed === 'object' && typeof (parsed as { version?: unknown }).version === 'string') {
654
+ return parsed as { version?: unknown; commit?: unknown };
655
+ }
656
+ } catch { /* not a JSON line — keep walking */ }
657
+ }
658
+ return undefined;
659
+ };
660
+ const originalCut = firstCutObject(versionRecord?.output) ?? recorded;
661
+ const base = typeof originalCut?.commit === 'string' ? originalCut.commit : '';
662
+ if (!versionRecord?.ok || !isReleaseVersion(version) || !/^[0-9a-f]{40}$/i.test(base)) {
663
+ throw new Error(`release run ${opts.runId} has no successful version-release record — nothing to repair`);
664
+ }
665
+ const branch = `release/${version}`;
666
+ const fromNode = opts.from ?? RECOVER_FIRST_NODE;
667
+ // RELEASE-RECOVER-PREFLIGHT (MS-02 review): the append pushes release/<v> on origin, and the resume refuses a
668
+ // bad run only after that push. Every read-only resume rejection is checked here FIRST — a run the resume
669
+ // would refuse never moves the branch. command-root mismatch is gone by construction: recover prepares the
670
+ // tip checkout itself below, and a human-provided --command-root is verified by the plan before the graph.
671
+ if (savedRun.status !== 'failed') {
672
+ throw new Error(`release run ${opts.runId} is ${savedRun.status} — only a failed run is recovered; ${branch} was not moved`);
673
+ }
674
+ if (fromNode === 'version-release') {
675
+ throw new Error(`--from version-release would cut again — recover at a later node; ${branch} was not moved`);
676
+ }
677
+ const restartAt = savedRun.path.indexOf(fromNode);
678
+ if (restartAt < 0 || savedRun.path.lastIndexOf(fromNode) !== restartAt) {
679
+ throw new Error(`--from ${fromNode} is not a node on the saved path of ${opts.runId}; ${branch} was not moved`);
680
+ }
681
+ const consumers = ['export-check', 'gate'].map((node) => savedRun.path.indexOf(node)).filter((index) => index >= 0);
682
+ const firstConsumer = consumers.length ? Math.min(...consumers) : -1;
683
+ if (firstConsumer >= 0 && restartAt > firstConsumer) {
684
+ throw new Error(`--from ${fromNode} is later than ${savedRun.path[firstConsumer]!} — later nodes were built from the old tip; ${branch} was not moved`);
685
+ }
686
+ const savedInput = (savedRun.input ?? {}) as { branchCut?: unknown; version?: unknown };
687
+ if (savedInput.branchCut !== true || savedInput.version !== version || recorded?.branch !== branch) {
688
+ throw new Error(`release run ${opts.runId} was not cut as ${branch} (input.branchCut/version or version-release branch differ); ${branch} was not moved`);
689
+ }
690
+ // The attempt ledger is the resume's own read-only gate — a refused recover consumes no attempt.
691
+ reserveReleaseResumeAttempt(savedRun, root, { now: deps.now, checkOnly: true });
692
+ const now = (): string => (deps.now?.() ?? new Date()).toISOString();
693
+ const stages: RecoverStageRecord[] = [];
694
+ const record = (stage: RecoverStageRecord): void => {
695
+ stages.push(stage);
696
+ recordRecoverStage({ root, runId: opts.runId, version, priorCountKnown: !savedRun.resume, stage });
697
+ };
698
+ const stop = (stage: RecoverStageName, error: unknown): never => {
699
+ throw new ReleaseRecoverStopped(stage, stages, RECOVER_STAGES.slice(RECOVER_STAGES.indexOf(stage) + 1),
700
+ error instanceof Error ? error.message : String(error));
701
+ };
702
+ const reason = (error: unknown): string => error instanceof Error ? error.message : String(error);
703
+ const cutBranch = deps.cutBranch ?? cutReleaseBranch;
704
+ const cut = { version, base, pick: opts.pick, append: true, repoRoot: opts.repoRoot, log: deps.onSource };
705
+ const repoRoot = resolve(opts.repoRoot ?? deps.repo ?? process.cwd());
706
+ // RELEASE-RECOVER-REENTRY (MS-02 review): once the append pushed and the resume did not finish, re-running
707
+ // recover with the same --pick is refused by cut-branch with «pick … is already in release/<v>» and dies at
708
+ // stage 1 with no guidance. The ledger recoveries decide: when their append-ok commit is still inside the
709
+ // advertised branch tip AND its recorded pick list is this --pick (an entry with no pick record is «기록 없음»,
710
+ // not an empty list — it falls back to the safe side and appends again), the repair already landed and this
711
+ // recover continues from the resume — the append stages never re-run.
712
+ /** Same pick list, order-insensitive, full 40-hex object ids only — anything else is «no record». */
713
+ const samePickList = (recorded: unknown): boolean => {
714
+ if (!Array.isArray(recorded) || recorded.length !== opts.pick.length) return false;
715
+ const left = recorded.map((sha) => (typeof sha === 'string' ? sha.toLowerCase() : '')).sort();
716
+ const right = [...opts.pick].map((sha) => sha.toLowerCase()).sort();
717
+ return left.every((sha, index) => /^[0-9a-f]{40}$/.test(sha) && sha === right[index]);
718
+ };
719
+ const ledgerPath = join(root, 'release', version, 'resume-attempts', `${opts.runId}.json`);
720
+ const recoveries: RecoverStageRecord[] = existsSync(ledgerPath)
721
+ ? ((JSON.parse(readFileSync(ledgerPath, 'utf8')) as { recoveries?: unknown[] }).recoveries ?? []) as RecoverStageRecord[]
722
+ : [];
723
+ let appendedCommit: string | undefined;
724
+ for (let index = recoveries.length - 1; index >= 0; index -= 1) {
725
+ const entry = recoveries[index]!;
726
+ if (entry.stage === 'append' && entry.outcome === 'ok' && typeof entry.commit === 'string' && samePickList(entry.pick)) {
727
+ appendedCommit = entry.commit;
728
+ break;
729
+ }
730
+ }
731
+ let advertised = '';
732
+ try {
733
+ advertised = (deps.git ?? gitRunner(repoRoot))(['ls-remote', '--heads', 'origin', `refs/heads/${branch}`]).split(/\s+/)[0] ?? '';
734
+ } catch {
735
+ advertised = '';
736
+ }
737
+ const isAncestor = deps.isAncestor ?? ancestorRunner(repoRoot);
738
+ const humanResume = `release resume --run ${opts.runId} --from ${fromNode}`;
739
+ const alreadyInGuidance = (cause: string): string =>
740
+ `${cause} — ${branch}가 이미 고른 수선을 담고 있다: 이 recover는 append하지 않았다. 사람이 직접 이어 간다: ${humanResume}`;
741
+ let tip = '';
742
+ if (appendedCommit !== undefined && /^[0-9a-f]{40}$/i.test(advertised) && isAncestor(appendedCommit, advertised)) {
743
+ tip = advertised;
744
+ deps.onSource?.(`· recover 재진입 · 원장의 append-ok(${appendedCommit.slice(0, 12)})이 가지 끝에 그대로 있다 — append를 다시 하지 않고 ${fromNode} resume부터 이어 간다`);
745
+ } else {
746
+ if (/^[0-9a-f]{40}$/i.test(advertised) && opts.pick.every((sha) => isAncestor(sha, advertised))) {
747
+ // The repair is on the branch already (a hand-run append) and the ledger has no append-ok for it: there is
748
+ // nothing to append — the stop error and the ledger record both name the human's next step.
749
+ const guidance = alreadyInGuidance(`pick ${opts.pick.join(' + ')} is already in ${branch}`);
750
+ record({ stage: 'append-dry-run', outcome: 'failed', at: now(), branch, reason: guidance });
751
+ return stop('append-dry-run', new Error(guidance));
752
+ }
753
+ // 1/3 append dry-run — the fast-forward plan only: no worktree, no push, no run-state write.
754
+ try {
755
+ const planned = cutBranch({ ...cut, dryRun: true });
756
+ record({ stage: 'append-dry-run', outcome: 'ok', at: now(), branch: planned.branch, commit: planned.commit });
757
+ deps.onSource?.(`· recover 1/3 append dry-run · ${planned.branch} ← ${opts.pick.join(' + ')} · 가지·push·런 상태 변경 없음`);
758
+ } catch (error) {
759
+ const raw = reason(error);
760
+ if (!/is already in /.test(raw)) {
761
+ record({ stage: 'append-dry-run', outcome: 'failed', at: now(), branch, reason: raw });
762
+ return stop('append-dry-run', error);
763
+ }
764
+ const guided = alreadyInGuidance(raw);
765
+ record({ stage: 'append-dry-run', outcome: 'failed', at: now(), branch, reason: guided });
766
+ return stop('append-dry-run', new Error(guided));
767
+ }
768
+ // 2/3 append — cherry-pick the repairs onto release/<v> and push the fast-forward (never a force push).
769
+ try {
770
+ const appended = cutBranch(cut);
771
+ if (!appended.commit) throw new Error(`${appended.branch} append produced no commit`);
772
+ tip = appended.commit;
773
+ record({ stage: 'append', outcome: 'ok', at: now(), branch: appended.branch, commit: tip, pick: opts.pick });
774
+ deps.onSource?.(`↻ recover 2/3 append · ${appended.branch} ${base.slice(0, 12)} → ${tip.slice(0, 12)} (fast-forward)`);
775
+ } catch (error) {
776
+ const raw = reason(error);
777
+ if (!/is already in /.test(raw)) {
778
+ record({ stage: 'append', outcome: 'failed', at: now(), branch, reason: raw });
779
+ return stop('append', error);
780
+ }
781
+ const guided = alreadyInGuidance(raw);
782
+ record({ stage: 'append', outcome: 'failed', at: now(), branch, reason: guided });
783
+ return stop('append', new Error(guided));
784
+ }
785
+ }
786
+
787
+ // 3/3 resume --from export-check — the read-only preflight first (its plan is the record), then the graph run.
788
+ // The append moved only the origin branch tip: the operator checkout is still wherever it was, and the resume
789
+ // preflight (verifyReleaseCommandRoot) demands a checkout whose HEAD is the new tip. So recover prepares that
790
+ // checkout itself — a temporary worktree at the tip. A human-provided --command-root stays a judgment
791
+ // boundary: the plan verifies it against the tip and stops there on a mismatch.
792
+ const resumeOptions: ResumeReleaseOptions = { runId: opts.runId, from: fromNode,
793
+ ...(opts.partial === undefined ? {} : { partial: opts.partial }) };
794
+ let preparedRoot: { dir: string; git: (args: string[]) => string } | undefined;
795
+ if (opts.commandRoot !== undefined) resumeOptions.commandRoot = opts.commandRoot;
796
+ else {
797
+ const temp = mkdtempSync(join(tmpdir(), 'release-recover-'));
798
+ const dir = join(temp, 'command-root');
799
+ const worktreeGit = gitRunner(repoRoot);
800
+ try {
801
+ worktreeGit(['worktree', 'add', '--detach', dir, tip]);
802
+ } catch (error) {
803
+ rmSync(temp, { recursive: true, force: true });
804
+ throw error;
805
+ }
806
+ preparedRoot = { dir, git: worktreeGit };
807
+ resumeOptions.commandRoot = dir;
808
+ }
809
+ try {
810
+ const plan = await planResumeReleaseRun(resumeOptions, deps);
811
+ const resumed = await resumeReleaseRun(resumeOptions, deps);
812
+ record({ stage: 'resume', outcome: 'ok', at: now(), from: fromNode, branch: resumed.tip.branch,
813
+ commit: resumed.tip.to, gatePlan: plan.gatePlan.mode, status: resumed.state.status });
814
+ deps.onSource?.(`▶ recover 3/3 resume ${fromNode}부터 · tip ${resumed.tip.to.slice(0, 12)} · gate ${plan.gatePlan.mode} → ${resumed.state.status}`);
815
+ return { runId: opts.runId, version, branch: resumed.tip.branch, fromNode, stages,
816
+ resume: { status: resumed.state.status, tip: resumed.tip, partial: resumed.partial } };
817
+ } catch (error) {
818
+ record({ stage: 'resume', outcome: 'failed', at: now(), from: fromNode, branch, reason: reason(error) });
819
+ return stop('resume', error);
820
+ } finally {
821
+ if (preparedRoot) {
822
+ try {
823
+ preparedRoot.git(['worktree', 'remove', '--force', preparedRoot.dir]);
824
+ } catch {
825
+ try { preparedRoot.git(['worktree', 'prune']); } catch { /* the temp dir below is still removed */ }
826
+ }
827
+ rmSync(dirname(preparedRoot.dir), { recursive: true, force: true });
828
+ }
829
+ }
830
+ }
@@ -0,0 +1,10 @@
1
+ // Resume tests need the same writable traffic-file prerequisite as the installed release configuration.
2
+ // This module is imported only by test files; the gate process owns and discards this environment.
3
+ import { rmSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+
7
+ const trafficFile = join(tmpdir(), `elanous-resume-test-traffic-${process.pid}.json`);
8
+ writeFileSync(trafficFile, '{}\n');
9
+ process.env.ELANOUS_RELEASE_TRAFFIC_FILE = trafficFile;
10
+ process.once('exit', () => rmSync(trafficFile, { force: true }));
@@ -53,12 +53,20 @@ function printedVerdict(output: unknown): boolean {
53
53
  });
54
54
  }
55
55
 
56
- /** The only post-gate detour allowed before the terminal failure is the executed, release-only triage shadow. */
57
- function failedAfterGate(state: GraphRunState, index: number): boolean {
56
+ /** A failed release may execute its warning-only traffic restore before the terminal failure. */
57
+ function failedAfterTrafficRestore(state: GraphRunState, index: number): boolean {
58
58
  if (state.nodes.length !== state.path.length || state.path.at(-1) !== 'failed' || state.nodes.at(-1)?.nodeId !== 'failed') return false;
59
59
  if (index === state.path.length - 2) return true;
60
- return index === state.path.length - 3 && state.path[index + 1] === 'gate-triage'
61
- && state.nodes[index + 1]?.nodeId === 'gate-triage' && state.nodes[index + 1]?.executed === true;
60
+ return index === state.path.length - 3 && state.path[index + 1] === 'traffic-failed-restore'
61
+ && state.nodes[index + 1]?.nodeId === 'traffic-failed-restore' && state.nodes[index + 1]?.executed === true;
62
+ }
63
+
64
+ /** Gate may also pass through its executed triage shadow before the traffic restore. */
65
+ function failedAfterGate(state: GraphRunState, index: number): boolean {
66
+ if (failedAfterTrafficRestore(state, index)) return true;
67
+ return state.path[index + 1] === 'gate-triage'
68
+ && state.nodes[index + 1]?.nodeId === 'gate-triage' && state.nodes[index + 1]?.executed === true
69
+ && failedAfterTrafficRestore(state, index + 1);
62
70
  }
63
71
 
64
72
  export function gateUnmeasuredDetail(state: GraphRunState, index: number): string | undefined {
@@ -113,7 +121,7 @@ export function releaseResumeWaiver(
113
121
  }
114
122
  if (!unique || state.path.lastIndexOf(opts.waive) !== index || state.nodes[index]?.nodeId !== opts.waive || state.nodes[index]?.ok !== false ||
115
123
  state.nodes[index]?.executed !== true || (opts.waive === 'gate' ? !failedAfterGate(state, index)
116
- : state.path.at(-2) !== opts.waive || state.path.at(-1) !== 'failed' || state.nodes.at(-1)?.nodeId !== 'failed')) {
124
+ : !failedAfterTrafficRestore(state, index))) {
117
125
  throw new Error(`--waive ${opts.waive} requires the failed executable node on the saved path`);
118
126
  }
119
127
  // Only user-visible, non-publication checks can become accepted regressions; build, safety and approval gates stay blocking.
@@ -7,8 +7,11 @@ import { errorResult, finishNode, readGraphContext } from './node-verdict.js';
7
7
  import { applyReleaseTrafficEvent, trafficOptionsFromConfig, type ReleaseTrafficEvent, type TrafficTransitionOptions } from './traffic-transition.js';
8
8
 
9
9
  const EVENTS: Record<string, ReleaseTrafficEvent> = {
10
+ 'traffic-cut-start': 'cut-start',
10
11
  'traffic-gate-passed': 'gate-passed',
12
+ 'traffic-npm-published': 'npm-published',
11
13
  'traffic-verify-complete': 'verify-complete',
14
+ 'traffic-failed-restore': 'failed',
12
15
  };
13
16
 
14
17
  export interface TrafficNodeDeps {
@@ -40,12 +43,17 @@ export async function runTrafficNode(node = process.argv[2], env: NodeJS.Process
40
43
  }
41
44
  const result = await applyReleaseTrafficEvent(context, event, options);
42
45
  if (!result.applied) {
43
- const consequence = event === 'verify-complete'
44
- ? '릴리스 검증은 성공했으나 트래픽 복귀가 적용되지 않았습니다.'
45
- : 'gate는 성공했으나 트래픽 감속이 적용되지 않았습니다.';
46
+ const consequence = event === 'failed' && result.reason === 'published-keeps-full'
47
+ ? 'npm 발행은 완료됐으므로 전체 트래픽을 유지합니다. 후속 발행 단계 실패를 확인하세요.'
48
+ : event === 'verify-complete' || event === 'npm-published'
49
+ ? '발행은 성공했으나 전체 트래픽 전환이 적용되지 않았습니다.'
50
+ : event === 'failed' ? '컷 전 트래픽 복귀가 적용되지 않았습니다.'
51
+ : event === 'cut-start' ? '컷은 시작했으나 gate 모드 전환이 적용되지 않았습니다.'
52
+ : 'gate는 성공했으나 트래픽 감속이 적용되지 않았습니다.';
46
53
  (deps.report ?? reportFailure)(`RELEASE-POSTPUB-TRAFFIC ${version} ${runId || 'unknown'} ${node} 무시 — ${result.reason ?? 'traffic state unchanged'}. ${consequence}`);
47
54
  }
48
- return finishNode(node!, version, { outcome: 'ok', verdict: 'pass', summary: `${event} ${result.applied ? 'applied' : result.reason ?? 'ignored'}` });
55
+ return finishNode(node!, version, { outcome: result.applied ? 'ok' : 'fail', verdict: result.applied ? 'pass' : 'fail',
56
+ summary: `${event} ${result.applied ? 'applied' : result.reason ?? 'ignored'}` });
49
57
  } catch (error) {
50
58
  const detail = errorResult(error).summary;
51
59
  const isLockTimeout = detail.startsWith('traffic lock timeout:');