elanous 0.2.32 → 0.2.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (633) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → L04y73dlwKeTW-GetaTF3}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +79 -0
  5. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +94 -0
  8. package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 1644.35dd25240ae24e4b.js} +2 -2
  9. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 1895-60ed0e341c658bd4.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 2124.ed5bf480cea7f85b.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +23 -0
  13. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +115 -0
  15. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +8 -0
  16. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 2547.dd27303624cb4da8.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 2554.3b5e200f5f5cfcd6.js} +16 -16
  19. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 2987-30cf9c2eb7b8bdd5.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{3541-ce3a5424ed5ad7f1.js → 3001-5a52788c813b6113.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +34 -0
  30. package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 3110.0a7065f25c841818.js} +17 -17
  31. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3121.779fafe3e44612c5.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 3414.172ad4ca2d9b08e8.js} +2 -2
  37. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{4745.67d6f99c245af3f7.js → 3498.cf2a15a8a9e5b926.js} +3 -3
  39. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +32 -0
  41. package/apps/pwa/out/_next/static/chunks/{5543.a438b8ab5a13ea47.js → 3837.722e053fb9f321ad.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +104 -0
  44. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +286 -0
  45. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +149 -0
  46. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +148 -0
  47. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +64 -0
  48. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +74 -0
  51. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → 4fa33ebd.21c1bd5b294496e6.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 5014f970-22bef0b5210f7d60.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/{2112-e4efc21a6505d5bc.js → 5028-f0722e6114c313e7.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/{2898.fd781bc7cf01a7b7.js → 5249.96a848656b582a93.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +62 -0
  60. package/apps/pwa/out/_next/static/chunks/{9407.e49124dedf0f5e72.js → 5446.edf141cff9ef647d.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9002.e5658224e3dc1b6f.js → 5489.ec2dd1b5272a19dc.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 5576-82d3703636d5c4b9.js} +3 -3
  63. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 6086.913a69e6fa3e4a8b.js} +4 -4
  70. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +77 -0
  76. package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 6740.43de73fc427c9fe2.js} +1 -1
  77. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +90 -0
  80. package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7005.1623d2aea78eb85f.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +287 -0
  87. package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 7431.3051e9b8a4372d2d.js} +2 -2
  88. package/apps/pwa/out/_next/static/chunks/{3583.a05e88cc8d594628.js → 7448.478958ffbbba0ac0.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +41 -0
  91. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +27 -0
  94. package/apps/pwa/out/_next/static/chunks/{9989.3694300e5f000b14.js → 7952.b192c31b6a0e00cc.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +36 -0
  97. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 8368.014caa8de2f5af34.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 8548.036c344973968847.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 9131-fce7256c4180c4a5.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +93 -0
  114. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +24 -0
  116. package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9550.d5f76828f972058c.js} +2 -2
  117. package/apps/pwa/out/_next/static/chunks/{2534.e85ae21ad0dac829.js → 9739.8d5f36ac67a3b236.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → 9a8cb466.cc9fc9e6e46038aa.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → 9b48c871.204d5d13e7809bd0.js} +7 -7
  123. package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → abb4b98b.163e0f56e84ae35d.js} +1 -1
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-8c66a3b24a745630.js → page-398c0faa173203f7.js} +1 -1
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-df3445b207ceceab.js} +1 -1
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{ebc7d829.264a0bcb6c750b50.js → ffdc3a04.b9c23c1b28dd4a96.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +1 -0
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/bin/elanous.mjs +9 -2
  278. package/docs/goal-context/README.md +1 -0
  279. package/graphs/default-loop.yaml +20 -3
  280. package/graphs/document-loop.yaml +21 -2
  281. package/graphs/implement-loop.yaml +6 -0
  282. package/graphs/journey/SCENARIOS.md +33 -0
  283. package/graphs/journey/recipes.yaml +1 -0
  284. package/graphs/journey/ta-journey.yaml +84 -0
  285. package/graphs/journey/units/author/author.yaml +20 -0
  286. package/graphs/journey/units/author/recipes.yaml +2 -0
  287. package/graphs/journey/units/green/green.yaml +20 -0
  288. package/graphs/journey/units/green/recipes.yaml +2 -0
  289. package/graphs/journey/units/pr/pr.yaml +20 -0
  290. package/graphs/journey/units/pr/recipes.yaml +2 -0
  291. package/graphs/journey/units/remember/recipes.yaml +2 -0
  292. package/graphs/journey/units/remember/remember.yaml +20 -0
  293. package/graphs/operate-loop.yaml +21 -2
  294. package/graphs/overlays/stop-heal-ladder.yaml +1 -1
  295. package/graphs/release-rehearsal/recipes.yaml +1 -1
  296. package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
  297. package/graphs/research-loop.yaml +23 -2
  298. package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
  299. package/graphs/units/dispatch-pod/recipes.yaml +14 -0
  300. package/graphs/units/entry/entry.yaml +50 -0
  301. package/graphs/units/entry/recipes.yaml +14 -0
  302. package/graphs/units/harvest/harvest.yaml +25 -0
  303. package/graphs/units/harvest/recipes.yaml +4 -0
  304. package/graphs/units/land/land.yaml +45 -0
  305. package/graphs/units/land/recipes.yaml +3 -0
  306. package/graphs/units/recipes.yaml +7 -0
  307. package/graphs/units/recover.yaml +39 -0
  308. package/graphs/units/reflect/recipes.yaml +3 -0
  309. package/graphs/units/reflect/reflect.yaml +15 -0
  310. package/graphs/units/task-agent-recover-review.yaml +17 -0
  311. package/graphs/units/task-agent-recover-wait.yaml +17 -0
  312. package/graphs/units/verbs/make-doc.yaml +34 -0
  313. package/graphs/units/verbs/recipes.yaml +33 -0
  314. package/graphs/units/verbs/verify.yaml +55 -0
  315. package/graphs/work/recipes.yaml +2 -0
  316. package/graphs/work/research-report.yaml +28 -0
  317. package/package.json +1 -1
  318. package/scripts/ci-typecheck-changed.ts +69 -16
  319. package/scripts/docs/generate-graph-anatomy.ts +19 -2
  320. package/scripts/graph-harvest-unit.ts +22 -0
  321. package/scripts/graph-units/journey-stub.ts +6 -0
  322. package/scripts/graph-units/land-enqueue.ts +78 -0
  323. package/scripts/graph-units/recover-plan.ts +15 -0
  324. package/scripts/graph-units/reflect-node.ts +88 -0
  325. package/scripts/graph-units/ta-journey-observe.ts +109 -0
  326. package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
  327. package/scripts/graph-units/verbs/verify-stage.ts +75 -0
  328. package/scripts/graph-units/verbs-envelope.ts +139 -0
  329. package/scripts/hq/standby-snapshot.ts +25 -0
  330. package/scripts/public-export.ts +43 -1
  331. package/scripts/ratchets/train-side-invariants.sh +45 -0
  332. package/scripts/release-loop/auto-approve-node.ts +30 -16
  333. package/scripts/release-loop/gate-closure.ts +5 -1
  334. package/scripts/release-loop/gate-diff.ts +1 -1
  335. package/scripts/release-loop/gate-node.ts +498 -31
  336. package/scripts/release-loop/gate-partial.ts +3 -3
  337. package/scripts/release-loop/gate-radius-shadow.ts +138 -0
  338. package/scripts/release-loop/gate-traffic-mode.ts +128 -0
  339. package/scripts/release-loop/gate-triage-node.ts +5 -2
  340. package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
  341. package/scripts/release-loop/known-issues-node.ts +77 -8
  342. package/scripts/release-loop/preflight.ts +93 -7
  343. package/scripts/release-loop/publish-node.ts +60 -9
  344. package/scripts/release-loop/resume-cap.ts +56 -0
  345. package/scripts/release-loop/resume-release.ts +114 -15
  346. package/scripts/release-loop/resume.ts +24 -1
  347. package/scripts/release-loop/tui-sim-node.ts +8 -2
  348. package/scripts/release-loop/unattended-release.ts +8 -2
  349. package/src/acp/core-turn-bridge.ts +20 -5
  350. package/src/acp/reasoning-thought-buffer.ts +45 -0
  351. package/src/agent-substrate/acp-reviewer.ts +52 -12
  352. package/src/agent-substrate/review-finding-key.ts +53 -0
  353. package/src/agent-substrate/self-review-cli.ts +126 -5
  354. package/src/ask-user-question/pending-questions.ts +1 -1
  355. package/src/autopilot/pr-manager.ts +192 -43
  356. package/src/chat/tool-render/dispatch.ts +62 -10
  357. package/src/cli/control-cli.ts +24 -7
  358. package/src/cli/guardian-cli.ts +10 -0
  359. package/src/cli/light-entry-route.ts +35 -0
  360. package/src/cli/llm-detect-cli.ts +23 -1
  361. package/src/cli/pr-cli.ts +76 -12
  362. package/src/cli/pr-land-base-read.ts +2 -0
  363. package/src/cli/pr-land-overlap-evidence.ts +154 -16
  364. package/src/cli/pr-land-recovery.ts +64 -0
  365. package/src/cli/pty-takeover-cli.ts +6 -5
  366. package/src/cli/release-cli.ts +120 -33
  367. package/src/cli/release-run-if-ready.ts +29 -28
  368. package/src/cli/release-single-flight.ts +178 -0
  369. package/src/cli/seat-cli.ts +37 -0
  370. package/src/cli/setup-cli.ts +40 -1
  371. package/src/cli/tasks-cli.ts +149 -5
  372. package/src/control/control-status.ts +8 -3
  373. package/src/control-plane/ledger.ts +5 -3
  374. package/src/control-plane/server.ts +5 -3
  375. package/src/core-turn/short-question.ts +5 -1
  376. package/src/dashboard/index.ts +36 -67
  377. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
  378. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  379. package/src/dashboard/input/seat-autowake.ts +56 -3
  380. package/src/dashboard/seat-boot-preamble.ts +1 -1
  381. package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
  382. package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
  383. package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
  384. package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
  385. package/src/dashboard/turn-preamble.ts +47 -1
  386. package/src/dashboard/turn-stream-formatter.ts +34 -1
  387. package/src/dashboard/turn-stream-runtime.ts +2 -0
  388. package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
  389. package/src/domains/guardian-tick.ts +54 -2
  390. package/src/domains/outbound-alert.ts +3 -2
  391. package/src/extractors.ts +3 -1
  392. package/src/git-fs/retry.ts +4 -0
  393. package/src/git-fs/runner.ts +2 -0
  394. package/src/graph-runner/runner.ts +114 -44
  395. package/src/grok/credential.ts +5 -0
  396. package/src/harness/harness-cli-command.ts +39 -10
  397. package/src/harness/harness-incidents.ts +4 -0
  398. package/src/harness/harness-pod-dispatch.ts +38 -1
  399. package/src/harness/harness-salvage-cli.ts +14 -2
  400. package/src/index.ts +192 -8
  401. package/src/intake-plane/already-built-hint.ts +89 -0
  402. package/src/knowhow/pack.ts +199 -0
  403. package/src/light-cli.ts +95 -0
  404. package/src/llm.ts +55 -9
  405. package/src/loops/budget.ts +95 -0
  406. package/src/loops/msg-wake.ts +8 -2
  407. package/src/loops/orchestrator/traffic.ts +132 -1
  408. package/src/mss/logging/log-store.ts +4 -5
  409. package/src/nexus/api/graphs-api.ts +22 -3
  410. package/src/nexus/api/http-server.ts +1 -1
  411. package/src/nexus/api/ops-api.ts +12 -0
  412. package/src/oauth/claude-pty-maturity.ts +66 -0
  413. package/src/oauth/codex-access-mirror.ts +55 -0
  414. package/src/oauth/fallback-chain.ts +1 -1
  415. package/src/onboarding/first-run.ts +5 -3
  416. package/src/onboarding/non-interactive.ts +64 -13
  417. package/src/onboarding.ts +10 -2
  418. package/src/ops/overview-collect.ts +36 -1
  419. package/src/ops/overview.ts +11 -0
  420. package/src/pr-tool/census.ts +23 -5
  421. package/src/pr-tool/inflight-registry.ts +160 -7
  422. package/src/prompt-library/gpt6-family-addendum.ts +14 -1
  423. package/src/pty-shell/herdr-agent-report.ts +442 -0
  424. package/src/pty-shell/pty-control-ipc.ts +5 -5
  425. package/src/pty-shell/pty-write-outcome.ts +24 -6
  426. package/src/pty-shell/tui-run-state.ts +117 -3
  427. package/src/release-loop/checklist.ts +79 -5
  428. package/src/release-loop/feature-store.ts +19 -2
  429. package/src/release-loop/placement.ts +10 -3
  430. package/src/release-loop/rehearsal.ts +205 -25
  431. package/src/release-loop/rubric.ts +16 -2
  432. package/src/self-dev/draft-sweep.ts +52 -3
  433. package/src/self-dev/graph-journey-nodes.ts +10 -6
  434. package/src/self-dev/graph-journey-route.ts +60 -6
  435. package/src/self-dev/orchestrate.ts +79 -3
  436. package/src/self-dev/run-supervisor.ts +107 -12
  437. package/src/self-dev/run-types.ts +5 -1
  438. package/src/self-implement/gate-baseline.ts +49 -5
  439. package/src/self-implement/gate-remote.ts +9 -5
  440. package/src/self-implement/goal-author-identity.ts +66 -0
  441. package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
  442. package/src/self-implement/goal-author.ts +4 -120
  443. package/src/self-implement/graph-overlay-yaml.ts +17 -2
  444. package/src/self-implement/graph-unit-flatten.ts +103 -0
  445. package/src/self-implement/graph-unit-resolver.ts +107 -0
  446. package/src/self-implement/graph-yaml.ts +151 -1
  447. package/src/self-implement/headless-elanous-driver.ts +1 -0
  448. package/src/self-implement/knowhow-pack.ts +103 -0
  449. package/src/self-implement/orchestrator.ts +8 -0
  450. package/src/self-implement/pod-warm-pool-profile.ts +45 -0
  451. package/src/self-implement/review-mustfix-class.ts +203 -0
  452. package/src/self-implement/run-stop.ts +8 -2
  453. package/src/self-implement/seams.ts +32 -1
  454. package/src/self-implement/stop-autoheal.ts +25 -1
  455. package/src/session/chat.ts +27 -0
  456. package/src/session-runtime/retry-policy.ts +2 -1
  457. package/src/skills/tools/schedule-wakeup.ts +66 -17
  458. package/src/steward/release-day.ts +7 -3
  459. package/src/steward/triage.ts +37 -4
  460. package/src/task-agent/harvest-unit.ts +141 -0
  461. package/src/task-agent/live-moves.ts +98 -12
  462. package/src/task-agent/parent-host.ts +93 -3
  463. package/src/task-agent/postland-card.ts +80 -1
  464. package/src/task-agent/rejudge-on-head.ts +112 -26
  465. package/src/task-agent/repair-branch-cas.ts +4 -1
  466. package/src/task-agent/repair-cycle.ts +16 -3
  467. package/src/task-agent/run-identity.ts +4 -3
  468. package/src/task-agent/shadow.ts +12 -2
  469. package/src/task-agent/task-hand.ts +54 -7
  470. package/src/task-agent/work-order-build.ts +22 -0
  471. package/src/task-orchestrator/surfaces/pod-account-broker.ts +39 -3
  472. package/src/task-orchestrator/surfaces/pod-command-job.ts +2 -1
  473. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
  474. package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
  475. package/src/task-orchestrator/surfaces/pod-source-receive.ts +54 -4
  476. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +26 -3
  477. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +389 -0
  478. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
  479. package/src/task-orchestrator/surfaces/self-implement-pod.ts +223 -38
  480. package/src/task-orchestrator/surfaces/self-implement.ts +83 -2
  481. package/src/tool-runtime/truncation-store.ts +4 -0
  482. package/src/tui-client/dashboard-session.ts +10 -1
  483. package/src/user-config/coercion.ts +36 -0
  484. package/src/user-config.ts +18 -41
  485. package/src/ux-sim/scenario.ts +72 -13
  486. package/src/version/packed-revision.json +1 -1
  487. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
  490. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
  491. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
  492. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
  496. package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
  498. package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
  499. package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
  506. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
  507. package/apps/pwa/out/_next/static/chunks/3267c0e6.d34854e7b3984a6e.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +0 -34
  510. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
  514. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
  518. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
  519. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
  521. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
  524. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
  529. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
  531. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
  538. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
  539. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
  541. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
  546. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
  547. package/apps/pwa/out/_next/static/chunks/69-0a2c8209c6d4a158.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
  555. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/control/page-a27b1e5a0d1b308f.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/morning/page-32866485913d6a04.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
  625. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
  632. package/src/cli/g6a-registration-probe.ts +0 -16
  633. /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → L04y73dlwKeTW-GetaTF3}/_ssgManifest.js +0 -0
