elanous 0.2.32 → 0.2.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (753) 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 → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 0368f25d-ad84af92fefee68f.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 1530.0e612369b6fd7ea0.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +41 -0
  9. package/apps/pwa/out/_next/static/chunks/{7391.ebae168025c91b6a.js → 1674.2a65fd5668e1cc5f.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +24 -0
  11. package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +74 -0
  12. package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{7947-d0759430f8042240.js → 1993-c0007b7ad0c0ef41.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{60fb96c9.360b01d8d4927b7b.js → 1c735de4.f993a30bbd3c57c4.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 2018.a741297bce759490.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +148 -0
  23. package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{3902.e1e71aaac850a045.js → 2625.5d870aa999f33db1.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +77 -0
  26. package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +62 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +90 -0
  31. package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 3408.21d1570602f4b6c0.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3589.5444a06bcf6e775c.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/359-2250789a2d3499e7.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 3677-4215f826f6aa68e5.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +79 -0
  40. package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +122 -0
  42. package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/{7371.80c05c653b08e907.js → 4346.8601952e73bf5803.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/4441-875b97f5821ed58a.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +286 -0
  46. package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +24 -0
  49. package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 4705-194e64e47ca0fbdb.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 4718-17d2af636796a330.js} +3 -3
  51. package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 5101.e32282718f99ed6f.js} +2 -2
  57. package/apps/pwa/out/_next/static/chunks/{2001.6c7e0fd02190886c.js → 5154.a118f3957ed14e36.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +23 -0
  61. package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 5483-dd5d7697f6bdb106.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +94 -0
  63. package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{3267c0e6.d34854e7b3984a6e.js → 56d372f2.681ab4ec4c998fae.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +287 -0
  67. package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 6236.e18cced2d5ba6afb.js} +17 -17
  74. package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +8 -0
  75. package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +27 -0
  78. package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +93 -0
  80. package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/{6544cb48.a87fe20ddf137be2.js → 6b89c8bd.24df687a820500b3.js} +1 -1
  83. package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +149 -0
  87. package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +104 -0
  88. package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7385.50a308a477bdfc21.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 7644.17e37ba6f1d4226e.js} +4 -4
  90. package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/{8018.a32663f04a6fc5f9.js → 8219.baa715d1deee80e2.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/{4111.2bfedbb233ad206b.js → 8256.e3ac8421a71f82f4.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 8444.4c26b379ca2b9596.js} +17 -17
  100. package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +226 -0
  101. package/apps/pwa/out/_next/static/chunks/8557-e7898769499cd56f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +64 -0
  104. package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 8637.47f5b35afcae5e6b.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9214.63a510d39178e997.js} +2 -2
  111. package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +115 -0
  112. package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 938.66ad1ef0e5abae1c.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 9512.5a76207a730e0491.js} +2 -2
  115. package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{69-0a2c8209c6d4a158.js → 967-2aa39b2d04b4c690.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 9952.5daf5f94063a2b3e.js} +1 -1
  120. package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/{page-a27b1e5a0d1b308f.js → page-406b47745b53f269.js} +1 -1
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/{page-32866485913d6a04.js → page-47c5d4db587266bd.js} +1 -1
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/{page-04d00ae9b0890349.js → page-dc0a532f5b9196ec.js} +1 -1
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → b2f6ba4d.fb56fdbbf798df33.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/b6705a4f-b9a9047de9eecfd0.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → cbe38a15.5a032598e39970c6.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → da5176c6.6773b6c5994e1d99.js} +7 -7
  178. package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +1 -0
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/bin/elanous.mjs +10 -2
  278. package/catalog/providers/opengateway.yaml +25 -0
  279. package/docs/goal-context/01-goal-authoring-checks.md +8 -0
  280. package/docs/goal-context/03-verification-menu.md +24 -0
  281. package/docs/goal-context/04-mock-scenarios.md +100 -0
  282. package/docs/goal-context/README.md +5 -0
  283. package/graphs/catalog/catalog.yaml +1 -1
  284. package/graphs/default-loop.yaml +76 -5
  285. package/graphs/document-loop.yaml +71 -4
  286. package/graphs/implement-loop.yaml +59 -4
  287. package/graphs/journey/SCENARIOS.md +33 -0
  288. package/graphs/journey/recipes.yaml +1 -0
  289. package/graphs/journey/ta-journey.yaml +94 -0
  290. package/graphs/journey/units/author/author.yaml +20 -0
  291. package/graphs/journey/units/author/recipes.yaml +2 -0
  292. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  293. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  294. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  295. package/graphs/journey/units/green/green.yaml +20 -0
  296. package/graphs/journey/units/green/recipes.yaml +2 -0
  297. package/graphs/journey/units/pr/pr.yaml +20 -0
  298. package/graphs/journey/units/pr/recipes.yaml +2 -0
  299. package/graphs/journey/units/remember/recipes.yaml +2 -0
  300. package/graphs/journey/units/remember/remember.yaml +20 -0
  301. package/graphs/operate-loop.yaml +71 -4
  302. package/graphs/overlays/stop-heal-ladder.yaml +1 -1
  303. package/graphs/release-rehearsal/recipes.yaml +1 -1
  304. package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
  305. package/graphs/research-loop.yaml +159 -4
  306. package/graphs/test-diet/test-diet.yaml +3 -0
  307. package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
  308. package/graphs/units/dispatch-pod/recipes.yaml +14 -0
  309. package/graphs/units/entry/entry.yaml +50 -0
  310. package/graphs/units/entry/recipes.yaml +14 -0
  311. package/graphs/units/harvest/harvest.yaml +25 -0
  312. package/graphs/units/harvest/recipes.yaml +4 -0
  313. package/graphs/units/land/land.yaml +45 -0
  314. package/graphs/units/land/recipes.yaml +3 -0
  315. package/graphs/units/recipes.yaml +7 -0
  316. package/graphs/units/recover.yaml +39 -0
  317. package/graphs/units/reflect/recipes.yaml +3 -0
  318. package/graphs/units/reflect/reflect.yaml +15 -0
  319. package/graphs/units/task-agent-recover-review.yaml +17 -0
  320. package/graphs/units/task-agent-recover-wait.yaml +17 -0
  321. package/graphs/units/verbs/make-doc.yaml +34 -0
  322. package/graphs/units/verbs/recipes.yaml +33 -0
  323. package/graphs/units/verbs/verify.yaml +55 -0
  324. package/graphs/work/recipes.yaml +2 -0
  325. package/graphs/work/research-report.yaml +28 -0
  326. package/package.json +1 -1
  327. package/scripts/ci-typecheck-changed.ts +69 -16
  328. package/scripts/coord-role-pack.ts +19 -6
  329. package/scripts/docs/generate-graph-anatomy.ts +19 -2
  330. package/scripts/graph-harvest-unit.ts +22 -0
  331. package/scripts/graph-units/journey-stub.ts +6 -0
  332. package/scripts/graph-units/land-enqueue.ts +78 -0
  333. package/scripts/graph-units/recover-plan.ts +15 -0
  334. package/scripts/graph-units/reflect-node.ts +88 -0
  335. package/scripts/graph-units/ta-journey-observe.ts +109 -0
  336. package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
  337. package/scripts/graph-units/verbs/verify-stage.ts +75 -0
  338. package/scripts/graph-units/verbs-envelope.ts +139 -0
  339. package/scripts/hq/standby-snapshot.ts +30 -0
  340. package/scripts/public-export.ts +43 -1
  341. package/scripts/ratchets/train-side-invariants.sh +45 -0
  342. package/scripts/release-loop/auto-approve-node.ts +30 -16
  343. package/scripts/release-loop/docs-land-node.ts +21 -5
  344. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  345. package/scripts/release-loop/gate-closure.ts +5 -1
  346. package/scripts/release-loop/gate-diff.ts +1 -1
  347. package/scripts/release-loop/gate-node.ts +675 -49
  348. package/scripts/release-loop/gate-partial.ts +68 -14
  349. package/scripts/release-loop/gate-radius-live.ts +177 -0
  350. package/scripts/release-loop/gate-radius-shadow.ts +138 -0
  351. package/scripts/release-loop/gate-traffic-mode.ts +128 -0
  352. package/scripts/release-loop/gate-triage-node.ts +5 -2
  353. package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
  354. package/scripts/release-loop/known-issues-node.ts +77 -8
  355. package/scripts/release-loop/node-verdict.ts +12 -1
  356. package/scripts/release-loop/npm-publish-node.ts +66 -12
  357. package/scripts/release-loop/preflight.ts +93 -7
  358. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  359. package/scripts/release-loop/publish-node.ts +60 -9
  360. package/scripts/release-loop/pwa-remote.ts +166 -0
  361. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  362. package/scripts/release-loop/resume-cap.ts +56 -0
  363. package/scripts/release-loop/resume-release.ts +155 -19
  364. package/scripts/release-loop/resume.ts +24 -1
  365. package/scripts/release-loop/tui-sim-node.ts +8 -2
  366. package/scripts/release-loop/unattended-release.ts +10 -2
  367. package/scripts/test-diet/lib.ts +6 -1
  368. package/scripts/test-diet/node.ts +194 -13
  369. package/scripts/ux-sim.ts +39 -0
  370. package/src/acp/core-turn-bridge.ts +20 -5
  371. package/src/acp/reasoning-thought-buffer.ts +45 -0
  372. package/src/agent/self-ambient-cache.ts +8 -0
  373. package/src/agent-substrate/acp-reviewer.ts +90 -15
  374. package/src/agent-substrate/pr-reviewer.ts +17 -0
  375. package/src/agent-substrate/review-finding-key.ts +53 -0
  376. package/src/agent-substrate/self-review-cli.ts +188 -18
  377. package/src/ask-user-question/pending-questions.ts +1 -1
  378. package/src/autopilot/pr-manager.ts +393 -65
  379. package/src/budget/run-usage-rollup.ts +1 -0
  380. package/src/chat/index.ts +0 -2
  381. package/src/chat/pickers/modal-runtime.ts +10 -27
  382. package/src/chat/tool-render/dispatch.ts +62 -10
  383. package/src/cli/agent-cli.ts +13 -2
  384. package/src/cli/control-cli.ts +24 -7
  385. package/src/cli/doctor-cli.ts +4 -1
  386. package/src/cli/guardian-cli.ts +10 -0
  387. package/src/cli/light-entry-route.ts +75 -0
  388. package/src/cli/llm-detect-cli.ts +23 -1
  389. package/src/cli/pod-cli.ts +77 -3
  390. package/src/cli/pr-cli.ts +81 -14
  391. package/src/cli/pr-land-base-read.ts +2 -0
  392. package/src/cli/pr-land-overlap-evidence.ts +154 -16
  393. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  394. package/src/cli/pr-land-recovery.ts +64 -0
  395. package/src/cli/pty-takeover-cli.ts +6 -5
  396. package/src/cli/release-checklist-read-cli.ts +79 -0
  397. package/src/cli/release-cli.ts +189 -132
  398. package/src/cli/release-run-if-ready.ts +29 -28
  399. package/src/cli/release-single-flight.ts +178 -0
  400. package/src/cli/remote-resolve.ts +1 -1
  401. package/src/cli/root-tui-entry.ts +48 -0
  402. package/src/cli/seat-cli.ts +37 -0
  403. package/src/cli/setup-cli.ts +40 -1
  404. package/src/cli/sim-cli.ts +22 -0
  405. package/src/cli/tasks-cli.ts +667 -14
  406. package/src/cli/usage-cli.ts +13 -11
  407. package/src/clipboard/history.ts +179 -13
  408. package/src/config.ts +8 -1
  409. package/src/control/control-status.ts +8 -3
  410. package/src/control-plane/ledger.ts +5 -3
  411. package/src/control-plane/server.ts +5 -3
  412. package/src/core-turn/short-question.ts +5 -1
  413. package/src/dashboard/chat/acp-chat.ts +8 -0
  414. package/src/dashboard/index.ts +114 -77
  415. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
  416. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  417. package/src/dashboard/input/seat-autowake.ts +56 -3
  418. package/src/dashboard/render/theme-resolver.ts +33 -4
  419. package/src/dashboard/seat-boot-preamble.ts +1 -1
  420. package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
  421. package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
  422. package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
  423. package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
  424. package/src/dashboard/turn-preamble.ts +47 -1
  425. package/src/dashboard/turn-stream-formatter.ts +34 -1
  426. package/src/dashboard/turn-stream-runtime.ts +2 -0
  427. package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
  428. package/src/domains/guardian-tick.ts +54 -2
  429. package/src/domains/outbound-alert.ts +3 -2
  430. package/src/domains/schedule-registry.ts +16 -2
  431. package/src/extractors.ts +3 -1
  432. package/src/git-fs/idle-refresh.ts +76 -0
  433. package/src/git-fs/index.ts +18 -7
  434. package/src/git-fs/retry.ts +4 -0
  435. package/src/git-fs/runner.ts +2 -0
  436. package/src/git-fs/worktree.ts +42 -4
  437. package/src/graph-kinds/registry.ts +2 -2
  438. package/src/graph-runner/runner.ts +267 -54
  439. package/src/grok/credential.ts +15 -3
  440. package/src/harness/harness-cli-command.ts +151 -38
  441. package/src/harness/harness-incidents.ts +37 -0
  442. package/src/harness/harness-pod-dispatch.ts +38 -1
  443. package/src/harness/harness-salvage-cli.ts +14 -2
  444. package/src/harness/launch-utterance-ledger.ts +208 -0
  445. package/src/impl-discipline/detector.ts +16 -4
  446. package/src/impl-discipline/system-prompt.ts +11 -0
  447. package/src/impl-discipline/types.ts +2 -2
  448. package/src/index.ts +683 -146
  449. package/src/intake-plane/already-built-hint.ts +91 -0
  450. package/src/intake-plane/requirement-funnel.ts +29 -1
  451. package/src/knowhow/pack.ts +199 -0
  452. package/src/light-cli.ts +111 -0
  453. package/src/llm/opengateway-models.ts +11 -0
  454. package/src/llm/provider-credentials.ts +14 -0
  455. package/src/llm/provider-detect.ts +8 -1
  456. package/src/llm/runtime-model-family.ts +2 -1
  457. package/src/llm.ts +268 -65
  458. package/src/loops/budget.ts +95 -0
  459. package/src/loops/msg-wake.ts +8 -2
  460. package/src/loops/orchestrator/traffic.ts +132 -1
  461. package/src/model-tier/llm-tier-map.ts +15 -1
  462. package/src/mss/logging/log-store.ts +4 -5
  463. package/src/native-tool-catalog.ts +15 -1
  464. package/src/nexus/api/graphs-api.ts +22 -3
  465. package/src/nexus/api/http-server.ts +1 -1
  466. package/src/nexus/api/loop-resources.ts +13 -1
  467. package/src/nexus/api/ops-api.ts +12 -0
  468. package/src/oauth/claude-pty-maturity.ts +66 -0
  469. package/src/oauth/codex-access-mirror.ts +55 -0
  470. package/src/oauth/codex.ts +7 -0
  471. package/src/oauth/fallback-chain.ts +1 -1
  472. package/src/onboarding/first-run.ts +5 -3
  473. package/src/onboarding/non-interactive.ts +64 -13
  474. package/src/onboarding.ts +10 -2
  475. package/src/ops/overview-collect.ts +54 -4
  476. package/src/ops/overview.ts +31 -7
  477. package/src/pr-tool/census.ts +282 -30
  478. package/src/pr-tool/inflight-registry.ts +160 -7
  479. package/src/prompt-library/gpt6-family-addendum.ts +14 -1
  480. package/src/pty-shell/herdr-agent-report.ts +442 -0
  481. package/src/pty-shell/pty-control-ipc.ts +5 -5
  482. package/src/pty-shell/pty-manifest.ts +7 -0
  483. package/src/pty-shell/pty-write-outcome.ts +24 -6
  484. package/src/pty-shell/tui-run-state.ts +117 -3
  485. package/src/release-loop/checklist.ts +103 -5
  486. package/src/release-loop/feature-store.ts +19 -2
  487. package/src/release-loop/landed-but-yellow.ts +129 -5
  488. package/src/release-loop/light-rc.ts +1 -0
  489. package/src/release-loop/placement.ts +10 -3
  490. package/src/release-loop/rehearsal.ts +205 -25
  491. package/src/release-loop/rubric.ts +16 -2
  492. package/src/repl/index.ts +174 -17
  493. package/src/repl/ops-msg-bridge.ts +32 -0
  494. package/src/self-dev/ask-launch-flow.ts +44 -5
  495. package/src/self-dev/cli-help-text.ts +17 -0
  496. package/src/self-dev/dev-cli.ts +11 -9
  497. package/src/self-dev/draft-residue.ts +37 -1
  498. package/src/self-dev/draft-sweep.ts +188 -13
  499. package/src/self-dev/draft-triage-rules.ts +107 -0
  500. package/src/self-dev/fleet-reduce.ts +3 -2
  501. package/src/self-dev/graph-front-nodes.ts +112 -0
  502. package/src/self-dev/graph-journey-nodes.ts +11 -6
  503. package/src/self-dev/graph-journey-route.ts +60 -6
  504. package/src/self-dev/harness-run-cli.ts +3 -15
  505. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  506. package/src/self-dev/orchestrate.ts +79 -3
  507. package/src/self-dev/review-provider-fallback.ts +35 -1
  508. package/src/self-dev/run-supervisor.ts +107 -12
  509. package/src/self-dev/run-types.ts +5 -1
  510. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  511. package/src/self-dev/shard-aggregate.ts +42 -5
  512. package/src/self-dev/shard-run.ts +8 -1
  513. package/src/self-implement/blocked-draft-policy.ts +20 -0
  514. package/src/self-implement/classify-shadow.ts +3 -7
  515. package/src/self-implement/doctor-visit.ts +18 -1
  516. package/src/self-implement/gate-baseline.ts +95 -12
  517. package/src/self-implement/gate-cli.ts +1 -0
  518. package/src/self-implement/gate-remote.ts +40 -25
  519. package/src/self-implement/goal-author-decompose.ts +275 -47
  520. package/src/self-implement/goal-author-identity.ts +66 -0
  521. package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
  522. package/src/self-implement/goal-author.ts +254 -120
  523. package/src/self-implement/goal-elaborate.ts +295 -0
  524. package/src/self-implement/goal-refine.ts +270 -0
  525. package/src/self-implement/graph-overlay-yaml.ts +28 -2
  526. package/src/self-implement/graph-unit-flatten.ts +103 -0
  527. package/src/self-implement/graph-unit-resolver.ts +107 -0
  528. package/src/self-implement/graph-yaml.ts +151 -1
  529. package/src/self-implement/headless-elanous-driver.ts +1 -0
  530. package/src/self-implement/knowhow-pack.ts +103 -0
  531. package/src/self-implement/orchestrator.ts +160 -45
  532. package/src/self-implement/pod-warm-pool-profile.ts +45 -0
  533. package/src/self-implement/review-mustfix-class.ts +203 -0
  534. package/src/self-implement/rework-budget-judgment.ts +5 -8
  535. package/src/self-implement/run-stop.ts +17 -2
  536. package/src/self-implement/running-runs.ts +29 -1
  537. package/src/self-implement/scope-adjacency.ts +113 -0
  538. package/src/self-implement/seams.ts +138 -4
  539. package/src/self-implement/stop-autoheal.ts +112 -2
  540. package/src/session/chat.ts +27 -0
  541. package/src/session-runtime/index.ts +1 -1
  542. package/src/session-runtime/retry-policy.ts +2 -1
  543. package/src/setup/llm-env-detect.ts +5 -0
  544. package/src/skills/tools/agent.ts +140 -14
  545. package/src/skills/tools/msg-ask.ts +100 -0
  546. package/src/skills/tools/ops-ledger.ts +2 -1
  547. package/src/skills/tools/schedule-wakeup.ts +66 -17
  548. package/src/steward/hold-hygiene.ts +24 -6
  549. package/src/steward/release-day.ts +7 -3
  550. package/src/steward/triage-budget.ts +194 -0
  551. package/src/steward/triage.ts +57 -7
  552. package/src/task-agent/actions.ts +69 -1
  553. package/src/task-agent/green-sweep.ts +4 -0
  554. package/src/task-agent/harvest-unit.ts +141 -0
  555. package/src/task-agent/live-moves.ts +257 -15
  556. package/src/task-agent/parent-host.ts +216 -6
  557. package/src/task-agent/postland-card.ts +80 -1
  558. package/src/task-agent/rejudge-on-head.ts +112 -26
  559. package/src/task-agent/repair-branch-cas.ts +4 -1
  560. package/src/task-agent/repair-cycle.ts +16 -3
  561. package/src/task-agent/run-identity.ts +4 -3
  562. package/src/task-agent/shadow.ts +19 -3
  563. package/src/task-agent/task-hand.ts +96 -36
  564. package/src/task-agent/tier-split.ts +127 -0
  565. package/src/task-agent/work-order-build.ts +24 -0
  566. package/src/task-agent/work-order.ts +3 -2
  567. package/src/task-orchestrator/generator-prompt.ts +60 -11
  568. package/src/task-orchestrator/surfaces/pod-account-broker.ts +72 -3
  569. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  570. package/src/task-orchestrator/surfaces/pod-command-job.ts +47 -8
  571. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  572. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  573. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
  574. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
  575. package/src/task-orchestrator/surfaces/pod-pool.ts +73 -17
  576. package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
  577. package/src/task-orchestrator/surfaces/pod-source-receive.ts +72 -4
  578. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  579. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +32 -5
  580. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
  581. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +421 -0
  582. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +2 -1
  583. package/src/task-orchestrator/surfaces/self-implement-pod.ts +588 -71
  584. package/src/task-orchestrator/surfaces/self-implement.ts +106 -2
  585. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  586. package/src/tool-runtime/truncation-store.ts +4 -0
  587. package/src/tui/README.md +2 -0
  588. package/src/tui/chat/background-job-status.ts +54 -0
  589. package/src/tui/chat/log-view.ts +80 -0
  590. package/src/tui/entry.ts +406 -0
  591. package/src/tui/input/composer.ts +144 -0
  592. package/src/tui/seat-mail-boot.ts +59 -0
  593. package/src/tui/slash/compact.ts +100 -0
  594. package/src/tui/slash/new-session.ts +35 -0
  595. package/src/tui-client/dashboard-session.ts +10 -1
  596. package/src/tui-client/local-chat-turn.ts +239 -0
  597. package/src/tui-client/local-harness-command.ts +63 -0
  598. package/src/tui-client/local-provider-command.ts +184 -0
  599. package/src/user-config/coercion.ts +36 -0
  600. package/src/user-config.ts +22 -43
  601. package/src/ux-sim/event-monkey.ts +378 -0
  602. package/src/ux-sim/fake-bin.ts +42 -7
  603. package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
  604. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  605. package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
  606. package/src/ux-sim/scenario.ts +72 -13
  607. package/src/version/packed-revision.json +1 -1
  608. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
  611. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
  612. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
  613. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
  617. package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
  619. package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
  620. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/2898.fd781bc7cf01a7b7.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
  629. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
  630. package/apps/pwa/out/_next/static/chunks/3541-ce3a5424ed5ad7f1.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
  636. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
  640. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
  641. package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +0 -226
  642. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
  644. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
  647. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/5543.a438b8ab5a13ea47.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
  653. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
  655. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
  661. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
  662. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
  663. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
  668. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
  669. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
  674. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +0 -24
  685. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/9989.3694300e5f000b14.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-8c66a3b24a745630.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/setup/page-c219f2ed171131be.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
  744. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
  752. package/src/cli/g6a-registration-probe.ts +0 -16
  753. /package/apps/pwa/out/_next/static/{IVKr3AlRUVLKsw2fh7eXF → T1mBQqmkwKDLGtyisDCOd}/_ssgManifest.js +0 -0
@@ -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 { assessDraftTriage, decideDraft, draftClaimComment, draftClaimState, draftReleaseComment, laterMergedTwins, sameGoalPr, PROTECTED_LABELS, type DraftTriageAssessment, type DraftTriagePr, type DraftTriageReviewState } 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';
@@ -25,6 +26,8 @@ export interface SweepMergedPr extends DraftTriagePr {
25
26
  export interface DraftSweepAdapters {
26
27
  /** Each call returns one complete page; a rejection must not be mistaken for an empty page. */
27
28
  listDrafts(page: number, perPage: number, repository: string): Promise<readonly SweepDraft[]>;
29
+ /** Head commit time is fetched only for explicit triage, where it gates idle/close recommendations. */
30
+ getHeadCommitTime?(repository: string, number: number): Promise<string | undefined>;
28
31
  listMerged(page: number, perPage: number, repository: string): Promise<readonly SweepMergedPr[]>;
29
32
  /** Complete closed PR inventory for the creation cohort (including closed without merge). */
30
33
  listRecentClosed?(repository: string, createdSince: Date): Promise<readonly SweepMergedPr[]>;
@@ -47,6 +50,8 @@ export interface DraftSweepAdapters {
47
50
  /** Host ledger terminal records; undefined means the ledger could not be read. */
48
51
  listPrTerminals?(): Promise<readonly PrTerminalRecord[] | undefined>;
49
52
  commentDraft?(repository: string, number: number, body: string): Promise<void>;
53
+ /** Complete issue-comment inventory for idempotent merge-time same-cell cleanup. */
54
+ listIssueComments?(repository: string, number: number): Promise<readonly string[]>;
50
55
  removeLabel?(repository: string, number: number, label: string): Promise<void>;
51
56
  /** Whether the current owned run has a self-implement.result final observation, even if its worktree remains. */
52
57
  hasFinalRunResult?(draft: SweepDraft, repository: string): Promise<boolean | undefined>;
@@ -74,6 +79,8 @@ export interface SweepReviewGate {
74
79
  readonly review?: 'pass' | 'fail';
75
80
  readonly mustFix?: boolean;
76
81
  readonly gate?: 'pass' | 'fail';
82
+ /** Exact-head review posture for triage; unknown stays distinct from legacy census posture. */
83
+ readonly triageReview?: DraftTriageReviewState;
77
84
  }
78
85
 
79
86
  export interface DraftSweepOptions {
@@ -86,6 +93,8 @@ export interface DraftSweepOptions {
86
93
  closeCapSource?: DraftSweepCloseCapSource;
87
94
  /** Closes already made this tick by the pod-terminal replay — they count against the same cap. */
88
95
  alreadyClosed?: number;
96
+ /** Include evidence-backed next-action recommendations in JSON output; never authorizes writes. */
97
+ includeTriage?: boolean;
89
98
  }
90
99
 
91
100
  export interface DraftSweepEntry {
@@ -104,6 +113,7 @@ export interface DraftSweepResult {
104
113
  apply: boolean;
105
114
  complete: boolean;
106
115
  entries: DraftSweepEntry[];
116
+ triage?: { entries: Array<{ number: number; assessment: DraftTriageAssessment }>; counts: Record<string, number> };
107
117
  counts: Record<string, number>;
108
118
  /** Drafts whose run could not be observed from here (kept, or closed by the idle rule). */
109
119
  unobserved?: number;
@@ -133,6 +143,11 @@ export interface DraftSweepLineageCounts {
133
143
  closed: number;
134
144
  harvestableClosed: number;
135
145
  fallThrough: Record<string, number>;
146
+ /**
147
+ * Of `closed`, the ones the 칸 (cell) key decided instead of the branch lineage key. Absent while the 칸 rule
148
+ * closes nothing, so every existing lineage count and log line keeps its exact shape.
149
+ */
150
+ cellClosed?: number;
136
151
  }
137
152
 
138
153
  /** A review counts as passed only on an observed PASS with no must-fix left. */
@@ -587,12 +602,14 @@ export function resolveDraftSweepCloseCap(input: { flag?: unknown; config?: unkn
587
602
  return { closeCap: DRAFT_SWEEP_CLOSE_CAP, closeCapSource: 'default', warnings };
588
603
  }
589
604
 
590
- /** Post-merge shortcut: only the existing superseded-by decision can authorize a close. */
605
+ /** Post-merge cleanup: an explicit same-cell successor or the existing verified-goal decision can authorize a close. */
591
606
  export async function supersedeDraftsOnMerge(input: {
592
607
  repository: string;
593
608
  merged: SweepMergedPr & { createdAt: string; mergedAt: string };
609
+ /** `pr land` and HQ train invoke only the explicit same-cell successor path. */
610
+ onlyExplicitSameCell?: boolean;
594
611
  adapters: Pick<DraftSweepAdapters, 'listDrafts' | 'listLiveBranches' | 'getRunStatus' | 'setLabels' | 'closeDraft'>
595
- & Pick<Partial<DraftSweepAdapters>, 'getLatestFileChanges' | 'getPrFiles'>;
612
+ & Pick<Partial<DraftSweepAdapters>, 'getLatestFileChanges' | 'getPrFiles' | 'commentDraft' | 'listIssueComments'>;
596
613
  }): Promise<{ closed: number[]; kept: number[] }> {
597
614
  const { repository, merged, adapters } = input;
598
615
  const closed: number[] = [];
@@ -611,6 +628,43 @@ export async function supersedeDraftsOnMerge(input: {
611
628
  || !Number.isFinite(Date.parse(merged.createdAt)) || !Number.isFinite(Date.parse(merged.mergedAt))
612
629
  || drafts.some((pr) => !Number.isInteger(pr.number) || !pr.branch || !Array.isArray(pr.labels)
613
630
  || !Number.isFinite(Date.parse(pr.createdAt)))) throw new Error('Incomplete merge draft inventory');
631
+ // The conflicting-PR path writes this exact marker. A marker by itself is not authority:
632
+ // both PR bodies must identify the same cell, and the old PR must still be an open draft.
633
+ const markers = [...(merged.body ?? '').matchAll(/^Supersedes:\s*#(\d+)\s*$/gm)];
634
+ const markedNumber = markers.length === 1 ? Number(markers[0]![1]) : null;
635
+ const explicitOld = Number.isSafeInteger(markedNumber) && markedNumber! > 0 ? markedNumber : null;
636
+ const mergedCell = cellIdFromBody(merged.body ?? '');
637
+ if (explicitOld && explicitOld !== merged.number && mergedCell) {
638
+ const old = drafts.find((draft) => draft.number === explicitOld);
639
+ if (old && cellIdFromBody(old.body ?? '') === mergedCell
640
+ && Date.parse(old.createdAt) < Date.parse(merged.mergedAt)
641
+ && !old.labels.some((label) => PROTECTED_LABELS.has(label))
642
+ && PR_LABELS.filter((label) => label.axis === 'state' && old.labels.includes(label.name)).length <= 1) {
643
+ const marker = `<!-- elanous:same-cell-superseded #${old.number} -> #${merged.number} -->`;
644
+ const comment = `${marker}\nSame-cell draft superseded by merged PR #${merged.number} (https://github.com/${repository}/pull/${merged.number}). Branch preserved.`;
645
+ try {
646
+ if (!adapters.listIssueComments || !adapters.commentDraft) throw new Error('same-cell comment inventory unavailable');
647
+ const comments = await adapters.listIssueComments(repository, old.number);
648
+ if (!Array.isArray(comments)) throw new Error('same-cell comment inventory incomplete');
649
+ const remove = stateLabels.filter((label) => old.labels.includes(label.name) && label.name !== supersededLabel).map((label) => label.name);
650
+ if (!old.labels.includes(supersededLabel)) await adapters.setLabels(repository, old.number, { add: supersededLabel, remove });
651
+ if (!comments.some((body) => body.includes(marker))) await adapters.commentDraft(repository, old.number, comment);
652
+ await adapters.closeDraft(repository, old.number);
653
+ closed.push(old.number);
654
+ closeAttempts += 1;
655
+ } catch (failure) {
656
+ failed.push(old.number);
657
+ error = String(failure);
658
+ debug.log('drafts.cleanup', 'same-cell-supersede-failed', { merged: merged.number, old: old.number, error });
659
+ }
660
+ }
661
+ }
662
+ if (input.onlyExplicitSameCell) {
663
+ kept.push(...drafts.map((draft) => draft.number).filter((number) => !closed.includes(number)));
664
+ debug.log('drafts.cleanup', 'superseded-on-merge', { merged: merged.number, closed, kept,
665
+ ...(failed.length ? { failed } : {}), ...(error ? { error } : {}) });
666
+ return { closed, kept };
667
+ }
614
668
  const statuses = new Map<number, string | undefined>();
615
669
  const latestChanges = new Map<number, Readonly<Record<string, string>> | undefined>();
616
670
  const mergedFiles = await adapters.getPrFiles?.(repository, merged.number);
@@ -625,7 +679,14 @@ export async function supersedeDraftsOnMerge(input: {
625
679
  }
626
680
  }
627
681
  for (const listedDraft of drafts) {
682
+ if (closed.includes(listedDraft.number)) continue;
628
683
  const draft = { ...listedDraft, latestFileChanges: latestChanges.get(listedDraft.number) };
684
+ // The same-cell route is never inferred from a title, goal, or file overlap.
685
+ // A failed explicit cleanup also stays open for a later retry instead of falling through to generic triage.
686
+ if (draft.number === explicitOld || (mergedCell && cellIdFromBody(draft.body ?? '') === mergedCell)) {
687
+ kept.push(draft.number);
688
+ continue;
689
+ }
629
690
  if (draft.number === merged.number || !draft.branch.startsWith('self-impl/') || liveBranches.has(draft.branch)
630
691
  || Date.parse(draft.createdAt) >= Date.parse(merged.mergedAt)) {
631
692
  kept.push(draft.number);
@@ -724,6 +785,30 @@ export function newerLineageDraft(draft: SweepDraft, openDrafts: readonly SweepD
724
785
  .sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt) || b.number - a.number)[0];
725
786
  }
726
787
 
788
+ /**
789
+ * The newest open draft of the same 칸 (cell) that was created strictly after `draft` and belongs to a different
790
+ * goal lineage — two runs of different goals working the same cell are duplicates of one deliverable.
791
+ * Reads the canonical cell identity (`cellIdFromBody`, the same `칸: <CELL>` marker the PR creation guard uses),
792
+ * never a re-derived marker, and keeps `branchLineageKey` byte-compatible: only a *different* key is a cell match.
793
+ * ⛔ A draft whose body names no 칸 never matches (keep), and a same-칸 draft of the same goal is `newerLineageDraft`.
794
+ */
795
+ export function newerSameCellDraft(draft: SweepDraft, openDrafts: readonly SweepDraft[]): SweepDraft | undefined {
796
+ const cellId = cellIdFromBody(draft.body ?? '');
797
+ const created = Date.parse(draft.createdAt);
798
+ if (cellId === null || !Number.isFinite(created)) return undefined;
799
+ const key = branchLineageKey(draft.branch);
800
+ // A missing goal id is not evidence of a different goal. Keep unknown lineage on either side.
801
+ if (key === null) return undefined;
802
+ return openDrafts
803
+ .filter((pr) => {
804
+ const openKey = branchLineageKey(pr.branch);
805
+ return pr.number !== draft.number && cellIdFromBody(pr.body ?? '') === cellId
806
+ && openKey !== null && openKey !== key
807
+ && Number.isFinite(Date.parse(pr.createdAt)) && Date.parse(pr.createdAt) > created;
808
+ })
809
+ .sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt) || b.number - a.number)[0];
810
+ }
811
+
727
812
  /**
728
813
  * Census of harness drafts older than 24h. Same-goal landing uses `sameGoalPr` unchanged.
729
814
  * A draft counts as closable when a same-goal merged PR exists, harvestable when review PASS and the gate passed,
@@ -751,7 +836,7 @@ export function draftSweepDaily(
751
836
  }
752
837
 
753
838
  /** A failed inventory or liveness lookup is never treated as proof that a draft can be closed. */
754
- export async function runDraftSweep({ repository, adapters, apply = false, now = new Date(), closeCap: requestedCap, closeCapSource: requestedSource, alreadyClosed = 0 }: DraftSweepOptions): Promise<DraftSweepResult> {
839
+ export async function runDraftSweep({ repository, adapters, apply = false, now = new Date(), closeCap: requestedCap, closeCapSource: requestedSource, alreadyClosed = 0, includeTriage = false }: DraftSweepOptions): Promise<DraftSweepResult> {
755
840
  const validCap = validCloseCap(requestedCap);
756
841
  const closeCap = validCap ?? DRAFT_SWEEP_CLOSE_CAP;
757
842
  const closeCapSource: DraftSweepCloseCapSource = validCap === undefined ? 'default' : requestedSource ?? 'flag';
@@ -829,7 +914,7 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
829
914
  const reviewGate = new Map<number, SweepReviewGate | undefined>();
830
915
  if (adapters.getReviewGate) {
831
916
  // Review/gate posture only feeds the daily census, which only counts harness drafts older than 24h.
832
- const censused = drafts.filter((draft) => dailyCensusDraft(draft, now));
917
+ const censused = includeTriage ? drafts : drafts.filter((draft) => dailyCensusDraft(draft, now));
833
918
  try {
834
919
  await mapBounded(censused, DRAFT_SWEEP_CONCURRENCY, async (draft) => {
835
920
  reviewGate.set(draft.number, await adapters.getReviewGate!(draft, repository));
@@ -845,12 +930,89 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
845
930
  // Card and terminal inventories are observations, not closing authority. An unreadable source cannot mint a claim.
846
931
  let cards: readonly TaskCard[] | undefined;
847
932
  let terminals: readonly PrTerminalRecord[] | undefined;
848
- if (apply) {
933
+ if (apply || includeTriage) {
849
934
  try { cards = await adapters.listTaskCards?.(); if (cards && !Array.isArray(cards)) cards = undefined; }
850
935
  catch (error) { debug.log('draft.residue', 'claim-skipped', { prNumber: null, owner: null, runId: null, reason: `cards-unreadable: ${sweepFailureReason(error)}` }); }
851
936
  try { terminals = await adapters.listPrTerminals?.(); if (terminals && !Array.isArray(terminals)) terminals = undefined; }
852
937
  catch (error) { debug.log('draft.residue', 'claim-skipped', { prNumber: null, owner: null, runId: null, reason: `terminals-unreadable: ${sweepFailureReason(error)}` }); }
853
938
  }
939
+ if (includeTriage) {
940
+ const latestCommitTimes = new Map<number, string | undefined>();
941
+ if (adapters.getHeadCommitTime) {
942
+ await mapBounded(drafts, DRAFT_SWEEP_CONCURRENCY, async (draft) => {
943
+ latestCommitTimes.set(draft.number, draft.latestCommitAt ?? await adapters.getHeadCommitTime!(repository, draft.number).catch(() => undefined));
944
+ });
945
+ }
946
+ const triageDrafts = drafts.map((draft) => ({ ...draft,
947
+ ...(latestCommitTimes.has(draft.number) ? { latestCommitAt: latestCommitTimes.get(draft.number) } : {}),
948
+ }));
949
+ const triageRows: Array<{ number: number; assessment: DraftTriageAssessment }> = [];
950
+ const initial = triageDrafts.map((draft) => {
951
+ const posture = reviewGate.get(draft.number);
952
+ return assessDraftTriage({ draft, now, runStatus: statuses.get(draft.number),
953
+ ...(posture?.gate ? { gate: posture.gate } : {}),
954
+ ...(posture?.triageReview ? { review: posture.triageReview } : {}),
955
+ });
956
+ });
957
+ const activeOwnerObservations = new Map<number, { owner?: string; observed: boolean }>();
958
+ if (adapters.getActiveClaimOwner) {
959
+ const ownerLookupDrafts = triageDrafts.filter((draft) => !(cards && draftTaskOwner(cards, draft)));
960
+ await mapBounded(ownerLookupDrafts, DRAFT_SWEEP_CONCURRENCY, async (draft) => {
961
+ try {
962
+ activeOwnerObservations.set(draft.number, { owner: await adapters.getActiveClaimOwner!(repository, draft.number), observed: true });
963
+ } catch {
964
+ activeOwnerObservations.set(draft.number, { observed: false });
965
+ }
966
+ });
967
+ }
968
+ for (let index = 0; index < drafts.length; index++) {
969
+ const draft = triageDrafts[index]!;
970
+ const identity = initial[index]!;
971
+ // A generic sweep can target any repository, while the checklist is machine-wide.
972
+ // Until checklist observations are repository-bound, leave cell status unknown so close-a stays human.
973
+ const draftCreatedAt = Date.parse(draft.createdAt);
974
+ let newerSameCellSameCard: boolean | undefined;
975
+ if (identity.origin && identity.cellId && identity.cardId && Number.isFinite(draftCreatedAt)) {
976
+ let uncertainMatch = false;
977
+ newerSameCellSameCard = false;
978
+ for (let otherIndex = 0; otherIndex < triageDrafts.length; otherIndex++) {
979
+ if (otherIndex === index) continue;
980
+ const other = triageDrafts[otherIndex]!;
981
+ const otherIdentity = initial[otherIndex];
982
+ const otherCreatedAt = Date.parse(other.createdAt);
983
+ if (Number.isFinite(otherCreatedAt) && otherCreatedAt <= draftCreatedAt) continue;
984
+ if (otherIdentity?.origin && otherIdentity.origin !== identity.origin) continue;
985
+ if (otherIdentity?.cellId && otherIdentity.cellId !== identity.cellId) continue;
986
+ if (otherIdentity?.cardId && otherIdentity.cardId !== identity.cardId) continue;
987
+ if (!Number.isFinite(otherCreatedAt) || !otherIdentity?.origin || !otherIdentity.cellId || !otherIdentity.cardId) {
988
+ uncertainMatch = true;
989
+ continue;
990
+ }
991
+ newerSameCellSameCard = true;
992
+ break;
993
+ }
994
+ if (newerSameCellSameCard !== true && uncertainMatch) newerSameCellSameCard = undefined;
995
+ }
996
+ const ownerCard = cards ? draftTaskOwner(cards, draft) : undefined;
997
+ // A cell can have several cards and PRs. Terminal evidence belongs to this draft only by exact PR number;
998
+ // the terminal `card` field can identify the cell, not this card.
999
+ const cellTerminals = terminals?.filter((terminal) => terminal.repository === repository && terminal.prNumber === draft.number);
1000
+ const activeOwnerObservation = ownerCard ? undefined : activeOwnerObservations.get(draft.number);
1001
+ const posture = reviewGate.get(draft.number);
1002
+ const assessment = assessDraftTriage({ draft, now, runStatus: statuses.get(draft.number),
1003
+ ...(posture?.gate ? { gate: posture.gate } : {}),
1004
+ ...(posture?.triageReview ? { review: posture.triageReview } : {}),
1005
+ newerSameCellSameCard,
1006
+ ownerConfirmed: ownerCard?.seat ? true : !activeOwnerObservation?.observed ? undefined : Boolean(activeOwnerObservation.owner?.trim()),
1007
+ });
1008
+ const terminalEvidence = terminals === undefined ? 'PrTerminalRecord 미관측'
1009
+ : `PrTerminalRecord: cell=${identity.cellId ?? 'unknown'} matched=${cellTerminals?.length ?? 0}`;
1010
+ triageRows.push({ number: draft.number, assessment: { ...assessment, evidence: [...assessment.evidence, terminalEvidence] } });
1011
+ }
1012
+ const triageCounts: Record<string, number> = {};
1013
+ for (const row of triageRows) triageCounts[row.assessment.nextAction] = (triageCounts[row.assessment.nextAction] ?? 0) + 1;
1014
+ result.triage = { entries: triageRows, counts: triageCounts };
1015
+ }
854
1016
  result.complete = true;
855
1017
  let closes = Number.isSafeInteger(alreadyClosed) && alreadyClosed > 0 ? alreadyClosed : 0;
856
1018
  let unobserved = 0;
@@ -858,6 +1020,8 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
858
1020
  let claimExpired = 0;
859
1021
  const lineageCounts: DraftSweepLineageCounts = { closed: 0, harvestableClosed: 0, fallThrough: {} };
860
1022
  result.lineage = lineageCounts;
1023
+ // 칸-keyed closes this tick; published on `lineageCounts` only when the 칸 rule fires (existing shapes stay byte-identical).
1024
+ let cellClosed = 0;
861
1025
  // Review posture for the harvestable lineage check, reusing the census lookups (one lookup per PR per tick).
862
1026
  const postureFor = async (pr: SweepDraft): Promise<SweepReviewGate | undefined> => {
863
1027
  if (!reviewGate.has(pr.number)) reviewGate.set(pr.number, await adapters.getReviewGate!(pr, repository));
@@ -980,7 +1144,11 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
980
1144
  // reruns open until the 24h idle expiry. It is still protected when its own review passed and the newer one's did not.
981
1145
  const harvestable = draft.labels.includes(harvestableLabel);
982
1146
  const lineageNewer = contradiction ? undefined : newerLineageDraft(draft, drafts);
983
- if (lineageNewer) {
1147
+ // A different goal working the same 칸 is invisible to the branch lineage key, so the canonical 칸 identity decides it.
1148
+ // The lineage key keeps priority: a same-goal rerun stays a lineage outcome even when both drafts share the 칸.
1149
+ const cellNewer = contradiction || lineageNewer ? undefined : newerSameCellDraft(draft, drafts);
1150
+ const duplicateNewer = lineageNewer ?? cellNewer;
1151
+ if (duplicateNewer) {
984
1152
  const base = decideDraft({ draft, runStatus, mergedTwins: merged, openDrafts: drafts, liveBranches,
985
1153
  finalRunResult, ageHours: runStatus ? ageHours : idleHours });
986
1154
  if (!base.reason.startsWith('label:') && !base.reason.startsWith('superseded-by #') && !base.reason.startsWith('duplicate-of-open #')) {
@@ -988,12 +1156,14 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
988
1156
  || (status !== 'self-implement.result final' && liveBranches.has(branch));
989
1157
  const runLive = live(runStatus, draft.branch);
990
1158
  const lineageKey = branchLineageKey(draft.branch);
991
- const reason = `duplicate-of-open #${lineageNewer.number} (lineage ${lineageKey})${runLive ? ` · stop run ${draft.runId ?? 'unknown'}` : ''}`;
1159
+ const cellId = cellNewer ? cellIdFromBody(draft.body ?? '') : null;
1160
+ const duplicateOf = cellNewer ? `cell ${cellId}` : `lineage ${lineageKey}`;
1161
+ const reason = `duplicate-of-open #${duplicateNewer.number} (${duplicateOf})${runLive ? ` · stop run ${draft.runId ?? 'unknown'}` : ''}`;
992
1162
  // Every lineage outcome that does not close falls through to the existing rules (preservation contract):
993
1163
  // a duplicate this rule cannot settle is decided exactly as it was before this rule existed.
994
1164
  const fallThrough = (why: string) => {
995
1165
  lineageCounts.fallThrough[why] = (lineageCounts.fallThrough[why] ?? 0) + 1;
996
- try { debug.log('self-dev.draft-sweep', 'lineage-fall-through', { number: draft.number, newer: lineageNewer.number, lineageKey, why, harvestable }); } catch { /* fail-soft */ }
1166
+ try { debug.log('self-dev.draft-sweep', 'lineage-fall-through', { number: draft.number, newer: duplicateNewer.number, lineageKey, ...(cellId === null ? {} : { cellId }), why, harvestable }); } catch { /* fail-soft */ }
997
1167
  };
998
1168
  // A harvestable draft yields only to a newer draft at least as complete: an observed review PASS on the old one
999
1169
  // is kept unless the newer one passed review too. Unobservable review posture keeps the old draft (fail-closed).
@@ -1002,17 +1172,19 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
1002
1172
  if (!adapters.getReviewGate) harvestProtection = 'lineage-harvestable-review-unobserved';
1003
1173
  else {
1004
1174
  try {
1005
- const [oldPosture, newPosture] = [await postureFor(draft), await postureFor(lineageNewer)];
1175
+ const [oldPosture, newPosture] = [await postureFor(draft), await postureFor(duplicateNewer)];
1006
1176
  if (oldPosture === undefined) harvestProtection = 'lineage-harvestable-review-unobserved';
1007
1177
  else if (reviewPassed(oldPosture) && !reviewPassed(newPosture)) harvestProtection = 'lineage-harvestable-review-pass-protected';
1008
1178
  } catch { harvestProtection = 'lineage-harvestable-review-unobserved'; }
1009
1179
  }
1010
1180
  }
1011
1181
  if (harvestProtection) fallThrough(harvestProtection);
1182
+ // `supersedeRun` is same-lineage authority only: a live 칸 duplicate is kept for the existing rules instead.
1183
+ else if (cellNewer && runLive) fallThrough('cell-duplicate-run-live');
1012
1184
  else if (runLive && !adapters.supersedeRun) fallThrough('lineage-duplicate-run-live');
1013
1185
  // Safety (OP 10-11): a live run is stopped only when the newer run of the same lineage is itself live —
1014
1186
  // never trade a running attempt for one that already ended or was never observed running.
1015
- else if (runLive && !live(statuses.get(lineageNewer.number), lineageNewer.branch)) fallThrough('lineage-newer-run-not-live');
1187
+ else if (runLive && !live(statuses.get(duplicateNewer.number), duplicateNewer.branch)) fallThrough('lineage-newer-run-not-live');
1016
1188
  else if (closes >= closeCap) {
1017
1189
  record({ number: draft.number, action: 'keep', reason: 'close-cap', applied: false });
1018
1190
  continue;
@@ -1020,9 +1192,9 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
1020
1192
  let stopFailed = false;
1021
1193
  // --apply only: the run is stopped before anything is written; a stop that cannot be confirmed writes nothing.
1022
1194
  if (apply && runLive) {
1023
- const observed = { number: draft.number, newer: lineageNewer.number, runId: draft.runId ?? null, newerRunId: lineageNewer.runId ?? null, lineageKey };
1195
+ const observed = { number: draft.number, newer: duplicateNewer.number, runId: draft.runId ?? null, newerRunId: duplicateNewer.runId ?? null, lineageKey };
1024
1196
  try {
1025
- await adapters.supersedeRun!(draft, repository, lineageNewer);
1197
+ await adapters.supersedeRun!(draft, repository, duplicateNewer);
1026
1198
  try { debug.log('self-dev.draft-sweep', 'supersede-run', observed); } catch { /* fail-soft */ }
1027
1199
  } catch (error) {
1028
1200
  stopFailed = true;
@@ -1035,6 +1207,7 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
1035
1207
  closes += 1;
1036
1208
  lineageCounts.closed += 1;
1037
1209
  if (harvestable) lineageCounts.harvestableClosed += 1;
1210
+ if (cellNewer) cellClosed += 1;
1038
1211
  const entry: DraftSweepEntry = { number: draft.number, action: 'close', reason, statusLabel: supersededLabel, applied: false };
1039
1212
  record(entry);
1040
1213
  if (!apply) continue;
@@ -1054,6 +1227,7 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
1054
1227
  closes -= 1;
1055
1228
  lineageCounts.closed -= 1;
1056
1229
  if (harvestable) lineageCounts.harvestableClosed -= 1;
1230
+ if (cellNewer) cellClosed -= 1;
1057
1231
  }
1058
1232
  entry.error = String(error);
1059
1233
  }
@@ -1163,6 +1337,7 @@ export async function runDraftSweep({ repository, adapters, apply = false, now =
1163
1337
  }
1164
1338
  }
1165
1339
  timing('decide', drafts.length);
1340
+ if (cellClosed > 0) lineageCounts.cellClosed = cellClosed;
1166
1341
  try { debug.log('self-dev.draft-sweep', 'lineage-summary', { ...lineageCounts, apply }); } catch { /* fail-soft */ }
1167
1342
  try { debug.log('self-dev.draft-sweep', 'timing', { phase: 'total', ms: Date.now() - started, count: drafts.length, closed: closes, closeCap, closeCapSource }); } catch { /* fail-soft */ }
1168
1343
  result.unobserved = unobserved;
@@ -30,6 +30,113 @@ export interface DraftTriagePr {
30
30
  changedFiles?: readonly string[];
31
31
  /** Latest change to each draft file, from the draft branch's commit history. Missing is not creation time. */
32
32
  latestFileChanges?: Readonly<Record<string, string>>;
33
+ /** Latest head commit, separate from PR updatedAt (labels/comments also update that). */
34
+ latestCommitAt?: string;
35
+ }
36
+
37
+ export type DraftTriageNextAction = 'close-a' | 'close-c' | 'human';
38
+ export type DraftTriageReviewState = 'approved' | 'changes-requested' | 'commented' | 'dismissed' | 'pending' | 'unknown';
39
+ export type DraftTriageCheck = { state: 'yes' | 'no' | 'unknown'; evidence: string };
40
+ export interface DraftTriageAssessment {
41
+ origin: string | null;
42
+ cellId: string | null;
43
+ cardId: string | null;
44
+ gate: 'pass' | 'fail' | 'unknown';
45
+ review: DraftTriageReviewState;
46
+ cellStatus: 'green' | 'yellow' | 'red' | 'done' | 'unknown';
47
+ nextAction: DraftTriageNextAction;
48
+ checks: Readonly<Record<'provenance' | 'gate' | 'review' | 'cell-complete' | 'cell-status-repository-bound' | 'replacement-landed' | 'newer-same-card' | 'idle-48h' | 'protected' | 'recent-commit' | 'running' | 'owner-confirmed', DraftTriageCheck>>;
49
+ evidence: readonly string[];
50
+ }
51
+
52
+ export interface DraftTriageAssessmentInput {
53
+ draft: DraftTriagePr;
54
+ now: Date;
55
+ runStatus?: string;
56
+ gate?: 'pass' | 'fail';
57
+ review?: DraftTriageReviewState;
58
+ cellStatus?: 'green' | 'yellow' | 'red' | 'done';
59
+ /** Repository identity attached to the cell-status observation, when available. */
60
+ cellStatusRepository?: string;
61
+ /** Repository targeted by this triage request. */
62
+ targetRepository?: string;
63
+ newerSameCellSameCard?: boolean;
64
+ ownerConfirmed?: boolean;
65
+ }
66
+
67
+ const CLOSE_PROTECTED_LABELS = new Set([
68
+ 'elanous:running', 'elanous:keep', 'elanous:release-hold', 'elanous:idea-approval',
69
+ 'elanous:harvest-claimed', 'triage:land', 'triage:active',
70
+ ]);
71
+ const TRIAGE_TERMINAL_RUN_STATUSES = new Set(['completed', 'failed', 'cancelled', 'abandoned', 'self-implement.result final']);
72
+
73
+ /** Evidence-first recommendation. Unknown evidence always routes to a person. */
74
+ export function assessDraftTriage(input: DraftTriageAssessmentInput): DraftTriageAssessment {
75
+ const { draft, now } = input;
76
+ const originLabels = (draft.labels ?? []).filter((name) => /^elanous:from-[a-z0-9-]+$/.test(name));
77
+ const origin = originLabels.length === 1 ? originLabels[0]! : null;
78
+ const bodyLines = (draft.body ?? '').split(/\r?\n/);
79
+ const cellMarkerLines = bodyLines.filter((line) => /^\s*칸\s*:/.test(line));
80
+ const cellRows = bodyLines.flatMap((line) => {
81
+ const match = /^칸:\s*([^\r\n]*)$/.exec(line);
82
+ return match ? [match[1]!.trim()] : [];
83
+ });
84
+ const cellValues = new Set(cellRows);
85
+ const cellId = cellMarkerLines.length === cellRows.length && cellRows.length > 0 && cellValues.size === 1
86
+ && /^[A-Z][A-Z0-9-]{2,}$/.test(cellRows[0]!) ? cellRows[0]! : null;
87
+ const cardMarkerLines = bodyLines.filter((line) => /^\s*카드\s*:/.test(line));
88
+ const cardRows = bodyLines.flatMap((line) => {
89
+ const match = /^카드:[ \t]*([^\r\n]+)[ \t]*$/.exec(line);
90
+ return match ? [match[1]!.trim()] : [];
91
+ });
92
+ const cardId = cardMarkerLines.length === cardRows.length && cardRows.length > 0
93
+ && cardRows.every((value) => value === cardRows[0])
94
+ && /^[A-Za-z0-9][A-Za-z0-9._:-]{2,}$/.test(cardRows[0]!) ? cardRows[0]! : null;
95
+ const provenance = Boolean(origin && cellId && cardId);
96
+ const latestCommit = Date.parse(draft.latestCommitAt ?? '');
97
+ const clock = now.getTime();
98
+ const ageHours = Number.isFinite(latestCommit) && Number.isFinite(clock) ? (clock - latestCommit) / 3_600_000 : NaN;
99
+ const protectedLabel = (draft.labels ?? []).find((name) => CLOSE_PROTECTED_LABELS.has(name));
100
+ const protectedState = Boolean(protectedLabel);
101
+ const running = input.runStatus === 'running' || input.runStatus === 'probable-running'
102
+ || (draft.labels ?? []).includes('elanous:running');
103
+ const cellComplete = input.cellStatus === 'green' || input.cellStatus === 'done';
104
+ const hasCellStatusRepositoryIdentity = Boolean(input.cellStatusRepository?.trim() && input.targetRepository?.trim());
105
+ const cellStatusRepositoryBound = hasCellStatusRepositoryIdentity
106
+ && input.cellStatusRepository!.trim().toLowerCase() === input.targetRepository!.trim().toLowerCase();
107
+ const releaseCutoff = Number.isFinite(clock) ? (() => {
108
+ const date = new Date(clock);
109
+ const cutoff = new Date(date);
110
+ cutoff.setUTCHours(0, 30, 0, 0); // 09:30 KST
111
+ return clock < cutoff.getTime() ? cutoff.getTime() - 86_400_000 : cutoff.getTime();
112
+ })() : NaN;
113
+ const recentCommit = Number.isFinite(latestCommit) && Number.isFinite(releaseCutoff) && latestCommit > releaseCutoff;
114
+ const runNotRunning = input.runStatus !== undefined && TRIAGE_TERMINAL_RUN_STATUSES.has(input.runStatus) && !running;
115
+ // Closing requires positive evidence that the head predates today's release cutoff.
116
+ // Missing timestamps are unknown, so they cannot authorize a close recommendation.
117
+ const closeEligible = provenance && !protectedState && Number.isFinite(latestCommit) && !recentCommit && runNotRunning;
118
+ const idle48h = Number.isFinite(ageHours) && ageHours >= 48;
119
+ let nextAction: DraftTriageNextAction = 'human';
120
+ if (closeEligible && cellComplete && cellStatusRepositoryBound) nextAction = 'close-a';
121
+ else if (closeEligible && idle48h && input.ownerConfirmed === true) nextAction = 'close-c';
122
+
123
+ const checks = {
124
+ provenance: { state: provenance ? 'yes' : 'unknown', evidence: provenance ? `origin=${origin}; cell=${cellId}; card=${cardId}` : '출처·유효 칸·카드 표지가 모두 확인되지 않음' },
125
+ gate: { state: input.gate === undefined ? 'unknown' : input.gate === 'pass' ? 'yes' : 'no', evidence: `gate=${input.gate ?? 'unknown'}` },
126
+ review: { state: input.review === undefined || input.review === 'unknown' ? 'unknown' : input.review === 'approved' ? 'yes' : 'no', evidence: `latest exact-head review=${input.review ?? 'unknown'}` },
127
+ 'cell-complete': { state: input.cellStatus && cellStatusRepositoryBound ? (cellComplete ? 'yes' : 'no') : 'unknown', evidence: input.cellStatus ? `cell=${cellId ?? 'unknown'} status=${input.cellStatus}${cellStatusRepositoryBound ? '' : ' (저장소 귀속 미확인)'}` : `칸 상태 미관측${cellId ? ` (${cellId})` : ''}` },
128
+ 'cell-status-repository-bound': { state: cellStatusRepositoryBound ? 'yes' : hasCellStatusRepositoryIdentity ? 'no' : 'unknown', evidence: cellStatusRepositoryBound ? `칸 상태 저장소=${input.cellStatusRepository}; 대상 저장소=${input.targetRepository}` : hasCellStatusRepositoryIdentity ? `칸 상태 저장소=${input.cellStatusRepository}; 대상 저장소=${input.targetRepository} (불일치)` : '칸 상태의 대상 저장소 귀속 미확인' },
129
+ 'replacement-landed': { state: 'unknown', evidence: '현재 adapter는 같은 칸 병합 PR과 이 초안의 대체 관계를 증명하지 않음; follow-up 필요' },
130
+ 'newer-same-card': { state: input.newerSameCellSameCard === undefined ? 'unknown' : input.newerSameCellSameCard ? 'yes' : 'no', evidence: `${input.newerSameCellSameCard === undefined ? '같은 칸·카드 새 draft 관계 미관측' : `same-cell-same-card-newer=${input.newerSameCellSameCard}`}; 관측 표지이며 대체 증거가 아님` },
131
+ 'idle-48h': { state: Number.isFinite(ageHours) ? (idle48h ? 'yes' : 'no') : 'unknown', evidence: Number.isFinite(ageHours) ? `head age=${ageHours.toFixed(1)}h` : 'head commit 시각 미관측' },
132
+ protected: { state: protectedState ? 'yes' : 'no', evidence: protectedLabel ? `보호 표지=${protectedLabel}` : '보호 표지 없음' },
133
+ 'recent-commit': { state: Number.isFinite(latestCommit) ? (recentCommit ? 'yes' : 'no') : 'unknown', evidence: Number.isFinite(latestCommit) ? `last commit=${draft.latestCommitAt}; cutoff=09:30 KST` : 'head commit 시각 미관측' },
134
+ running: { state: running ? 'yes' : runNotRunning ? 'no' : 'unknown', evidence: running ? `run=${input.runStatus ?? 'elanous:running'}` : runNotRunning ? `종결 run=${input.runStatus}` : `run 상태 미관측${input.runStatus ? ` (${input.runStatus})` : ''}` },
135
+ 'owner-confirmed': { state: input.ownerConfirmed === undefined ? 'unknown' : input.ownerConfirmed ? 'yes' : 'no', evidence: input.ownerConfirmed === undefined ? '소유자 출처 미관측' : input.ownerConfirmed ? '고유 카드 또는 활성 claim owner 확인' : '고유 소유자 없음' },
136
+ } satisfies DraftTriageAssessment['checks'];
137
+ const evidence = Object.values(checks).map((check) => check.evidence);
138
+ return { origin, cellId, cardId, gate: input.gate ?? 'unknown', review: input.review ?? 'unknown',
139
+ cellStatus: input.cellStatus ?? 'unknown', nextAction, checks, evidence };
33
140
  }
34
141
 
35
142
  export interface DraftTriageInput {
@@ -3,7 +3,7 @@
3
3
  //
4
4
  // 순서: 기준(origin/<base>)에서 임시 워크트리 → 조각 브랜치를 차례로 `merge --no-ff`
5
5
  // → 충돌이면 «그 조각 ⊕ 충돌 파일»을 이름으로 대고 병합을 되돌린 뒤 멈춘다(추측으로 풀지 않는다)
6
- // → 다 합쳐지면 `self gate --base <base>`(새 회귀만 빨강) → 통합 브랜치 푸시 → PR 하나(조각 PR 나열)
6
+ // → 다 합쳐지면 `self gate --local --base <base>`(새 회귀만 빨강) → 통합 브랜치 푸시 → PR 하나(조각 PR 나열)
7
7
  // → 조각 PR 에 «통합 PR 로 대체됨» 코멘트(닫지는 않는다 — 사람 몫).
8
8
  // ⛔ 조각 PR 을 main 에 따로 병합하지 않는다 — 그건 `--auto-merge` 의 일이고 reduce 는 «하나로»다.
9
9
 
@@ -116,7 +116,8 @@ export async function reduceShards(opts: ReduceOptions): Promise<ReduceOutcome>
116
116
  // 게이트는 저장소 코드로 돈다 — 통합 워크트리에 의존성을 잇는다(설치 없이).
117
117
  const nm = join(opts.repoRoot, 'node_modules');
118
118
  if (existsSync(nm) && !existsSync(join(wt, 'node_modules'))) symlinkSync(nm, join(wt, 'node_modules'));
119
- const g = run('bun', ['bin/elanous.mjs', 'self', 'gate', '--changed', '--base', `origin/${base}`], wt); // 📏 `--changed` 가 없으면 rc 2 로 거절한다(첫 실물)
119
+ // This gate measures the local integration worktree; remote SSH availability is unrelated to the merge result.
120
+ const g = run('bun', ['bin/elanous.mjs', 'self', 'gate', '--local', '--changed', '--base', `origin/${base}`], wt); // 📏 `--changed` 가 없으면 rc 2 로 거절한다(첫 실물)
120
121
  const tail = `${g.stdout}\n${g.stderr}`.trim().split('\n').slice(-6).join('\n');
121
122
  if (g.status !== 0) {
122
123
  debug.log('self-dev.reduce', 'gate-failed', { branch, merged: merged.length, rc: g.status });
@@ -1,6 +1,10 @@
1
1
  import { debug } from '../debug/log.js';
2
+ import type { GoalType } from '../self-implement/goal-author.js';
2
3
  import { frontObservationTemplate, visitBudgetOfVisits, type VisitBudgetReading } from '../self-implement/graph-authority.js';
3
4
  import { GRAPH_TEMPLATES_SOURCE, graphIdentityOf, pipelineNodeEntryPayload, type GraphTemplate } from '../self-implement/graph-templates.js';
5
+ import { appendRunLedgerEntry, runLedgerDir } from '../self-implement/run-ledger.js';
6
+ import { journeyJoinFields } from './graph-journey-nodes.js';
7
+ import { journeySpec, readJourneyEdge, recordJourneyEdge, type JourneyRoute } from './graph-journey-route.js';
4
8
 
5
9
  /** ⭐ RFC §5 «5단계» — 전반부(저작·플랜·분해) 노드를 그래프 관측에 «잇는다».
6
10
  *
@@ -51,6 +55,25 @@ export function resetFrontVisitCountsForTesting(now?: () => number): void {
51
55
  lastFrontVisitPruneMs = Number.NEGATIVE_INFINITY;
52
56
  }
53
57
 
58
+ /** Record the actual front-half execution boundary, without controlling the stage. */
59
+ export async function observeFrontNodeUnit<T>(node: FrontNodeId, runId: string | undefined, goalType: GoalType | undefined, execute: () => Promise<T>): Promise<T> {
60
+ const emit = (phase: 'enter' | 'exit'): void => {
61
+ if (!runId) return;
62
+ try {
63
+ const template = frontObservationTemplate(goalType);
64
+ const contractId = template.nodes.find((item) => item.nodeId === node)?.recipe ?? null;
65
+ const data = { graphId: template.graphId, nodeId: node, unit: node, contractId, phase };
66
+ try { appendRunLedgerEntry({ timestamp: new Date().toISOString(), runId, event: 'graph.unit', data }, runLedgerDir()); }
67
+ catch { /* ledger failure cannot change execution */ }
68
+ try { debug.log('graph.unit', phase, { ...data, runId }); }
69
+ catch { /* debug failure cannot change execution */ }
70
+ } catch { /* template failure cannot change execution */ }
71
+ };
72
+ emit('enter');
73
+ try { return await execute(); }
74
+ finally { emit('exit'); }
75
+ }
76
+
54
77
  function pruneIdleFrontVisitRuns(nowMs: number): void {
55
78
  if (nowMs - lastFrontVisitPruneMs < FRONT_VISIT_PRUNE_INTERVAL_MS) return;
56
79
  lastFrontVisitPruneMs = nowMs;
@@ -120,3 +143,92 @@ export function observeFrontNodeEntry(node: FrontNodeId, data: {
120
143
  });
121
144
  } catch { /* 판독 실패는 fail-soft — 예산은 관측이고 저작을 막지 않는다 */ }
122
145
  }
146
+
147
+ /** GRAPH-AUTHOR-FAIL-EDGE — author 결과가 고르는 «앞단 결과 노드». ⛔ 런타임 값 — YAML 이 더한 노드를 시험이 센다. */
148
+ export const AUTHOR_OUTCOME_NODE_IDS = ['re-ground', 'needs-human'] as const;
149
+
150
+ /** author 노드의 결과 라벨 — implement-loop.yaml `from: author · on: outcome` 의 map 키와 «같은» 닫힌 집합. */
151
+ export const AUTHOR_EXIT_OUTCOMES = ['ok', 're-authored', 'not-grounded', 'fail'] as const;
152
+ export type AuthorExitOutcome = typeof AUTHOR_EXIT_OUTCOMES[number];
153
+
154
+ export type FrontNodeExit =
155
+ | { readonly node: 'author'; readonly outcome: AuthorExitOutcome }
156
+ | { readonly node: 're-ground'; readonly outcome: 'retry' };
157
+
158
+ export interface FrontNodeExitData {
159
+ /** 1 = 첫 저작 · 2 = 자동 재저작(re-ground 를 한 번 지난 뒤). */
160
+ readonly attempt: number;
161
+ /** 코드가 «실제로» 간 다음 노드 — 그래프 답과 다르면 graph-edge-taken 이 honored:false 로 남긴다. 없으면 그래프 답. */
162
+ readonly taken?: string;
163
+ readonly reason?: string;
164
+ readonly runId?: string;
165
+ readonly goalId?: string;
166
+ readonly goalType?: string;
167
+ readonly goalFile?: string;
168
+ /** 근거 카드 — needs-human 으로 갈 때 사람이 «무엇 때문에»를 다시 캐지 않게 막힘을 그대로 싣는다. */
169
+ readonly blockers?: readonly { readonly kind: string; readonly name: string; readonly detail?: string }[];
170
+ }
171
+
172
+ const EVIDENCE_DETAIL_CHARS = 400;
173
+
174
+ /** 그래프가 고른 다음 노드에 «방문 예산»을 겹친다 — re-ground(max_visits 1)를 이미 지났으면 같은 결과의
175
+ * 두 번째는 re-ground 가 아니라 author 의 `fail` 출구(needs-human)로 간다. ⛔ 노드 이름·예산은 선언에서 읽는다. */
176
+ function withVisitBudget(route: JourneyRoute, exit: FrontNodeExit, attempt: number): { readonly to: string | null; readonly budgetReason?: string } {
177
+ // ⛔ 예산을 겹치는 대상은 re-ground 뿐이다 — attempt-1 은 «re-ground 를 지난 횟수»이지 다른 노드의 방문 수가 아니다.
178
+ if (exit.node !== 'author' || route.to !== 're-ground') return { to: route.to };
179
+ const target = journeySpec({}).spec?.nodes.find((node) => node.nodeId === route.to);
180
+ const priorVisits = Math.max(0, attempt - 1);
181
+ if (target === undefined || priorVisits < target.maxVisits) return { to: route.to };
182
+ const exhausted = readJourneyEdge('author', 'fail');
183
+ return { to: exhausted.to, budgetReason: `${route.to}-visit-budget-exhausted (max_visits ${target.maxVisits})` };
184
+ }
185
+
186
+ /** ⭐ GRAPH-AUTHOR-FAIL-EDGE ① — 앞 노드의 «나감»을 결과와 함께 남긴다(진입만 있던 자리).
187
+ * 호출부(실행 경로): src/self-dev/ask-launch-flow.ts — 저작 끝(author ok · not-grounded · re-authored) ·
188
+ * 저작기 throw(author fail) · 자동 재저작 시작(re-ground retry).
189
+ * 🔎 관측: `self-implement` / `front-node-exit` ⊕ 같은 자리의 `graph-edge-taken`(from author|re-ground).
190
+ * ⛔ 관측이지 제어가 아니다 — 다음 걸음은 여전히 코드가 정하고, 그래프 답과 다르면 honored:false 로 남는다.
191
+ * ⛔ fail-soft — 관측 실패가 저작을 죽이지 않는다. */
192
+ export function observeFrontNodeExit(exit: FrontNodeExit, data: FrontNodeExitData): JourneyRoute | null {
193
+ let recorded: JourneyRoute | null = null;
194
+ try {
195
+ const route = readJourneyEdge(exit.node, exit.outcome);
196
+ const budget = withVisitBudget(route, exit, data.attempt);
197
+ const graphRoute: JourneyRoute = { ...route, to: budget.to };
198
+ const taken = data.taken ?? budget.to ?? exit.outcome;
199
+ const reason = [budget.budgetReason, data.reason].filter((part): part is string => part !== undefined).join(' · ');
200
+ recordJourneyEdge(graphRoute, taken, reason.length > 0 ? reason : undefined);
201
+ recorded = graphRoute;
202
+ const payload = {
203
+ graphId: 'self-implement',
204
+ node: exit.node,
205
+ outcome: exit.outcome,
206
+ attempt: data.attempt,
207
+ to: budget.to,
208
+ taken,
209
+ honored: budget.to === null || budget.to === taken,
210
+ ...(reason.length > 0 ? { reason } : {}),
211
+ ...(data.runId === undefined ? {} : { runId: data.runId }),
212
+ ...(data.goalId === undefined ? {} : { goalId: data.goalId }),
213
+ ...(data.goalType === undefined ? {} : { goalType: data.goalType }),
214
+ ...(data.goalFile === undefined ? {} : { goalFile: data.goalFile }),
215
+ ...(data.blockers === undefined || data.blockers.length === 0 ? {} : {
216
+ evidenceCard: data.blockers.map((blocker) => ({
217
+ kind: blocker.kind, name: blocker.name,
218
+ ...(blocker.detail === undefined ? {} : { detail: blocker.detail.slice(0, EVIDENCE_DETAIL_CHARS) }),
219
+ })),
220
+ }),
221
+ phase: 'front',
222
+ graphTemplatesSource: GRAPH_TEMPLATES_SOURCE,
223
+ ...journeyJoinFields(),
224
+ };
225
+ try { debug.log('self-implement', 'front-node-exit', payload); }
226
+ catch { /* debug failure cannot change authoring */ }
227
+ // Pod 의 logs.db 는 Job 과 사라진다 — 원장에도 남겨 호스트가 NOT-GROUNDED 의 길을 사후에 읽게 한다.
228
+ if (data.runId !== undefined) {
229
+ try { appendRunLedgerEntry({ timestamp: new Date().toISOString(), runId: data.runId, event: 'front-node-exit', data: payload }, runLedgerDir()); }
230
+ catch { /* ledger failure cannot change authoring */ }
231
+ }
232
+ } catch { /* 관측은 fail-soft — 저작을 죽이지 않는다 */ }
233
+ return recorded;
234
+ }