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
@@ -60,8 +60,8 @@ export const AGENT_TOOL_DEFAULT_MAX_TURNS = 20;
60
60
  export const AGENT_TOOL_TURNS_CEILING = 50;
61
61
 
62
62
  /** Numeric ceiling on concurrent `run_in_background` Agent-tool fan-out.
63
- * Pure declaration — enforcement in dispatchAgent is the follow-up cell
64
- * TUI-AGENT-CAPS-WIRING (not wired here). */
63
+ * Enforced at exactly one point in `dispatchAgent` (see the
64
+ * `background-fanout-limit` block: after dedup, before `noteSeen`). */
65
65
  export const AGENT_TOOL_BACKGROUND_FANOUT_CEILING = 8;
66
66
 
67
67
  /** Clamp a caller-supplied `max_turns` onto `[1, AGENT_TOOL_TURNS_CEILING]`.
@@ -82,7 +82,9 @@ export function stripAgentToolForOneLevelNesting<T extends { name: string }>(
82
82
  }
83
83
 
84
84
  /** Live `run_in_background` tasks occupy fan-out slots until they terminal.
85
- * Pure judgement — the ceiling check that uses it is TUI-AGENT-CAPS-WIRING. */
85
+ * Counts a task list (e.g. `globalAgentRegistry.list()`). `dispatchAgent`
86
+ * enforces the per-session ceiling over its own reservation ledger
87
+ * (`backgroundFanoutSlots`) instead — see that field's doc. */
86
88
  export function countLiveBackgroundFanout(
87
89
  tasks: ReadonlyArray<{ background?: boolean; state?: string }>,
88
90
  ): number {
@@ -95,6 +97,35 @@ export function countLiveBackgroundFanout(
95
97
  return n;
96
98
  }
97
99
 
100
+ /** Fallback fan-out session key for dispatches that carry no
101
+ * `sessionCache` (agent-cli, one-off callers). All of their slots share
102
+ * one process-wide bucket so the ceiling still binds for them. */
103
+ const UNSCOPED_BACKGROUND_FANOUT_SESSION: object = Object.freeze({});
104
+
105
+ /** Fan-out slots by session (the dispatching session's `SessionCache`
106
+ * identity; WeakMap so a dropped session releases its key together with
107
+ * the cache instance). A slot is RESERVED in the same synchronous block
108
+ * as the ceiling check inside `dispatchAgent` — concurrent dispatches
109
+ * that interleave at the async definition-resolution awaits cannot all
110
+ * pass the check before any of them registers — and RELEASED when the
111
+ * registered task reaches a terminal state (done/error/aborted) via
112
+ * `globalAgentRegistry.onTaskDone`. A dispatch that throws before it
113
+ * registers releases its own reservation (see
114
+ * `releaseReservedFanoutSlot` inside `dispatchAgent`). */
115
+ const backgroundFanoutSlots = new WeakMap<object, number>();
116
+
117
+ /** Count this session's live fan-out slots (reserved or running). */
118
+ export function countSessionBackgroundFanout(session: object): number {
119
+ return backgroundFanoutSlots.get(session) ?? 0;
120
+ }
121
+
122
+ /** Release one of this session's fan-out slots (floors at zero). */
123
+ function releaseBackgroundFanoutSlot(session: object): void {
124
+ const live = backgroundFanoutSlots.get(session);
125
+ if (live === undefined || live <= 1) backgroundFanoutSlots.delete(session);
126
+ else backgroundFanoutSlots.set(session, live - 1);
127
+ }
128
+
98
129
  /** Fallback agent when subagent_type is missing or unresolvable. The
99
130
  * loader picks this up from src/agents/general-purpose.md — built
100
131
  * inline below as a defensive default in case that file is removed. */
@@ -374,19 +405,22 @@ export async function dispatchAgent(
374
405
  // burn another turn on the same work. Return a stub that points
375
406
  // the parent back to its existing history. Parents stuck in a
376
407
  // "keep re-spawning Data Collector" loop escape via this gate.
377
- if (opts.sessionCache) {
378
- const key = agentCacheKey(requestedType, requestedType, prompt);
408
+ const sessionCache = opts.sessionCache;
409
+ const cacheKey = sessionCache
410
+ ? agentCacheKey(requestedType, requestedType, prompt)
411
+ : undefined;
412
+ if (sessionCache && cacheKey) {
379
413
  // Key strategy: description is noisy (parents sometimes vary the
380
414
  // label between calls); we hash the FUNCTIONAL signature only
381
415
  // — subagent_type + prompt. Same prompt to same agent = same
382
416
  // expected work, regardless of how the call was labelled.
383
- const hit = opts.sessionCache.check(key);
417
+ const hit = sessionCache.check(cacheKey);
384
418
  if (hit) {
385
419
  const label = `Agent[${requestedType}] "${description.slice(0, 60)}"`;
386
420
  logDedupHit('agent.dedup', label, hit, {
387
421
  requestedType,
388
422
  description: description.slice(0, 80),
389
- consecutive: opts.sessionCache.consecutiveHits,
423
+ consecutive: sessionCache.consecutiveHits,
390
424
  });
391
425
 
392
426
  // Runtime-level block: same treatment as Read. When the parent
@@ -395,16 +429,16 @@ export async function dispatchAgent(
395
429
  // tool_result carries is_error=true. Soft stubs have been
396
430
  // observed to produce 6+ retries in the wild; an error break
397
431
  // the reflex loop more reliably.
398
- if (opts.sessionCache.consecutiveHits >= CONSECUTIVE_DEDUP_BLOCK_THRESHOLD) {
432
+ if (sessionCache.consecutiveHits >= CONSECUTIVE_DEDUP_BLOCK_THRESHOLD) {
399
433
  debug.log('agent.dedup', 'consecutive-block', {
400
434
  requestedType,
401
435
  description: description.slice(0, 80),
402
- consecutive: opts.sessionCache.consecutiveHits,
436
+ consecutive: sessionCache.consecutiveHits,
403
437
  threshold: CONSECUTIVE_DEDUP_BLOCK_THRESHOLD,
404
438
  });
405
439
  throw new Error(
406
440
  `RUNTIME BLOCKED — Agent[${requestedType}] "${description.slice(0, 60)}" ` +
407
- `has been spawned ${opts.sessionCache.consecutiveHits} times in a row with ` +
441
+ `has been spawned ${sessionCache.consecutiveHits} times in a row with ` +
408
442
  `no intervening progress. The previous sub-agent's final message is in ` +
409
443
  `your conversation history above — use that. Spawn an Agent with a ` +
410
444
  `DIFFERENT persona (different subagent_type or a substantively different ` +
@@ -420,9 +454,9 @@ export async function dispatchAgent(
420
454
  // ~500 chars of history noise per hit. We now emit the debug
421
455
  // event past threshold for traceability but return the normal
422
456
  // "spawn a different persona" stub — same message every hit.
423
- if (opts.sessionCache.totalHits >= DEDUP_CASCADE_HALT_THRESHOLD) {
457
+ if (sessionCache.totalHits >= DEDUP_CASCADE_HALT_THRESHOLD) {
424
458
  debug.log('agent.dedup', 'cascade-threshold', {
425
- totalHits: opts.sessionCache.totalHits,
459
+ totalHits: sessionCache.totalHits,
426
460
  threshold: DEDUP_CASCADE_HALT_THRESHOLD,
427
461
  requestedType,
428
462
  description: description.slice(0, 80),
@@ -444,7 +478,79 @@ export async function dispatchAgent(
444
478
  taskId: 'dedup',
445
479
  };
446
480
  }
447
- opts.sessionCache.noteSeen(key, `Agent[${requestedType}] ${description.slice(0, 60)}`);
481
+ }
482
+
483
+ // ── TUI-AGENT-CAPS-FU: background fan-out ceiling ──
484
+ //
485
+ // The ONE enforcement point for AGENT_TOOL_BACKGROUND_FANOUT_CEILING, and
486
+ // it sits exactly between the dedup short-circuit above and `noteSeen`
487
+ // below on purpose:
488
+ // • after dedup — a repeat of an already-answered prompt still gets the
489
+ // dedup stub instead of a fan-out refusal (it never reaches here);
490
+ // • before `noteSeen` — a refused launch must NOT register its cache
491
+ // key. Otherwise the caller's retry (same prompt, once a slot opens)
492
+ // would be answered with "you already got this result" even though no
493
+ // child ever ran, permanently poisoning the cache with a spawn that
494
+ // never happened.
495
+ //
496
+ // Live slots are counted over the shared task ledger: `background` tasks
497
+ // that have not reached a terminal state (done / error / aborted). So a
498
+ // slot re-opens the moment any background agent finishes, which is what
499
+ // lets the next launch through again.
500
+ let fanoutSession: object | undefined;
501
+ if (runInBackground) {
502
+ // Per-session scope: slots count against THIS session's cache
503
+ // identity (shared fallback bucket for cache-less callers), so a
504
+ // busy OTHER session cannot starve this one's first launch.
505
+ fanoutSession = opts.sessionCache ?? UNSCOPED_BACKGROUND_FANOUT_SESSION;
506
+ const liveBackground = countSessionBackgroundFanout(fanoutSession);
507
+ if (liveBackground >= AGENT_TOOL_BACKGROUND_FANOUT_CEILING) {
508
+ debug.log('agent.spawn', 'background-fanout-limit', {
509
+ cid: debugCorrelationId,
510
+ requestedType,
511
+ description: description.slice(0, 80),
512
+ liveBackground,
513
+ ceiling: AGENT_TOOL_BACKGROUND_FANOUT_CEILING,
514
+ }, { level: 'warn' });
515
+ // Not spawned: no registry task, no provider call, no cache entry.
516
+ // taskId is a sentinel (like 'dedup' above) so a caller can tell a
517
+ // refusal from a real spawn without parsing the prose.
518
+ return {
519
+ output:
520
+ `NOT SPAWNED — ${liveBackground} background agents are already live and the ` +
521
+ `fan-out ceiling is ${AGENT_TOOL_BACKGROUND_FANOUT_CEILING}. A slot reopens as ` +
522
+ `soon as one of them reaches a terminal state (done/error/aborted); its result ` +
523
+ `then arrives as a task-notification. Either wait for one to finish, fold this ` +
524
+ `work into an existing background spawn, or re-issue it without ` +
525
+ `run_in_background so it runs in the foreground.`,
526
+ agent: requestedType,
527
+ cid: debugCorrelationId,
528
+ durationMs: 0,
529
+ maxTurns: requestedMaxTurns,
530
+ taskId: 'background-fanout-limit',
531
+ };
532
+ }
533
+ }
534
+
535
+ if (fanoutSession !== undefined) {
536
+ // Atomic reservation: taken in the SAME synchronous block as the
537
+ // ceiling check above, before any await — concurrent dispatches
538
+ // cannot all pass the check and push this session past the ceiling
539
+ // while their definitions resolve. Released when the registered
540
+ // task terminals (see the onTaskDone subscription at spawn); a
541
+ // dispatch that throws before registering releases it in the finally
542
+ // below, including failures from definition resolution and lazy imports.
543
+ backgroundFanoutSlots.set(fanoutSession, countSessionBackgroundFanout(fanoutSession) + 1);
544
+ }
545
+ const releaseReservedFanoutSlot = (): void => {
546
+ if (fanoutSession === undefined) return;
547
+ releaseBackgroundFanoutSlot(fanoutSession);
548
+ fanoutSession = undefined;
549
+ };
550
+
551
+ try {
552
+ if (sessionCache && cacheKey) {
553
+ sessionCache.noteSeen(cacheKey, `Agent[${requestedType}] ${description.slice(0, 60)}`);
448
554
  }
449
555
 
450
556
  // Resolve the agent definition. Try the 4-layer resolver first;
@@ -536,7 +642,9 @@ export async function dispatchAgent(
536
642
  });
537
643
  } catch (error) {
538
644
  const message = error instanceof Error ? error.message : String(error);
539
- if (!message.includes('is not inside a git repo')) throw error;
645
+ if (!message.includes('is not inside a git repo')) {
646
+ throw error;
647
+ }
540
648
  childCwd = opts.cwd ?? getSessionCwd();
541
649
  appliedIsolation = 'cwd';
542
650
  debug.log('agent.spawn', 'worktree-fallback-cwd', {
@@ -679,6 +787,19 @@ export async function dispatchAgent(
679
787
  ...(runInBackground ? { background: true } : {}),
680
788
  });
681
789
 
790
+ // Terminal release for this dispatch's reserved fan-out slot: the
791
+ // registry fires this exactly once per task when it reaches a
792
+ // terminal state (done/error/aborted); until then the slot counts as
793
+ // occupied against this session's ceiling above.
794
+ if (fanoutSession !== undefined) {
795
+ const fanoutSlotSession = fanoutSession;
796
+ const fanoutSlotSubscription = globalAgentRegistry.onTaskDone((task) => {
797
+ if (!task || task.id !== handle.task.id) return;
798
+ fanoutSlotSubscription.dispose();
799
+ releaseBackgroundFanoutSlot(fanoutSlotSession);
800
+ });
801
+ fanoutSession = undefined; // the terminal subscription owns the release now
802
+ }
682
803
  // Forward parent abort to the spawned task. The registry owns the
683
804
  // child's controller; we just chain ours into it.
684
805
  if (opts.signal) {
@@ -907,4 +1028,9 @@ export async function dispatchAgent(
907
1028
  ...(childCwd ? { cwd: childCwd } : {}),
908
1029
  ...(appliedIsolation ? { isolation: appliedIsolation } : {}),
909
1030
  };
1031
+ } finally {
1032
+ // The registered task owns its slot after the handoff above. Every
1033
+ // pre-registration throw leaves fanoutSession set and releases it here.
1034
+ releaseReservedFanoutSlot();
1035
+ }
910
1036
  }
@@ -0,0 +1,100 @@
1
+ import type { LLMToolSpec } from '../../llm.js';
2
+ import { openMsgStore, validateMessageEnvelope, type Message, type MsgStore } from '../../msg/msg-store.js';
3
+
4
+ export interface MsgAskDeps {
5
+ openStore?: () => MsgStore;
6
+ sleep?: (ms: number) => Promise<void>;
7
+ monotonicNow?: () => number;
8
+ wallNow?: () => number;
9
+ signal?: AbortSignal;
10
+ }
11
+
12
+ export interface MsgAskResult extends Record<string, unknown> {
13
+ output: string;
14
+ ok: boolean;
15
+ question: Message;
16
+ reply: Message | null;
17
+ }
18
+
19
+ export function buildMsgAskTool(): LLMToolSpec {
20
+ return {
21
+ name: 'MsgAsk',
22
+ description: 'Post a durable seat question, then wait for the first message whose replyTo points to it. A timeout or cancellation keeps the posted question and returns its ID for later follow-up.',
23
+ parameters: {
24
+ type: 'object',
25
+ properties: {
26
+ from: { type: 'string', description: 'Asking seat (ALL cannot send).' },
27
+ to: { type: 'string', description: 'Recipient seat.' },
28
+ question: { type: 'string', description: 'Nonempty question body.' },
29
+ waitSeconds: { type: 'integer', description: 'Wait 0–300 seconds; default 60.' },
30
+ },
31
+ required: ['from', 'to', 'question'],
32
+ additionalProperties: false,
33
+ },
34
+ };
35
+ }
36
+
37
+ export async function dispatchMsgAsk(rawArgs: Record<string, unknown>, deps: MsgAskDeps = {}): Promise<MsgAskResult> {
38
+ const waitRaw = rawArgs.waitSeconds ?? 60;
39
+ if (typeof waitRaw !== 'number' || !Number.isSafeInteger(waitRaw) || waitRaw < 0 || waitRaw > 300) {
40
+ throw new Error("'waitSeconds' must be an integer between 0 and 300");
41
+ }
42
+ const envelope = validateMessageEnvelope({
43
+ from: rawArgs.from,
44
+ to: rawArgs.to,
45
+ body: rawArgs.question,
46
+ });
47
+ if (envelope.to === 'ALL') throw new Error("'to' must name one recipient seat for MsgAsk");
48
+ const monotonicNow = deps.monotonicNow ?? (() => performance.now());
49
+ const wallNow = deps.wallNow ?? Date.now;
50
+ const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
51
+ const store = deps.openStore?.() ?? openMsgStore();
52
+ try {
53
+ if (deps.signal?.aborted) throw new Error('ask cancelled before posting');
54
+ const question = store.post(envelope);
55
+ const startedAt = monotonicNow();
56
+ const wallStartedAt = wallNow();
57
+ const deadline = startedAt + waitRaw * 1000;
58
+ const wallDeadline = Date.parse(question.createdAt) + waitRaw * 1000;
59
+ // Ledger timestamps are wall time while the wait budget is monotonic.
60
+ // If the two clocks diverge materially, preserve the question ID and
61
+ // make the uncertain result explicit instead of accepting a late reply.
62
+ const clockAdjusted = () => Math.abs((wallNow() - wallStartedAt) - (monotonicNow() - startedAt)) > 250;
63
+ let afterId = 0;
64
+ do {
65
+ if (deps.signal?.aborted) {
66
+ return { output: `MsgAsk #${question.id} posted; wait cancelled`, ok: false, question, reply: null };
67
+ }
68
+ if (clockAdjusted()) {
69
+ return { output: `MsgAsk #${question.id} posted; clock adjusted during wait, inspect linked replies`, ok: false, question, reply: null };
70
+ }
71
+ const replies = store.listReplies(question.id, 1000, afterId);
72
+ if (clockAdjusted()) {
73
+ return { output: `MsgAsk #${question.id} posted; clock adjusted during wait, inspect linked replies`, ok: false, question, reply: null };
74
+ }
75
+ for (const reply of replies) {
76
+ afterId = reply.id;
77
+ // A replyTo link alone does not prove the intended seat answered.
78
+ // A wall-clock timestamp can move backwards by less than the clock
79
+ // adjustment guard. Never accept a reply once monotonic time expired.
80
+ // This conservatively leaves replies observed late for follow-up.
81
+ if (reply.from === question.to && reply.to === question.from
82
+ && monotonicNow() <= deadline && Date.parse(reply.createdAt) <= wallDeadline) {
83
+ return { output: `MsgAsk #${question.id} → reply #${reply.id}: ${reply.body}`, ok: true, question, reply };
84
+ }
85
+ }
86
+ const remaining = deadline - monotonicNow();
87
+ if (deps.signal?.aborted) {
88
+ return { output: `MsgAsk #${question.id} posted; wait cancelled`, ok: false, question, reply: null };
89
+ }
90
+ if (remaining <= 0) {
91
+ return { output: `MsgAsk #${question.id} posted; no linked reply within ${waitRaw}s`, ok: false, question, reply: null };
92
+ }
93
+ // A full page may repeat forever. Yield so timers and AbortSignal
94
+ // callbacks can run before asking SQLite for the next page.
95
+ await sleep(replies.length === 1000 ? 0 : Math.min(100, remaining));
96
+ } while (true);
97
+ } finally {
98
+ store.close();
99
+ }
100
+ }
@@ -3,7 +3,7 @@
3
3
  // OP TUI turns previously drove `elanous msg list/post/ack` and
4
4
  // `elanous release checklist list/move/set/add` through RunShell:
5
5
  // 1.3–2s of CLI startup per call, 30+ spawns per turn, and the CLI's
6
- // human-oriented stdout amplifying TUI screen defects. These eight
6
+ // human-oriented stdout amplifying TUI screen defects. These
7
7
  // tools reuse the SAME durable services in-process —
8
8
  //
9
9
  // • msg tools → src/msg/msg-store.ts (the SQLite ledger `elanous msg`
@@ -11,6 +11,7 @@
11
11
  // • checklist tools → src/release-loop/checklist.ts + feature-store.ts
12
12
  // (the same per-version ledger, claim history, seat/OP move rules)
13
13
  //
14
+ // MsgAsk joins this family through msg-ask.ts; the other dispatchers live here.
14
15
  // The permission and audit contract is preserved 1:1:
15
16
  // • writes record the actor from ELANOUS_TRACK (seat identity),
16
17
  // • ChecklistMove keeps the CLI routing — anonymous (no ELANOUS_TRACK)
@@ -41,6 +41,17 @@ export const WAKEUP_MAX_CALLS_PER_TURN = 6;
41
41
  export const WAKEUP_REPEAT_INVALID_ERROR =
42
42
  'repeatMinutes 는 반복 간격(분 · 1 이상)이다 — 한 번만 깨우려면 repeatMinutes 를 빼거나 0 으로 두고 delaySeconds 또는 at 만 줘라';
43
43
 
44
+ function formatWakeupTimeConflictError(req: ScheduleWakeupRequest): string {
45
+ const corrected = { ...req };
46
+ delete corrected.at;
47
+ delete corrected.atProvided;
48
+ return `at 과 delaySeconds 는 둘 중 하나만 줄 수 있다 — 교정 인자 예시(at 을 빼고 delaySeconds 사용): ${JSON.stringify(corrected)}. 같은 인자를 다시 보내지 말고 이 교정 인자로 한 번만 재시도하라`;
49
+ }
50
+
51
+ function canonicalToolArgs(args: Record<string, unknown>): string {
52
+ return JSON.stringify(Object.fromEntries(Object.entries(args).sort(([a], [b]) => a.localeCompare(b))));
53
+ }
54
+
44
55
  export type WakeupTimerHandle = unknown;
45
56
 
46
57
  export interface WakeupEntry {
@@ -79,7 +90,9 @@ export interface WakeupSchedulerDeps {
79
90
 
80
91
  export type ScheduleWakeupRequest = {
81
92
  /** «HH:MM»(로컬 시각 · 지났으면 내일). delaySeconds 와 둘 중 하나. */
82
- at?: string;
93
+ at?: unknown;
94
+ /** Host tool must preserve property presence even when the provider sent a non-string value. */
95
+ atProvided?: boolean;
83
96
  delaySeconds?: number;
84
97
  reason: string;
85
98
  /** 반복 간격(분). 첫 발화는 at/delaySeconds — 둘 다 없으면 지금부터 repeatMinutes 뒤. 0 = 일회성(생략과 같다). */
@@ -93,7 +106,7 @@ export type ScheduleWakeupResult =
93
106
  export type CancelWakeupResult = { ok: true } | { ok: false; error: string; capped?: boolean };
94
107
 
95
108
  export interface WakeupScheduler {
96
- schedule(req: ScheduleWakeupRequest): ScheduleWakeupResult;
109
+ schedule(req: ScheduleWakeupRequest, requestKey?: string): ScheduleWakeupResult;
97
110
  list(): WakeupEntry[];
98
111
  cancel(id: string): boolean;
99
112
  /** cancel 과 같되 거부 사유(없는 id · 턴 상한)를 값으로 낸다 — LLM 도구가 쓴다. */
@@ -151,12 +164,24 @@ export function createWakeupScheduler(deps: WakeupSchedulerDeps): WakeupSchedule
151
164
  const maxCallsPerTurn = deps.maxCallsPerTurn ?? WAKEUP_MAX_CALLS_PER_TURN;
152
165
  let callTurnKey: string | null = null;
153
166
  let callCount = 0;
167
+ const conflictErrors = new Map<string, string>();
168
+
169
+ const readTurnId = (): string | null => deps.currentTurnId?.() ?? null;
154
170
 
155
- /** 한 턴 호출 상한 — 넘었으면 거부 문구, 아니면 null. 턴 경계를 모르면(currentTurnId 없음) 걸지 않는다. */
156
- const loopCapError = (action: 'schedule' | 'cancel'): string | null => {
157
- if (!deps.currentTurnId) return null;
158
- const turnId = deps.currentTurnId() ?? 'none';
159
- if (turnId !== callTurnKey) { callTurnKey = turnId; callCount = 0; }
171
+ /** 한 턴 호출 상한 — 넘었으면 거부 문구, 아니면 null. 턴 경계가 unknown 이면 cap·dedupe 상태를 버린다. */
172
+ const loopCapError = (action: 'schedule' | 'cancel', observedTurnId = readTurnId()): string | null => {
173
+ if (observedTurnId === null) {
174
+ callTurnKey = null;
175
+ callCount = 0;
176
+ conflictErrors.clear();
177
+ return null;
178
+ }
179
+ const turnId = observedTurnId;
180
+ if (turnId !== callTurnKey) {
181
+ callTurnKey = turnId;
182
+ callCount = 0;
183
+ conflictErrors.clear();
184
+ }
160
185
  callCount += 1;
161
186
  if (callCount <= maxCallsPerTurn) return null;
162
187
  log('tui.wakeup', 'loop-capped', { turnId, count: callCount, max: maxCallsPerTurn, action });
@@ -252,20 +277,35 @@ export function createWakeupScheduler(deps: WakeupSchedulerDeps): WakeupSchedule
252
277
  };
253
278
 
254
279
  return {
255
- schedule(req) {
280
+ schedule(req, requestKey) {
256
281
  const t = now();
257
282
  const reason = (req.reason ?? '').replace(/\s+/g, ' ').trim();
258
283
  const reject = (error: string): ScheduleWakeupResult => {
259
284
  log('tui.wakeup', 'rejected', { id: null, reason: 'invalid', error });
260
285
  return { ok: false, error };
261
286
  };
262
- const capped = loopCapError('schedule');
287
+ // Every schedule attempt consumes the per-turn budget before validation.
288
+ const turnId = readTurnId();
289
+ const capped = loopCapError('schedule', turnId);
263
290
  if (capped) return { ok: false, error: capped };
291
+ // Presence is the contract: invalidly typed `at` values from the host
292
+ // must still conflict with delaySeconds rather than silently disappear.
293
+ const hasAt = req.atProvided ?? req.at !== undefined;
294
+ const hasDelay = req.delaySeconds !== undefined;
295
+ if (hasAt && hasDelay) {
296
+ const key = requestKey ?? canonicalToolArgs(req as Record<string, unknown>);
297
+ if (turnId !== null) {
298
+ const previousError = conflictErrors.get(key);
299
+ if (previousError !== undefined) {
300
+ return { ok: false, error: `${previousError} — 같은 충돌 인자의 재시도는 억제했다` };
301
+ }
302
+ if (conflictErrors.size < maxCallsPerTurn) conflictErrors.set(key, formatWakeupTimeConflictError(req));
303
+ }
304
+ const error = formatWakeupTimeConflictError(req);
305
+ return reject(error);
306
+ }
264
307
  if (!reason) return reject('reason 이 비었다 — 깨어나서 무엇을 할지 한 줄로 적어라');
265
308
  if (entries.size >= maxEntries) return reject(`예약 상한 ${maxEntries}개 — list 로 보고 cancel 뒤 다시`);
266
- const hasAt = typeof req.at === 'string' && req.at.trim() !== '';
267
- const hasDelay = typeof req.delaySeconds === 'number';
268
- if (hasAt && hasDelay) return reject('at 과 delaySeconds 는 둘 중 하나만');
269
309
  let repeatMs: number | undefined;
270
310
  // ⭐ 0 = 일회성(생략과 같다) — 모델이 «한 번만»을 0 으로 부른다(라이브 실측). 음수·NaN·1 미만 소수는 거부.
271
311
  if (req.repeatMinutes !== undefined && req.repeatMinutes !== 0) {
@@ -276,7 +316,8 @@ export function createWakeupScheduler(deps: WakeupSchedulerDeps): WakeupSchedule
276
316
  }
277
317
  let dueAt: number;
278
318
  if (hasAt) {
279
- const resolved = resolveWakeupAt(req.at!, t);
319
+ if (typeof req.at !== 'string') return reject(`at 은 «HH:MM» 문자열이어야 한다 — 받은 값 ${JSON.stringify(req.at)}`);
320
+ const resolved = resolveWakeupAt(req.at, t);
280
321
  if (resolved === null) return reject(`at 은 «HH:MM»(24시간) 꼴 — 받은 값 ${JSON.stringify(req.at)}`);
281
322
  dueAt = resolved;
282
323
  } else if (hasDelay) {
@@ -342,7 +383,7 @@ export function buildScheduleWakeupHostTool(scheduler: WakeupScheduler): LLMTool
342
383
  name: SCHEDULE_WAKEUP_TOOL_NAME,
343
384
  description:
344
385
  'Wake THIS TUI later with an internal turn: when you would write «다음 점검 HH:MM» and end the turn, call this instead so the check actually happens. '
345
- + 'action=schedule (default) needs reason plus one of at ("HH:MM" local, past → tomorrow) / delaySeconds (≥60) / repeatMinutes (≥1; repeats expire after 7 days). '
386
+ + 'action=schedule (default) needs reason plus one of at ("HH:MM" local, past → tomorrow) / delaySeconds (≥60) / repeatMinutes (≥1; repeats expire after 7 days). Never provide both at and delaySeconds; the schema requires one timing variant. '
346
387
  + 'ONE-SHOT (wake once): give only delaySeconds or at and OMIT repeatMinutes (0 also means one-shot). Set repeatMinutes only when you really want it to repeat. '
347
388
  + `action=list shows pending wakeups; action=cancel needs id. Limits: ≥60s ahead, ≤7 days, at most 5 pending, at most ${WAKEUP_MAX_CALLS_PER_TURN} schedule/cancel calls per turn. `
348
389
  + 'If the TUI is busy or the human is typing at that time it retries once a minute later, then gives up (repeats move to the next tick). '
@@ -358,6 +399,11 @@ export function buildScheduleWakeupHostTool(scheduler: WakeupScheduler): LLMTool
358
399
  id: { type: 'string', description: 'Wakeup id for action=cancel (from schedule/list).' },
359
400
  },
360
401
  required: [],
402
+ oneOf: [
403
+ { not: { anyOf: [{ required: ['at'] }, { required: ['delaySeconds'] }] } },
404
+ { required: ['at'], not: { required: ['delaySeconds'] } },
405
+ { required: ['delaySeconds'], not: { required: ['at'] } },
406
+ ],
361
407
  },
362
408
  handler: async (args) => {
363
409
  const action = typeof args.action === 'string' ? args.action : 'schedule';
@@ -368,12 +414,15 @@ export function buildScheduleWakeupHostTool(scheduler: WakeupScheduler): LLMTool
368
414
  return r.ok ? { cancelled: id } : { error: r.error };
369
415
  }
370
416
  if (action !== 'schedule') return { error: `unknown action ${JSON.stringify(action)}` };
371
- const result = scheduler.schedule({
417
+ const atProvided = Object.prototype.hasOwnProperty.call(args, 'at');
418
+ const request: ScheduleWakeupRequest = {
372
419
  reason: typeof args.reason === 'string' ? args.reason : '',
373
- ...(typeof args.at === 'string' ? { at: args.at } : {}),
420
+ atProvided,
421
+ ...(atProvided ? { at: args.at } : {}),
374
422
  ...(typeof args.delaySeconds === 'number' ? { delaySeconds: args.delaySeconds } : {}),
375
423
  ...(typeof args.repeatMinutes === 'number' ? { repeatMinutes: args.repeatMinutes } : {}),
376
- });
424
+ };
425
+ const result = scheduler.schedule(request, canonicalToolArgs(args));
377
426
  return result.ok ? { scheduled: describeEntry(result.entry) } : { error: result.error };
378
427
  },
379
428
  };
@@ -5,7 +5,7 @@ import { opSeatStatePath, readTrafficSignal } from '../seat-loop/traffic-signal.
5
5
 
6
6
  const SEATS = ['OP', 'MK', 'TC', 'UX'] as const;
7
7
  type Seat = typeof SEATS[number];
8
- export type HygieneCell = { id: string; owner?: string | null; status: string };
8
+ export type HygieneCell = { id: string; owner?: string | null; status: string; title?: string };
9
9
  export type HygieneNotice = { to: Seat; key: string; body: string };
10
10
  export type HygieneDeps = {
11
11
  root: string;
@@ -45,7 +45,7 @@ export function starvingCycles(log: string): { reasons: Record<string, number> }
45
45
  return { reasons };
46
46
  }
47
47
 
48
- type HoldMeta = { id?: unknown; op?: unknown; reason?: unknown; until?: unknown };
48
+ type HoldMeta = { id?: unknown; op?: unknown; reason?: unknown; until?: unknown; kind?: unknown; confirmedAt?: unknown; at?: unknown; title?: unknown };
49
49
  function holdMetadata(path: string): Map<string, HoldMeta> {
50
50
  const latest = new Map<string, HoldMeta>();
51
51
  for (const line of (readOptional(path) ?? '').split(/\r?\n/)) {
@@ -65,6 +65,10 @@ function untilTime(value: unknown): number | null {
65
65
  return Number.isFinite(time) ? time : null;
66
66
  }
67
67
 
68
+ function confirmedTime(value: unknown): number | null {
69
+ return typeof value === 'string' && /^\d{12}$/.test(value) ? untilTime(value) : null;
70
+ }
71
+
68
72
  export function inspectHoldHygiene(deps: HygieneDeps): HygieneNotice[] {
69
73
  const notices: HygieneNotice[] = [];
70
74
  const dir = deps.dispatcherDir ?? opSeatStatePath('feeder');
@@ -88,11 +92,25 @@ export function inspectHoldHygiene(deps: HygieneDeps): HygieneNotice[] {
88
92
  if (!SEATS.some(seat => seat === owner)) continue;
89
93
  const meta = metadata.get(cell.id);
90
94
  const reason = meta?.op === 'add' && typeof meta.reason === 'string' ? meta.reason.trim() : '';
91
- const expiry = untilTime(meta?.until);
92
- const expired = typeof meta?.until === 'string' && meta.until.trim() !== '' && (expiry === null || expiry <= deps.now.getTime());
93
- if (reason && !expired) continue;
95
+ let attention = '';
96
+ if (meta?.kind === '손작업') {
97
+ const confirmed = confirmedTime(meta.confirmedAt ?? meta.at);
98
+ if (confirmed === null) attention = '재확인 시각 없음';
99
+ else if (deps.now.getTime() - confirmed >= 24 * 60 * 60_000) attention = '24h 재확인 지연';
100
+ } else if (meta?.kind === '재발사금지') {
101
+ if (typeof meta.title !== 'string' || !meta.title || typeof cell.title !== 'string' || !cell.title) attention = '제목 기준 확인 불가';
102
+ else if (cell.title !== meta.title) attention = '칸 제목 변경';
103
+ } else if (meta?.kind === '선행대기' || meta?.kind === undefined || meta?.kind === '') {
104
+ const expiry = untilTime(meta?.until);
105
+ if (expiry === null) attention = 'until 확인 불가';
106
+ else if (expiry <= deps.now.getTime()) attention = `until ${String(meta?.until)} 지남`;
107
+ } else attention = 'hold 종류 확인 불가';
108
+ if (reason && !attention) continue;
109
+ const guidance = meta?.kind === '손작업' ? '재확인 시각·사유를 판단해 OP에 알려 주세요.'
110
+ : meta?.kind === '재발사금지' ? '칸 제목과 기준 제목·사유를 대조해 OP에 알려 주세요.'
111
+ : '풀기/유지(사유·until)를 판단해 OP에 알려 주세요.';
94
112
  notices.push({ to: owner as Seat, key: `hold:${cell.id}:${owner}`,
95
- body: `노랑 칸 ${cell.id} traffic hold: ${!reason ? '사유 없음' : `사유 ${reason}`} ${expired ? `· until ${String(meta?.until)} 지남` : ''}. 풀기/유지(사유·until)를 판단해 OP에 알려 주세요. 자동 해제하지 않습니다.` });
113
+ body: `노랑 칸 ${cell.id} traffic hold: ${!reason ? '사유 없음' : `사유 ${reason}`} ${attention ? `· ${attention}` : ''}. ${guidance} 자동 해제하지 않습니다.` });
96
114
  }
97
115
  return notices;
98
116
  }
@@ -15,16 +15,19 @@ export interface ReleaseDayDecision {
15
15
  reason?: string;
16
16
  }
17
17
 
18
- /** The release record, rather than publishAt (a planned time), opens green-back. */
18
+ /** Green-back waits for both the scheduled publish end and the actual publication record. */
19
19
  export function decideReleaseDayPhase(schedule: ReleaseSchedule, now: Date, publishedAt: string | null): ReleaseDayDecision {
20
20
  const cut = Date.parse(schedule.cutAt);
21
21
  const land = schedule.landBy ? Date.parse(schedule.landBy) : cut;
22
22
  const gate = cut - 30 * 60_000;
23
23
  const time = now.getTime();
24
+ const published = publishedAt ? Date.parse(publishedAt) : Number.NaN;
25
+ const publishEnd = schedule.publishAt ? Date.parse(schedule.publishAt) : published;
26
+ const greenAt = Number.isFinite(published) && Number.isFinite(publishEnd) ? Math.max(published, publishEnd) : Number.NaN;
24
27
  let phase: ReleaseDayPhase = 'none';
25
28
  let dueAt: string | null = null;
26
- if (publishedAt && time >= Date.parse(publishedAt)) {
27
- phase = 'green-back'; dueAt = publishedAt;
29
+ if (time >= greenAt) {
30
+ phase = 'green-back'; dueAt = publishEnd >= published ? schedule.publishAt ?? publishedAt : publishedAt;
28
31
  } else if (time >= cut) {
29
32
  phase = 'cut-run'; dueAt = schedule.cutAt;
30
33
  } else if (time >= land) {
@@ -133,6 +136,7 @@ export function runReleaseDayShadow(deps: ReleaseDayShadowDeps = {}): ReleaseDay
133
136
  continue;
134
137
  }
135
138
  const publishedAt = publication.kind === 'published' ? publication.at : null;
139
+ // The steward graph tick records this judgment only; release CLI actions remain outside this shadow boundary.
136
140
  const decision = decideReleaseDayPhase(schedule, now, publishedAt);
137
141
  let recorded = false;
138
142
  if (decision.phase !== 'none') {