@@ -1,29 +1,47 @@
1
1
  import { spawnSync } from 'node:child_process';
2
2
  import { randomUUID } from 'node:crypto';
3
- import { existsSync, linkSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
3
+ import { appendFileSync, closeSync, existsSync, linkSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, renameSync, rmSync, realpathSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
- import { dirname, join } from 'node:path';
5
+ import { dirname, join, resolve } from 'node:path';
6
6
  import { debug } from '../debug/log.js';
7
+ import { stateDirSourceForChild } from '../agent/identity-env.js';
7
8
  import { sendOutbound } from '../domains/outbound-alert.js';
8
9
  import { releaseLedgerRoot } from '../instance/resolve.js';
9
10
  import { isValidGateHost } from '../self-implement/gate-remote.js';
11
+ import { parsePodPool } from '../task-orchestrator/surfaces/pod-pool.js';
12
+ import { latestPublishedPreviousVersion, releaseLoopConfig } from '../../scripts/release-loop/unattended-release.js';
13
+ import { LEAK_MARKERS, loadExportConfig, selectExportFiles } from '../../scripts/public-export.js';
10
14
  import { LIGHT_RC_UNKNOWN_HOST, runLightRc, type LightRcResult } from './light-rc.js';
11
15
  import { planRehearsalShards, type RehearsalShardPlan, type RehearsalShardPlanDeps } from './rehearsal-shard-plan.js';
12
16
  import { listSchedules, type ReleaseSchedule } from './release-schedule.js';
17
+ import { SPAWN_SYNC_MAX_BUFFER } from '../util/spawn-sync-output.js';
13
18
 
14
- export type StepId = 'rc-7h' | 'rc-150m';
19
+ export type StepId = 'hard-mid' | 'rc-7h' | 'hard-5h' | 'rc-150m';
15
20
  export type RehearsalOutcome = 'ok' | 'regression' | 'unmeasured' | 'error' | 'no-checkout' | 'checkout-dirty' | 'superseded' | 'interrupted';
21
+ export interface HardGateResult {
22
+ outcome: 'ok' | 'regression' | 'error';
23
+ commit: string;
24
+ executor: 'pod' | 'host' | null;
25
+ introduced: string[];
26
+ preexisting: number;
27
+ error?: string;
28
+ }
16
29
  export type RehearsalPlan =
17
30
  | { status: 'no-schedule' }
18
31
  | { status: 'not-yet'; version: string; cutAt: string; nextStepAt: string }
19
32
  | { status: 'due'; version: string; cutAt: string; run: StepId | null; supersede: StepId[] }
20
33
  | { status: 'nothing-due'; version: string; cutAt: string };
21
34
 
22
- const steps = [{ id: 'rc-7h', minutes: 420 }, { id: 'rc-150m', minutes: 150 }] as const;
35
+ const fixedSteps = [{ id: 'rc-7h', minutes: 420 }, { id: 'hard-5h', minutes: 300 }, { id: 'rc-150m', minutes: 150 }] as const;
23
36
  const minute = 60_000;
37
+ function rehearsalSteps(intervalHours = 12): Array<{ id: StepId; minutes: number }> {
38
+ if (!Number.isSafeInteger(intervalHours) || intervalHours < 8 || intervalHours > 72)
39
+ throw new Error('release.loop.rehearsalHardIntervalHours must be an integer from 8 to 72');
40
+ return [{ id: 'hard-mid', minutes: intervalHours * 60 }, ...fixedSteps];
41
+ }
24
42
 
25
- /** Only the earliest future cut is eligible. A missed early step is never run back-to-back with the late step. */
26
- export function planRehearsal(schedules: readonly ReleaseSchedule[], now: Date, stamps: Readonly<Partial<Record<StepId, boolean>>>): RehearsalPlan {
43
+ /** Only the earliest future cut is eligible. A missed step is superseded rather than run beside a later one. */
44
+ export function planRehearsal(schedules: readonly ReleaseSchedule[], now: Date, stamps: Readonly<Partial<Record<StepId, boolean>>>, intervalHours = 12): RehearsalPlan {
27
45
  const current = now.getTime();
28
46
  if (!Number.isFinite(current)) throw new Error('now must be a valid date');
29
47
  const schedule = schedules.filter(row => Number.isFinite(Date.parse(row.cutAt)) && Date.parse(row.cutAt) > current)
@@ -31,14 +49,20 @@ export function planRehearsal(schedules: readonly ReleaseSchedule[], now: Date,
31
49
  if (!schedule) return { status: 'no-schedule' };
32
50
  const { version, cutAt } = schedule;
33
51
  const cut = Date.parse(cutAt);
52
+ const steps = rehearsalSteps(intervalHours);
34
53
  const open = steps.filter(step => !stamps[step.id]);
35
54
  if (!open.length) return { status: 'nothing-due', version, cutAt };
36
55
  if (current >= cut - 45 * minute) return { status: 'due', version, cutAt, run: null, supersede: open.map(step => step.id) };
37
- if (current >= cut - 150 * minute) {
38
- return { status: 'due', version, cutAt, run: stamps['rc-150m'] ? null : 'rc-150m', supersede: stamps['rc-7h'] ? [] : ['rc-7h'] };
56
+ const latestDue = [...steps].reverse().find(step => current >= cut - step.minutes * minute);
57
+ if (latestDue) {
58
+ const run = stamps[latestDue.id] ? null : latestDue.id;
59
+ const supersede = steps.filter(step => step.minutes > latestDue.minutes && !stamps[step.id]).map(step => step.id);
60
+ if (!run && supersede.length === 0) {
61
+ const next = open.find(step => current < cut - step.minutes * minute);
62
+ if (next) return { status: 'not-yet', version, cutAt, nextStepAt: new Date(cut - next.minutes * minute).toISOString() };
63
+ }
64
+ return { status: 'due', version, cutAt, run, supersede };
39
65
  }
40
- const due = open.filter(step => current >= cut - step.minutes * minute);
41
- if (due.length) return { status: 'due', version, cutAt, run: due[0]!.id, supersede: [] };
42
66
  return { status: 'not-yet', version, cutAt, nextStepAt: new Date(cut - open[0]!.minutes * minute).toISOString() };
43
67
  }
44
68
 
@@ -53,8 +77,13 @@ export interface RehearsalStamp {
53
77
  summary?: string;
54
78
  regressionFiles?: string[];
55
79
  result?: LightRcResult;
80
+ hardGate?: HardGateResult;
81
+ hardGateRunId?: string;
82
+ hardGateLog?: string;
83
+ /** B6: an unmeasured hard gate always retains a cause, run id and durable local evidence path. */
84
+ measurementGap?: { cause: string; runId: string; evidence: string };
56
85
  shardPlan?: RehearsalShardPlan;
57
- leakCheck?: { outcome: 'ok' | 'fail'; sha: string; exitCode: number | null };
86
+ leakCheck?: { outcome: 'ok' | 'fail'; sha: string; exitCode: number | null; detail?: string };
58
87
  selection?: { shards?: number; remote?: string };
59
88
  notifiedAt?: string;
60
89
  ownerPid?: number;
@@ -69,14 +98,16 @@ export interface RehearsalOptions {
69
98
  }
70
99
 
71
100
  export interface RehearsalDeps {
101
+ hardIntervalHours?: number;
72
102
  now?: () => Date;
73
103
  schedules?: (root: string) => ReleaseSchedule[];
74
104
  lightRc?: (version: string, checkout: string, selection: { shards?: number; remote?: string }) => Promise<LightRcResult>;
105
+ hardGate?: (version: string, checkout: string, sha: string, ledgerRoot: string, runId: string) => Promise<HardGateResult>;
75
106
  shardPlan?: typeof planRehearsalShards;
76
107
  shardPlanDeps?: RehearsalShardPlanDeps;
77
108
  notify?: (text: string) => void | boolean | Promise<void | boolean>;
78
109
  git?: (args: string[], cwd: string) => { rc: number | null; stdout: string; stderr?: string };
79
- leakCheck?: (checkout: string) => { status: number | null };
110
+ leakCheck?: (checkout: string) => { status: number | null; detail?: string };
80
111
  }
81
112
 
82
113
  export type RehearsalTickResult = RehearsalPlan & { applied?: boolean; stamps?: RehearsalStamp[]; notificationFailures?: number };
@@ -97,17 +128,103 @@ function gitResult(git: NonNullable<RehearsalDeps['git']>, args: string[], check
97
128
  return result.stdout.trim();
98
129
  }
99
130
 
131
+ export function rehearsalLeakFailureDetail(stdout: string, stderr: string, spawnError?: string): string {
132
+ try {
133
+ const report = JSON.parse(stdout.trim()) as {
134
+ leaks?: number; hits?: Array<{ marker?: string; file?: string; line?: number; text?: string }>;
135
+ };
136
+ const first = report.hits?.[0];
137
+ if (Number.isSafeInteger(report.leaks) && report.leaks! >= 0) {
138
+ if (!first) return `${report.leaks} hit(s)`;
139
+ return sanitizeRehearsalLeakDetail(`${report.leaks} hit(s) · ${first.marker ?? ''} ${first.file ?? ''}:${first.line ?? ''}`);
140
+ }
141
+ } catch { /* fall through to the process diagnostic */ }
142
+ return 'leak-check produced no structured diagnostic';
143
+ }
144
+
145
+ /** Validate before evidence persistence: JSON and injected checkers are both untrusted diagnostic inputs. */
146
+ export function sanitizeRehearsalLeakDetail(detail: string, checkout?: string): string {
147
+ if (detail === 'leak-check produced no structured diagnostic') return detail;
148
+ const parsed = /^(?<count>\d+) hit\(s\) · (?<marker>[a-z][a-z0-9-]{0,63}) (?<file>.+):(?<line>[1-9]\d*)$/.exec(detail);
149
+ if (!parsed?.groups) return 'leak-check produced no structured diagnostic';
150
+ const { count, marker, file, line } = parsed.groups;
151
+ const countValue = Number(count), lineValue = Number(line);
152
+ if (!Number.isSafeInteger(countValue) || countValue < 1 || !Number.isSafeInteger(lineValue) || lineValue < 1)
153
+ return 'leak-check produced no structured diagnostic';
154
+ const parts = file!.split('/');
155
+ if (!LEAK_MARKERS.some(item => item.marker === marker) || file!.startsWith('/')
156
+ || /[\p{Cc}]/u.test(file!) || parts.some(part => !part || part === '.' || part === '..'))
157
+ return 'leak-check produced no structured diagnostic';
158
+ if (checkout) {
159
+ try {
160
+ const tracked = spawnSync('git', ['ls-files', '-z'], { cwd: checkout, encoding: 'utf8', maxBuffer: SPAWN_SYNC_MAX_BUFFER });
161
+ if (tracked.status !== 0 || tracked.error) return 'leak-check produced no structured diagnostic';
162
+ const publicFiles = selectExportFiles((tracked.stdout ?? '').split('\0').filter(Boolean), loadExportConfig(checkout));
163
+ if (!publicFiles.includes(file!)) return 'leak-check produced no structured diagnostic';
164
+ const checkoutRoot = realpathSync(checkout);
165
+ const realFile = realpathSync(resolve(checkoutRoot, file!));
166
+ if (!realFile.startsWith(`${checkoutRoot}/`))
167
+ return 'leak-check produced no structured diagnostic';
168
+ const sourceLine = readFileSync(realFile, 'utf8').split(/\r?\n/)[lineValue - 1];
169
+ const markerPattern = LEAK_MARKERS.find(item => item.marker === marker)?.pattern;
170
+ if (!sourceLine || !markerPattern?.test(sourceLine)) return 'leak-check produced no structured diagnostic';
171
+ } catch { return 'leak-check produced no structured diagnostic'; }
172
+ }
173
+ return `${countValue} hit(s) · ${marker} ${file}:${lineValue}`;
174
+ }
175
+
100
176
  /** Public export checks the pinned rehearsal checkout before any remote RC work. Its output is private and ephemeral. */
101
- function runRehearsalLeakCheck(checkout: string): { status: number | null } {
177
+ export function runRehearsalLeakCheck(checkout: string): { status: number | null; detail?: string } {
102
178
  const out = mkdtempSync(join(tmpdir(), 'elanous-rehearsal-export-'));
103
179
  try {
104
- const result = spawnSync('bun', ['scripts/public-export.ts', '--out', join(out, 'export')], {
180
+ const result = spawnSync('bun', ['scripts/public-export.ts', '--out', join(out, 'export'), '--json', '--all'], {
105
181
  cwd: checkout, encoding: 'utf8', timeout: 1_800_000, maxBuffer: 64 * 1024 * 1024,
106
182
  });
107
- return { status: result.status };
183
+ if (result.status === 0) return { status: 0 };
184
+ return { status: result.status, detail: rehearsalLeakFailureDetail(result.stdout ?? '', result.stderr ?? '', result.error?.message) };
108
185
  } finally { rmSync(out, { recursive: true, force: true }); }
109
186
  }
110
187
 
188
+ /** The hard rehearsal uses the release gate itself, pinned to the fetched main SHA and node-b Pod member. */
189
+ async function runHardGate(version: string, checkout: string, sha: string, ledgerRoot: string, runId: string): Promise<HardGateResult> {
190
+ const configuredPool = releaseLoopConfig().gatePodPool;
191
+ if (!configuredPool) throw new Error('hard rehearsal requires release.loop.gatePodPool');
192
+ const members = parsePodPool(configuredPool);
193
+ const gateMember = members.find(member => member.sshHost === 'node-b');
194
+ if (!gateMember) throw new Error('hard rehearsal requires a live node-b Pod member');
195
+ const pool = configuredPool.split(',').map(part => part.trim())
196
+ .find(part => part.split(/[#:]/, 1)[0] === `${gateMember.context}@${gateMember.sshHost}`);
197
+ if (!pool) throw new Error('hard rehearsal cannot isolate the node-b Pod member');
198
+ const previous = latestPublishedPreviousVersion(version, ledgerRoot);
199
+ const logPath = join(ledgerRoot, 'release', version, 'rehearsal', `${runId}.log`);
200
+ mkdirSync(dirname(logPath), { recursive: true });
201
+ const run = (() => {
202
+ const log = openSync(logPath, 'wx', 0o600);
203
+ try { return spawnSync('bun', ['scripts/release-loop/gate-node.ts', '--commit', sha, '--version', version,
204
+ '--baseline-version', previous, '--executor', 'pod', '--pod-pool', pool, '--pod-shards', '12', '--json'], {
205
+ cwd: checkout, encoding: 'utf8', stdio: ['ignore', log, log], timeout: 4 * 60 * 60_000,
206
+ env: { ...process.env, ELANOUS_STATE_DIR: ledgerRoot, ELANOUS_STATE_DIR_SOURCE: stateDirSourceForChild(ledgerRoot) },
207
+ }); } finally { closeSync(log); }
208
+ })();
209
+ // stdout and stderr stream to the claim's durable evidence while the child is still running.
210
+ const output = readFileSync(logPath, 'utf8');
211
+ const line = output.split(/\r?\n/).reverse().find(value => value.trim().startsWith('{'));
212
+ if (!line) throw new Error(`hard rehearsal gate produced no JSON (rc=${run.status ?? 'spawn'}${run.error ? `: ${run.error.message}` : ''}; log ${logPath})`);
213
+ const result = JSON.parse(line) as HardGateResult;
214
+ if (!['ok', 'regression', 'error'].includes(result.outcome) || !Array.isArray(result.introduced)
215
+ || result.introduced.some(item => typeof item !== 'string')) {
216
+ throw new Error('hard rehearsal gate result lacks a valid verdict');
217
+ }
218
+ if (result.outcome !== 'error' && (result.commit !== sha || result.executor !== 'pod')) {
219
+ throw new Error('hard rehearsal gate result lacks pinned commit, Pod executor or verdict evidence');
220
+ }
221
+ if (result.outcome === 'ok' && result.introduced.length) throw new Error('hard rehearsal gate ok verdict contains introduced failures');
222
+ if (run.status === 0 && result.outcome === 'ok') return result;
223
+ if (run.status === 1 && result.outcome === 'regression') return result;
224
+ if (run.status === 2 && result.outcome === 'error') return result;
225
+ throw new Error(`hard rehearsal gate rc=${run.status ?? 'spawn'} disagrees with outcome=${result.outcome}`);
226
+ }
227
+
111
228
  function oneLine(text: string): string { return text.replace(/\s+/g, ' ').trim(); }
112
229
 
113
230
  function outcomeLine(stamp: RehearsalStamp): string {
@@ -121,7 +238,7 @@ function outcomeLine(stamp: RehearsalStamp): string {
121
238
  || (stamp.selection?.shards !== undefined && result.shards !== stamp.selection.shards)
122
239
  || (stamp.selection?.remote !== undefined && result.remote !== stamp.selection.remote);
123
240
  const detail = stamp.summary && (stamp.outcome === 'unmeasured' || stamp.outcome === 'error' && planningGap) ? ` · ${stamp.summary}` : '';
124
- return `${head} · 새 회귀 ${result.introduced ?? '못 쟀다'} · 기존 ${result.preexisting ?? '못 쟀다'} · 미분류 ${result.unclassified ?? '못 쟀다'} · ${result.remote ?? 'local'} · ${duration}분${stamp.outcome === 'error' ? ` · gate rc ${result.gateExitCode}${!result.ok ? ' · RC 실패' : ''}` : ''}${stamp.regressionFiles?.length ? ` · 파일 ${stamp.regressionFiles.slice(0, 3).join(', ')}` : ''}${detail}`;
241
+ return `${head} · 새 회귀 ${result.introduced ?? 'UNKNOWN'} · 기존 ${result.preexisting ?? 'UNKNOWN'} · 미분류 ${result.unclassified ?? 'UNKNOWN'} · ${result.remote ?? 'local'} · ${duration}분${stamp.outcome === 'error' ? ` · gate rc ${result.gateExitCode}${!result.ok ? ' · RC 실패' : ''}` : ''}${stamp.regressionFiles?.length ? ` · 파일 ${stamp.regressionFiles.slice(0, 3).join(', ')}` : ''}${detail}`;
125
242
  }
126
243
 
127
244
  function persistStamp(path: string, stamp: RehearsalStamp): void {
@@ -221,9 +338,19 @@ function interruptStamp(path: string, saved: RehearsalStamp, now: Date): Rehears
221
338
  try {
222
339
  const latest = JSON.parse(readFileSync(path, 'utf8')) as RehearsalStamp;
223
340
  if (latest.outcome !== 'running' || latest.endedAt || latest.startedAt !== saved.startedAt || latest.ownerPid !== saved.ownerPid || !ownerIsDead(latest.ownerPid)) return null;
341
+ if (latest.step === 'hard-mid' || latest.step === 'hard-5h') {
342
+ // The claim stores this identity atomically. Older running stamps may lack it, so recovery mints one.
343
+ const runId = latest.hardGateRunId || `hard-${randomUUID()}`;
344
+ const evidence = join(dirname(path), `${runId}.log`);
345
+ const cause = `hard rehearsal process ended before a gate verdict (pid ${latest.ownerPid})`;
346
+ appendFileSync(evidence, `${cause}\n`, { mode: 0o600 });
347
+ latest.hardGateRunId = runId;
348
+ latest.hardGateLog = evidence;
349
+ latest.measurementGap = { cause, runId, evidence };
350
+ latest.summary = `${cause} · runId ${runId} · evidence ${evidence}`;
351
+ } else latest.summary = '실행 프로세스 종료 · RC 재실행 안 함';
224
352
  latest.outcome = 'interrupted';
225
353
  latest.endedAt = now.toISOString();
226
- latest.summary = '실행 프로세스 종료 · RC 재실행 안 함';
227
354
  persistStamp(path, latest);
228
355
  return latest;
229
356
  } finally {
@@ -231,7 +358,7 @@ function interruptStamp(path: string, saved: RehearsalStamp, now: Date): Rehears
231
358
  }
232
359
  }
233
360
 
234
- /** wx claim is permanent per version/step; a crashed run is reported as interrupted without running RC twice. */
361
+ /** A started RC claim is permanent; a preflight with no runnable shards releases its claim for the next tick. */
235
362
  export async function runRehearsalTick(opts: RehearsalOptions = {}, deps: RehearsalDeps = {}): Promise<RehearsalTickResult> {
236
363
  if (opts.shards !== undefined && (!Number.isSafeInteger(opts.shards) || opts.shards < 1)) {
237
364
  throw new Error(`release rehearsal tick: invalid --shards count: ${opts.shards}`);
@@ -242,11 +369,13 @@ export async function runRehearsalTick(opts: RehearsalOptions = {}, deps: Rehear
242
369
  const root = opts.ledgerRoot ?? releaseLedgerRoot();
243
370
  const now = (deps.now ?? (() => new Date()))();
244
371
  const schedules = (deps.schedules ?? listSchedules)(root);
372
+ const intervalHours = deps.hardIntervalHours ?? releaseLoopConfig().rehearsalHardIntervalHours ?? 12;
373
+ const steps = rehearsalSteps(intervalHours);
245
374
  if (!Number.isFinite(now.getTime())) throw new Error('now must be a valid date');
246
- const candidate = planRehearsal(schedules, now, {});
375
+ const candidate = planRehearsal(schedules, now, {}, intervalHours);
247
376
  const stamps = candidate.status !== 'no-schedule'
248
377
  ? Object.fromEntries(steps.map(step => [step.id, existsSync(stampPath(root, candidate.version, step.id))])) as Partial<Record<StepId, boolean>> : {};
249
- const plan = planRehearsal(schedules, now, stamps);
378
+ const plan = planRehearsal(schedules, now, stamps, intervalHours);
250
379
  debug.log('release.rehearsal', 'tick', { ...plan, apply: !!opts.apply });
251
380
  if (!opts.apply) return plan;
252
381
  const written: RehearsalStamp[] = [];
@@ -278,6 +407,10 @@ export async function runRehearsalTick(opts: RehearsalOptions = {}, deps: Rehear
278
407
  const path = stampPath(root, plan.version, step);
279
408
  mkdirSync(dirname(path), { recursive: true });
280
409
  const stamp: RehearsalStamp = { version: plan.version, cutAt: plan.cutAt, step, outcome: 'running', startedAt: now.toISOString(), ownerPid: process.pid };
410
+ if (step === 'hard-mid' || step === 'hard-5h') {
411
+ stamp.hardGateRunId = `hard-${randomUUID()}`;
412
+ stamp.hardGateLog = join(dirname(path), `${stamp.hardGateRunId}.log`);
413
+ }
281
414
  // Crash-safe exclusive create: the complete JSON is written to a private temp file, then hard-linked into
282
415
  // place. link(2) fails with EEXIST like wx, but the stamp can never be observed empty or half-written.
283
416
  const temp = `${path}.${process.pid}.${randomUUID()}.claim.tmp`;
@@ -322,13 +455,47 @@ export async function runRehearsalTick(opts: RehearsalOptions = {}, deps: Rehear
322
455
  stamp.sha = gitResult(git, ['rev-parse', 'HEAD'], checkout);
323
456
  if (!stamp.sha) throw new Error('git rev-parse HEAD returned no sha');
324
457
  const leak = (deps.leakCheck ?? runRehearsalLeakCheck)(checkout);
325
- stamp.leakCheck = { outcome: leak.status === 0 ? 'ok' : 'fail', sha: stamp.sha, exitCode: leak.status };
326
- if (leak.status !== 0) throw new Error(`public export leak-check failed (rc=${leak.status ?? 'spawn'})`);
327
- const regressionFiles: string[] = [];
458
+ const statusIsValid = leak.status === null || (Number.isSafeInteger(leak.status) && leak.status >= 0 && leak.status <= 255);
459
+ const leakStatus = statusIsValid ? leak.status : null;
460
+ const leakDetail = leakStatus === 0 ? undefined : sanitizeRehearsalLeakDetail(leak.detail ?? '', checkout);
461
+ stamp.leakCheck = { outcome: leakStatus === 0 ? 'ok' : 'fail', sha: stamp.sha, exitCode: leakStatus,
462
+ ...(leakDetail ? { detail: leakDetail } : {}) };
463
+ if (leakStatus !== 0) throw new Error(`public export leak-check failed (rc=${leakStatus ?? 'spawn'})${leakDetail ? ` · ${leakDetail}` : ''}`);
464
+ if (plan.run === 'hard-5h' || plan.run === 'hard-mid') {
465
+ stamp.selection = { shards: 12, remote: 'node-b' };
466
+ const hardGateRunId = stamp.hardGateRunId;
467
+ const hardGateLog = stamp.hardGateLog;
468
+ if (!hardGateRunId || !hardGateLog) throw new Error('hard rehearsal claim has no evidence identity');
469
+ const hard = await (deps.hardGate ?? runHardGate)(plan.version, checkout, stamp.sha, root, hardGateRunId);
470
+ stamp.hardGate = hard;
471
+ if (!existsSync(hardGateLog)) writeFileSync(hardGateLog, `${JSON.stringify(hard)}\n`, { flag: 'wx', mode: 0o600 });
472
+ if (hard.outcome !== 'error' && (hard.commit !== stamp.sha || hard.executor !== 'pod' || !Array.isArray(hard.introduced)))
473
+ throw new Error('hard rehearsal result did not measure pinned SHA on a Pod');
474
+ if (hard.outcome === 'ok' && hard.introduced.length) throw new Error('hard rehearsal gate ok verdict contains introduced failures');
475
+ stamp.outcome = hard.outcome === 'regression' && hard.introduced.length === 0 ? 'unmeasured' : hard.outcome;
476
+ const cause = stamp.outcome === 'unmeasured' ? 'regression verdict has no introduced IDs'
477
+ : hard.outcome === 'error' ? hard.error?.trim() || 'gate returned error without a cause' : undefined;
478
+ if (cause) stamp.measurementGap = { cause, runId: hardGateRunId, evidence: hardGateLog };
479
+ const introducedCount: number | null = stamp.outcome === 'unmeasured' || stamp.outcome === 'error' ? null : hard.introduced.length;
480
+ const preexistingCount: number | null = introducedCount === null ? null : hard.preexisting;
481
+ const totalFailures: number | null = introducedCount === null || preexistingCount === null ? null : introducedCount + preexistingCount;
482
+ stamp.summary = oneLine(`hard gate ${hard.outcome} · introduced ${introducedCount ?? 'UNKNOWN'} · preexisting ${preexistingCount ?? 'UNKNOWN'} · total failures ${totalFailures ?? 'UNKNOWN'} · node-b Pod · 12 shards · runId ${hardGateRunId} · evidence ${hardGateLog}${cause ? ` · ${cause}` : ''}`);
483
+ } else {
328
484
  const shardPlan = opts.shards === undefined ? (deps.shardPlan ?? planRehearsalShards)(plan.version, root, checkout, { ...deps.shardPlanDeps, remoteGate: true }) : undefined;
329
485
  if (shardPlan) stamp.shardPlan = shardPlan;
330
486
  const selection = { shards: opts.shards ?? shardPlan?.shards, remote: opts.remote };
331
487
  stamp.selection = selection;
488
+ if (shardPlan && (shardPlan.testFiles === 0 || shardPlan.gatePlanShards === null)) {
489
+ stamp.outcome = 'unmeasured';
490
+ stamp.summary = oneLine(`${shardPlan.testFiles === 0 ? 'no runnable rehearsal shards' : 'rehearsal shard plan unavailable'} · ${shardPlan.unmeasured ?? 'selected test files empty'}`);
491
+ stamp.endedAt = clock().toISOString();
492
+ // No RC was launched: this claim is not a completed stage. Leave the ledger free for the next tick.
493
+ unlinkSync(path);
494
+ written.push(stamp);
495
+ debug.log('release.rehearsal', 'step-shortage-retry', { version: stamp.version, step: stamp.step, summary: stamp.summary });
496
+ return { ...plan, applied: true, stamps: written, notificationFailures };
497
+ }
498
+ const regressionFiles: string[] = [];
332
499
  const result = await (deps.lightRc ?? ((version, cwd) => runLightRc(version, { ledgerRoot: root, head: stamp.sha, ...selection, rehearsalTui: true, log: (line) => {
333
500
  for (const entry of line.split(/\r?\n/)) {
334
501
  const file = /^- introduced: (.+?)(?: > |$)/.exec(entry)?.[1];
@@ -359,12 +526,25 @@ export async function runRehearsalTick(opts: RehearsalOptions = {}, deps: Rehear
359
526
  : result.introduced === null || result.unclassified === null || result.unmeasured !== null || result.unclassified > 0 ? 'unmeasured'
360
527
  : result.unmeasured === null && (!result.ok || result.gateExitCode !== 0) ? 'error'
361
528
  : planningGap ? 'unmeasured' : 'ok';
362
- stamp.summary = oneLine(`introduced ${result.introduced} · preexisting ${result.preexisting ?? 'unmeasured'} · unclassified ${result.unclassified} · ${result.remote ?? 'local'} · gate rc ${result.gateExitCode}${!result.ok ? ' · RC 실패' : ''}${result.unmeasured !== null ? ` · unmeasured: ${result.unmeasured || 'RC reason empty'}` : ''}${stamp.shardPlan?.unmeasured ? ` · unmeasured: ${stamp.shardPlan.unmeasured}` : ''}${shardMismatch ? ` · unmeasured: ${shardMismatch}` : ''}${remoteMismatch ? ` · unmeasured: ${remoteMismatch}` : ''}`);
529
+ stamp.summary = oneLine(`introduced ${result.introduced ?? 'UNKNOWN'} · preexisting ${result.preexisting ?? 'UNKNOWN'} · unclassified ${result.unclassified ?? 'UNKNOWN'} · ${result.remote ?? 'local'} · gate rc ${result.gateExitCode}${!result.ok ? ' · RC 실패' : ''}${result.unmeasured !== null ? ` · unmeasured: ${result.unmeasured || 'RC reason empty'}` : ''}${stamp.shardPlan?.unmeasured ? ` · unmeasured: ${stamp.shardPlan.unmeasured}` : ''}${shardMismatch ? ` · unmeasured: ${shardMismatch}` : ''}${remoteMismatch ? ` · unmeasured: ${remoteMismatch}` : ''}`);
530
+ }
363
531
  }
364
532
  }
365
533
  } catch (error) {
366
534
  stamp.outcome = 'error';
367
- stamp.summary = oneLine(`${String(error instanceof Error ? error.message : error).split(/\r?\n/, 1)[0] ?? 'unknown error'}${stamp.shardPlan?.unmeasured ? ` · unmeasured: ${stamp.shardPlan.unmeasured}` : ''}`);
535
+ const cause = String(error instanceof Error ? error.message : error).split(/\r?\n/, 1)[0] ?? 'unknown error';
536
+ if (stamp.hardGateRunId && stamp.hardGateLog) {
537
+ // The runner opens stderr before launch, so a failed launch or missing JSON may leave an empty file.
538
+ appendFileSync(stamp.hardGateLog, `${cause}\n`, { mode: 0o600 });
539
+ stamp.measurementGap = { cause, runId: stamp.hardGateRunId, evidence: stamp.hardGateLog };
540
+ }
541
+ stamp.summary = oneLine(`${cause}${stamp.hardGateRunId ? ` · runId ${stamp.hardGateRunId} · evidence ${stamp.hardGateLog}` : ''}${stamp.shardPlan?.unmeasured ? ` · unmeasured: ${stamp.shardPlan.unmeasured}` : ''}`);
542
+ }
543
+ if (stamp.hardGateRunId && stamp.hardGateLog && !stamp.measurementGap
544
+ && (stamp.outcome === 'no-checkout' || stamp.outcome === 'checkout-dirty')) {
545
+ const cause = stamp.outcome === 'no-checkout' ? 'hard gate checkout unavailable' : 'hard gate checkout dirty';
546
+ appendFileSync(stamp.hardGateLog, `${cause}\n`, { mode: 0o600 });
547
+ stamp.measurementGap = { cause, runId: stamp.hardGateRunId, evidence: stamp.hardGateLog };
368
548
  }
369
549
  await finish(path, stamp);
370
550
  }
@@ -66,8 +66,7 @@ export interface Rubric {
66
66
 
67
67
  const AXES = ['A', 'E', 'R', 'D', 'M', 'B', 'S', 'X'] as const;
68
68
 
69
- /** Read one explicit rubric line; an old score in parentheses is not an axis. */
70
- export function parseRubric(text: string): Rubric | null {
69
+ function* rubricLines(text: string): Generator<Partial<Rubric>> {
71
70
  for (const line of text.split(/\r?\n/)) {
72
71
  const match = /(?:^|\s)루브릭:\s*([^\r\n]*)/.exec(line);
73
72
  if (!match) continue;
@@ -77,11 +76,26 @@ export function parseRubric(text: string): Rubric | null {
77
76
  const axis = /^([AERDMBSX])([0-3])$/.exec(token);
78
77
  if (axis) values[axis[1] as keyof Rubric] = Number(axis[2]);
79
78
  }
79
+ yield values;
80
+ }
81
+ }
82
+
83
+ /** Read one explicit rubric line; an old score in parentheses is not an axis. */
84
+ export function parseRubric(text: string): Rubric | null {
85
+ for (const values of rubricLines(text)) {
80
86
  if (AXES.every((axis) => values[axis] !== undefined)) return values as Rubric;
81
87
  }
82
88
  return null;
83
89
  }
84
90
 
91
+ /** Read an explicitly entered S axis even when the other rubric axes are incomplete. */
92
+ export function parseRubricS(text: string): number | null {
93
+ for (const values of rubricLines(text)) {
94
+ if (values.S !== undefined) return values.S;
95
+ }
96
+ return null;
97
+ }
98
+
85
99
  export function rubricScore(r: Rubric): number {
86
100
  return rubricScoreWith(INTERNAL_AXES, r);
87
101
  }
@@ -1,6 +1,7 @@
1
1
  import { CLAIM_IDLE_HOURS, PR_LABELS, STALLED_DRAFT_HOURS } from '../github/pr-labels.js';
2
2
  import { debug } from '../debug/log.js';
3
- import { decideDraft, draftClaimComment, draftClaimState, draftReleaseComment, laterMergedTwins, sameGoalPr, type DraftTriagePr } from './draft-triage-rules.js';
3
+ import { decideDraft, draftClaimComment, draftClaimState, draftReleaseComment, laterMergedTwins, sameGoalPr, PROTECTED_LABELS, type DraftTriagePr } from './draft-triage-rules.js';
4
+ import { cellIdFromBody } from '../pr-tool/census.js';
4
5
  import { cardPrNumber, draftTaskOwner, type TaskCard } from '../task-agent/task-hand.js';
5
6
  import type { PrTerminalRecord } from './draft-residue.js';
6
7
  import { branchLineageSlug } from '../cli/pr-lineage.js';
@@ -47,6 +48,8 @@ export interface DraftSweepAdapters {
47
48
  /** Host ledger terminal records; undefined means the ledger could not be read. */
48
49
  listPrTerminals?(): Promise<readonly PrTerminalRecord[] | undefined>;
49
50
  commentDraft?(repository: string, number: number, body: string): Promise<void>;
51
+ /** Complete issue-comment inventory for idempotent merge-time same-cell cleanup. */
52
+ listIssueComments?(repository: string, number: number): Promise<readonly string[]>;
50
53
  removeLabel?(repository: string, number: number, label: string): Promise<void>;
51
54
  /** Whether the current owned run has a self-implement.result final observation, even if its worktree remains. */
52
55
  hasFinalRunResult?(draft: SweepDraft, repository: string): Promise<boolean | undefined>;
@@ -587,12 +590,14 @@ export function resolveDraftSweepCloseCap(input: { flag?: unknown; config?: unkn
587
590
  return { closeCap: DRAFT_SWEEP_CLOSE_CAP, closeCapSource: 'default', warnings };
588
591
  }
589
592
 
590
- /** Post-merge shortcut: only the existing superseded-by decision can authorize a close. */
593
+ /** Post-merge cleanup: an explicit same-cell successor or the existing verified-goal decision can authorize a close. */
591
594
  export async function supersedeDraftsOnMerge(input: {
592
595
  repository: string;
593
596
  merged: SweepMergedPr & { createdAt: string; mergedAt: string };
597
+ /** `pr land` and HQ train invoke only the explicit same-cell successor path. */
598
+ onlyExplicitSameCell?: boolean;
594
599
  adapters: Pick<DraftSweepAdapters, 'listDrafts' | 'listLiveBranches' | 'getRunStatus' | 'setLabels' | 'closeDraft'>
595
- & Pick<Partial<DraftSweepAdapters>, 'getLatestFileChanges' | 'getPrFiles'>;
600
+ & Pick<Partial<DraftSweepAdapters>, 'getLatestFileChanges' | 'getPrFiles' | 'commentDraft' | 'listIssueComments'>;
596
601
  }): Promise<{ closed: number[]; kept: number[] }> {
597
602
  const { repository, merged, adapters } = input;
598
603
  const closed: number[] = [];
@@ -611,6 +616,43 @@ export async function supersedeDraftsOnMerge(input: {
611
616
  || !Number.isFinite(Date.parse(merged.createdAt)) || !Number.isFinite(Date.parse(merged.mergedAt))
612
617
  || drafts.some((pr) => !Number.isInteger(pr.number) || !pr.branch || !Array.isArray(pr.labels)
613
618
  || !Number.isFinite(Date.parse(pr.createdAt)))) throw new Error('Incomplete merge draft inventory');
619
+ // The conflicting-PR path writes this exact marker. A marker by itself is not authority:
620
+ // both PR bodies must identify the same cell, and the old PR must still be an open draft.
621
+ const markers = [...(merged.body ?? '').matchAll(/^Supersedes:\s*#(\d+)\s*$/gm)];
622
+ const markedNumber = markers.length === 1 ? Number(markers[0]![1]) : null;
623
+ const explicitOld = Number.isSafeInteger(markedNumber) && markedNumber! > 0 ? markedNumber : null;
624
+ const mergedCell = cellIdFromBody(merged.body ?? '');
625
+ if (explicitOld && explicitOld !== merged.number && mergedCell) {
626
+ const old = drafts.find((draft) => draft.number === explicitOld);
627
+ if (old && cellIdFromBody(old.body ?? '') === mergedCell
628
+ && Date.parse(old.createdAt) < Date.parse(merged.mergedAt)
629
+ && !old.labels.some((label) => PROTECTED_LABELS.has(label))
630
+ && PR_LABELS.filter((label) => label.axis === 'state' && old.labels.includes(label.name)).length <= 1) {
631
+ const marker = `<!-- elanous:same-cell-superseded #${old.number} -> #${merged.number} -->`;
632
+ const comment = `${marker}\nSame-cell draft superseded by merged PR #${merged.number} (https://github.com/${repository}/pull/${merged.number}). Branch preserved.`;
633
+ try {
634
+ if (!adapters.listIssueComments || !adapters.commentDraft) throw new Error('same-cell comment inventory unavailable');
635
+ const comments = await adapters.listIssueComments(repository, old.number);
636
+ if (!Array.isArray(comments)) throw new Error('same-cell comment inventory incomplete');
637
+ const remove = stateLabels.filter((label) => old.labels.includes(label.name) && label.name !== supersededLabel).map((label) => label.name);
638
+ if (!old.labels.includes(supersededLabel)) await adapters.setLabels(repository, old.number, { add: supersededLabel, remove });
639
+ if (!comments.some((body) => body.includes(marker))) await adapters.commentDraft(repository, old.number, comment);
640
+ await adapters.closeDraft(repository, old.number);
641
+ closed.push(old.number);
642
+ closeAttempts += 1;
643
+ } catch (failure) {
644
+ failed.push(old.number);
645
+ error = String(failure);
646
+ debug.log('drafts.cleanup', 'same-cell-supersede-failed', { merged: merged.number, old: old.number, error });
647
+ }
648
+ }
649
+ }
650
+ if (input.onlyExplicitSameCell) {
651
+ kept.push(...drafts.map((draft) => draft.number).filter((number) => !closed.includes(number)));
652
+ debug.log('drafts.cleanup', 'superseded-on-merge', { merged: merged.number, closed, kept,
653
+ ...(failed.length ? { failed } : {}), ...(error ? { error } : {}) });
654
+ return { closed, kept };
655
+ }
614
656
  const statuses = new Map<number, string | undefined>();
615
657
  const latestChanges = new Map<number, Readonly<Record<string, string>> | undefined>();
616
658
  const mergedFiles = await adapters.getPrFiles?.(repository, merged.number);
@@ -625,7 +667,14 @@ export async function supersedeDraftsOnMerge(input: {
625
667
  }
626
668
  }
627
669
  for (const listedDraft of drafts) {
670
+ if (closed.includes(listedDraft.number)) continue;
628
671
  const draft = { ...listedDraft, latestFileChanges: latestChanges.get(listedDraft.number) };
672
+ // The same-cell route is never inferred from a title, goal, or file overlap.
673
+ // A failed explicit cleanup also stays open for a later retry instead of falling through to generic triage.
674
+ if (draft.number === explicitOld || (mergedCell && cellIdFromBody(draft.body ?? '') === mergedCell)) {
675
+ kept.push(draft.number);
676
+ continue;
677
+ }
629
678
  if (draft.number === merged.number || !draft.branch.startsWith('self-impl/') || liveBranches.has(draft.branch)
630
679
  || Date.parse(draft.createdAt) >= Date.parse(merged.mergedAt)) {
631
680
  kept.push(draft.number);
@@ -1,5 +1,7 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { debug } from '../debug/log.js';
3
+ import type { FrontNodeId } from './graph-front-nodes.js';
4
+ import type { PipelineNodeId } from '../self-implement/pipeline-shape.js';
3
5
  import { GRAPH_SPECS, GRAPH_TEMPLATES, GRAPH_TEMPLATES_SOURCE, pipelineNodeEntryPayload, templateForGoalType, type GraphTemplate } from '../self-implement/graph-templates.js';
4
6
  import type { GoalType } from '../self-implement/goal-author.js';
5
7
 
@@ -42,6 +44,8 @@ export const JOURNEY_NODE_IDS = [
42
44
  'stopped',
43
45
  ] as const;
44
46
  export type JourneyNodeId = typeof JOURNEY_NODE_IDS[number];
47
+ /** Existing author/front and self-implement pipeline nodes may use the same observation helpers. */
48
+ export type JourneyObservationNodeId = JourneyNodeId | FrontNodeId | PipelineNodeId;
45
49
 
46
50
  export const JOURNEY_KEY_ENV = 'ELANOUS_JOURNEY_KEY';
47
51
  const QUEUE_LAUNCH_ENV = 'ELANOUS_HARNESS_QUEUE_LAUNCH';
@@ -81,7 +85,7 @@ export interface JourneyObservation {
81
85
  readonly data?: Readonly<Record<string, unknown>>;
82
86
  }
83
87
 
84
- function emit(entry: boolean, node: JourneyNodeId, o: JourneyObservation): void {
88
+ function emit(entry: boolean, node: JourneyObservationNodeId, o: JourneyObservation): void {
85
89
  try {
86
90
  const template = journeyTemplate(node, o.goalType);
87
91
  const runId = o.runId ?? process.env[RUN_ID_ENV]?.trim();
@@ -104,14 +108,14 @@ function emit(entry: boolean, node: JourneyNodeId, o: JourneyObservation): void
104
108
  }
105
109
 
106
110
  /** 노드 진입. */
107
- export function enterJourneyNode(node: JourneyNodeId, o: JourneyObservation): void {
111
+ export function enterJourneyNode(node: JourneyObservationNodeId, o: JourneyObservation): void {
108
112
  emit(true, node, o);
109
113
  }
110
114
 
111
115
  /** 노드 출구 — `outcome` 이 그 노드에서 나간 간선의 라벨(YAML `map` 키)이다.
112
116
  * ⭐ 그 라벨이 선언에서 종결 노드 `stopped` 로 가면 `stopped` 진입도 남긴다 — 거절·포기 런이 «선언된 종결점»에서 끝난다.
113
117
  * `outcome: 'error'` = 노드 안 작업이 예외를 던졌다(예외는 호출자에게 그대로 간다). */
114
- export function exitJourneyNode(node: JourneyNodeId, o: JourneyObservation & { readonly outcome: string }): void {
118
+ export function exitJourneyNode(node: JourneyObservationNodeId, o: JourneyObservation & { readonly outcome: string }): void {
115
119
  emit(false, node, o);
116
120
  if (node !== 'stopped' && journeyEdgeTarget(node, o.outcome) === 'stopped') {
117
121
  const { outcome: _outcome, ...rest } = o;
@@ -130,7 +134,7 @@ export function journeyEdgeTarget(from: string, label: string): string | undefin
130
134
  }
131
135
 
132
136
  /** 노드 안 작업을 감싼다 — 예외면 출구 `error` 를 남기고 다시 던진다(진입 뒤 출구가 빠지지 않게). */
133
- export function withJourneyNode<T>(node: JourneyNodeId, o: JourneyObservation, work: () => Promise<T>): Promise<T> {
137
+ export function withJourneyNode<T>(node: JourneyObservationNodeId, o: JourneyObservation, work: () => Promise<T>): Promise<T> {
134
138
  const onError = (error: unknown): void => {
135
139
  exitJourneyNode(node, { ...o, outcome: 'error', data: { ...o.data, error: error instanceof Error ? error.message : String(error) } });
136
140
  };
@@ -144,7 +148,7 @@ export function withJourneyNode<T>(node: JourneyNodeId, o: JourneyObservation, w
144
148
  }
145
149
 
146
150
  /** 동기 판. */
147
- export function withJourneyNodeSync<T>(node: JourneyNodeId, o: JourneyObservation, work: () => T): T {
151
+ export function withJourneyNodeSync<T>(node: JourneyObservationNodeId, o: JourneyObservation, work: () => T): T {
148
152
  try { return work(); }
149
153
  catch (error) {
150
154
  exitJourneyNode(node, { ...o, outcome: 'error', data: { ...o.data, error: error instanceof Error ? error.message : String(error) } });
@@ -153,7 +157,7 @@ export function withJourneyNodeSync<T>(node: JourneyNodeId, o: JourneyObservatio
153
157
  }
154
158
 
155
159
  /** 진입·출구를 한 번에 — 판정만 하는 노드(대기 없는 관문)용. */
156
- export function passJourneyNode(node: JourneyNodeId, o: JourneyObservation & { readonly outcome: string }): void {
160
+ export function passJourneyNode(node: JourneyObservationNodeId, o: JourneyObservation & { readonly outcome: string }): void {
157
161
  enterJourneyNode(node, o);
158
162
  exitJourneyNode(node, o);
159
163
  }