elanous 0.2.34 → 0.2.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (611) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{5014f970-22bef0b5210f7d60.js → 0368f25d-ad84af92fefee68f.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/{2124.ed5bf480cea7f85b.js → 1530.0e612369b6fd7ea0.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +41 -0
  9. package/apps/pwa/out/_next/static/chunks/1674.2a65fd5668e1cc5f.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +24 -0
  11. package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +74 -0
  12. package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.js → 2018.a741297bce759490.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +148 -0
  23. package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +34 -0
  25. package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +77 -0
  26. package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +62 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +90 -0
  31. package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{1644.35dd25240ae24e4b.js → 3408.21d1570602f4b6c0.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{3121.779fafe3e44612c5.js → 3589.5444a06bcf6e775c.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/359-2250789a2d3499e7.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{9131-fce7256c4180c4a5.js → 3677-4215f826f6aa68e5.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +79 -0
  40. package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +122 -0
  42. package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4346.8601952e73bf5803.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/{6053-d893974de92e6198.js → 4441-875b97f5821ed58a.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +286 -0
  46. package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +24 -0
  49. package/apps/pwa/out/_next/static/chunks/{1895-60ed0e341c658bd4.js → 4705-194e64e47ca0fbdb.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.js → 4718-17d2af636796a330.js} +3 -3
  51. package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{7431.3051e9b8a4372d2d.js → 5101.e32282718f99ed6f.js} +2 -2
  57. package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +23 -0
  61. package/apps/pwa/out/_next/static/chunks/{2987-30cf9c2eb7b8bdd5.js → 5483-dd5d7697f6bdb106.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +94 -0
  63. package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/56d372f2.681ab4ec4c998fae.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/{7386.5d8e7e42e818dfb6.js → 5852.db1f7449f4f74612.js} +2 -2
  67. package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/{3110.0a7065f25c841818.js → 6236.e18cced2d5ba6afb.js} +3 -3
  74. package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +8 -0
  75. package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +27 -0
  78. package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +93 -0
  80. package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +149 -0
  87. package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +104 -0
  88. package/apps/pwa/out/_next/static/chunks/{7005.1623d2aea78eb85f.js → 7385.50a308a477bdfc21.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.js → 7644.17e37ba6f1d4226e.js} +4 -4
  90. package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{7193-cf355cca5ba6c5d5.js → 8437-8d5492094b166cfa.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/{2554.3b5e200f5f5cfcd6.js → 8444.4c26b379ca2b9596.js} +4 -4
  100. package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +226 -0
  101. package/apps/pwa/out/_next/static/chunks/8557-e7898769499cd56f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +64 -0
  104. package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{2547.dd27303624cb4da8.js → 8637.47f5b35afcae5e6b.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{9550.d5f76828f972058c.js → 9214.63a510d39178e997.js} +2 -2
  111. package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +115 -0
  112. package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{8548.036c344973968847.js → 938.66ad1ef0e5abae1c.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/{3414.172ad4ca2d9b08e8.js → 9512.5a76207a730e0491.js} +2 -2
  115. package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{6740.43de73fc427c9fe2.js → 9952.5daf5f94063a2b3e.js} +1 -1
  120. package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/{page-d7bff0f0905a662c.js → page-26e6c18a1a750cf6.js} +1 -1
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-47c5d4db587266bd.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/{page-df3445b207ceceab.js → page-dc0a532f5b9196ec.js} +1 -1
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{9a8cb466.cc9fc9e6e46038aa.js → b2f6ba4d.fb56fdbbf798df33.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/b6705a4f-b9a9047de9eecfd0.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{4fa33ebd.21c1bd5b294496e6.js → cbe38a15.5a032598e39970c6.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{abb4b98b.163e0f56e84ae35d.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.js → da5176c6.6773b6c5994e1d99.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +1 -0
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/bin/elanous.mjs +3 -2
  278. package/catalog/providers/opengateway.yaml +25 -0
  279. package/docs/goal-context/01-goal-authoring-checks.md +8 -0
  280. package/docs/goal-context/03-verification-menu.md +24 -0
  281. package/docs/goal-context/04-mock-scenarios.md +100 -0
  282. package/docs/goal-context/README.md +4 -0
  283. package/graphs/catalog/catalog.yaml +1 -1
  284. package/graphs/default-loop.yaml +57 -3
  285. package/graphs/document-loop.yaml +51 -3
  286. package/graphs/implement-loop.yaml +53 -4
  287. package/graphs/journey/ta-journey.yaml +11 -1
  288. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  289. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  290. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  291. package/graphs/operate-loop.yaml +51 -3
  292. package/graphs/research-loop.yaml +137 -3
  293. package/graphs/test-diet/test-diet.yaml +3 -0
  294. package/package.json +1 -1
  295. package/scripts/coord-role-pack.ts +19 -6
  296. package/scripts/hq/standby-snapshot.ts +17 -12
  297. package/scripts/release-loop/docs-land-node.ts +21 -5
  298. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  299. package/scripts/release-loop/gate-node.ts +181 -22
  300. package/scripts/release-loop/gate-partial.ts +65 -11
  301. package/scripts/release-loop/gate-radius-live.ts +177 -0
  302. package/scripts/release-loop/gate-radius-shadow.ts +1 -1
  303. package/scripts/release-loop/node-verdict.ts +12 -1
  304. package/scripts/release-loop/npm-publish-node.ts +66 -12
  305. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  306. package/scripts/release-loop/pwa-remote.ts +166 -0
  307. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  308. package/scripts/release-loop/resume-release.ts +41 -4
  309. package/scripts/release-loop/unattended-release.ts +2 -0
  310. package/scripts/test-diet/lib.ts +6 -1
  311. package/scripts/test-diet/node.ts +194 -13
  312. package/scripts/ux-sim.ts +39 -0
  313. package/src/agent/self-ambient-cache.ts +8 -0
  314. package/src/agent-substrate/acp-reviewer.ts +39 -4
  315. package/src/agent-substrate/pr-reviewer.ts +17 -0
  316. package/src/agent-substrate/self-review-cli.ts +62 -13
  317. package/src/autopilot/pr-manager.ts +215 -36
  318. package/src/budget/run-usage-rollup.ts +1 -0
  319. package/src/chat/index.ts +0 -2
  320. package/src/chat/pickers/modal-runtime.ts +10 -27
  321. package/src/cli/agent-cli.ts +13 -2
  322. package/src/cli/doctor-cli.ts +4 -1
  323. package/src/cli/light-entry-route.ts +46 -6
  324. package/src/cli/pod-cli.ts +77 -3
  325. package/src/cli/pr-cli.ts +5 -2
  326. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  327. package/src/cli/release-checklist-read-cli.ts +79 -0
  328. package/src/cli/release-cli.ts +72 -102
  329. package/src/cli/remote-resolve.ts +1 -1
  330. package/src/cli/root-tui-entry.ts +48 -0
  331. package/src/cli/sim-cli.ts +22 -0
  332. package/src/cli/tasks-cli.ts +540 -31
  333. package/src/cli/usage-cli.ts +13 -11
  334. package/src/clipboard/history.ts +179 -13
  335. package/src/config.ts +8 -1
  336. package/src/dashboard/chat/acp-chat.ts +8 -0
  337. package/src/dashboard/index.ts +78 -10
  338. package/src/dashboard/render/theme-resolver.ts +33 -4
  339. package/src/domains/schedule-registry.ts +16 -2
  340. package/src/git-fs/idle-refresh.ts +76 -0
  341. package/src/git-fs/index.ts +18 -7
  342. package/src/git-fs/worktree.ts +42 -4
  343. package/src/graph-kinds/registry.ts +2 -2
  344. package/src/graph-runner/runner.ts +153 -10
  345. package/src/grok/credential.ts +10 -3
  346. package/src/harness/harness-cli-command.ts +112 -28
  347. package/src/harness/harness-incidents.ts +33 -0
  348. package/src/harness/launch-utterance-ledger.ts +208 -0
  349. package/src/impl-discipline/detector.ts +16 -4
  350. package/src/impl-discipline/system-prompt.ts +11 -0
  351. package/src/impl-discipline/types.ts +2 -2
  352. package/src/index.ts +496 -143
  353. package/src/intake-plane/already-built-hint.ts +4 -2
  354. package/src/intake-plane/requirement-funnel.ts +29 -1
  355. package/src/light-cli.ts +27 -11
  356. package/src/llm/opengateway-models.ts +11 -0
  357. package/src/llm/provider-credentials.ts +14 -0
  358. package/src/llm/provider-detect.ts +8 -1
  359. package/src/llm/runtime-model-family.ts +2 -1
  360. package/src/llm.ts +213 -56
  361. package/src/model-tier/llm-tier-map.ts +15 -1
  362. package/src/native-tool-catalog.ts +15 -1
  363. package/src/nexus/api/loop-resources.ts +13 -1
  364. package/src/oauth/codex.ts +7 -0
  365. package/src/ops/overview-collect.ts +18 -3
  366. package/src/ops/overview.ts +20 -7
  367. package/src/pr-tool/census.ts +261 -27
  368. package/src/pty-shell/pty-manifest.ts +7 -0
  369. package/src/release-loop/checklist.ts +24 -0
  370. package/src/release-loop/landed-but-yellow.ts +129 -5
  371. package/src/release-loop/light-rc.ts +1 -0
  372. package/src/release-loop/rehearsal.ts +2 -2
  373. package/src/repl/index.ts +174 -17
  374. package/src/repl/ops-msg-bridge.ts +32 -0
  375. package/src/self-dev/ask-launch-flow.ts +44 -5
  376. package/src/self-dev/cli-help-text.ts +17 -0
  377. package/src/self-dev/dev-cli.ts +11 -9
  378. package/src/self-dev/draft-residue.ts +37 -1
  379. package/src/self-dev/draft-sweep.ts +137 -11
  380. package/src/self-dev/draft-triage-rules.ts +107 -0
  381. package/src/self-dev/fleet-reduce.ts +3 -2
  382. package/src/self-dev/graph-front-nodes.ts +112 -0
  383. package/src/self-dev/graph-journey-nodes.ts +1 -0
  384. package/src/self-dev/harness-run-cli.ts +3 -15
  385. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  386. package/src/self-dev/review-provider-fallback.ts +35 -1
  387. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  388. package/src/self-dev/shard-aggregate.ts +42 -5
  389. package/src/self-dev/shard-run.ts +8 -1
  390. package/src/self-implement/blocked-draft-policy.ts +20 -0
  391. package/src/self-implement/classify-shadow.ts +3 -7
  392. package/src/self-implement/doctor-visit.ts +18 -1
  393. package/src/self-implement/gate-baseline.ts +56 -17
  394. package/src/self-implement/gate-cli.ts +1 -0
  395. package/src/self-implement/gate-remote.ts +31 -20
  396. package/src/self-implement/goal-author-decompose.ts +275 -47
  397. package/src/self-implement/goal-author.ts +250 -0
  398. package/src/self-implement/goal-elaborate.ts +295 -0
  399. package/src/self-implement/goal-refine.ts +270 -0
  400. package/src/self-implement/graph-overlay-yaml.ts +14 -3
  401. package/src/self-implement/orchestrator.ts +152 -45
  402. package/src/self-implement/rework-budget-judgment.ts +5 -8
  403. package/src/self-implement/run-stop.ts +10 -1
  404. package/src/self-implement/running-runs.ts +29 -1
  405. package/src/self-implement/scope-adjacency.ts +113 -0
  406. package/src/self-implement/seams.ts +127 -24
  407. package/src/self-implement/stop-autoheal.ts +87 -1
  408. package/src/session-runtime/index.ts +1 -1
  409. package/src/setup/llm-env-detect.ts +5 -0
  410. package/src/skills/tools/agent.ts +140 -14
  411. package/src/skills/tools/msg-ask.ts +100 -0
  412. package/src/skills/tools/ops-ledger.ts +2 -1
  413. package/src/steward/hold-hygiene.ts +24 -6
  414. package/src/steward/triage-budget.ts +194 -0
  415. package/src/steward/triage.ts +20 -3
  416. package/src/task-agent/actions.ts +69 -1
  417. package/src/task-agent/green-sweep.ts +4 -0
  418. package/src/task-agent/live-moves.ts +160 -4
  419. package/src/task-agent/parent-host.ts +123 -3
  420. package/src/task-agent/shadow.ts +7 -1
  421. package/src/task-agent/task-hand.ts +54 -41
  422. package/src/task-agent/tier-split.ts +127 -0
  423. package/src/task-agent/work-order-build.ts +2 -0
  424. package/src/task-agent/work-order.ts +3 -2
  425. package/src/task-orchestrator/generator-prompt.ts +60 -11
  426. package/src/task-orchestrator/surfaces/pod-account-broker.ts +33 -0
  427. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  428. package/src/task-orchestrator/surfaces/pod-command-job.ts +45 -7
  429. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  430. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  431. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
  432. package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
  433. package/src/task-orchestrator/surfaces/pod-source-receive.ts +18 -0
  434. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  435. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
  436. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
  437. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +37 -5
  438. package/src/task-orchestrator/surfaces/self-implement-pod.ts +368 -36
  439. package/src/task-orchestrator/surfaces/self-implement.ts +23 -0
  440. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  441. package/src/tui/README.md +2 -0
  442. package/src/tui/chat/background-job-status.ts +54 -0
  443. package/src/tui/chat/log-view.ts +80 -0
  444. package/src/tui/entry.ts +406 -0
  445. package/src/tui/input/composer.ts +144 -0
  446. package/src/tui/seat-mail-boot.ts +59 -0
  447. package/src/tui/slash/compact.ts +100 -0
  448. package/src/tui/slash/new-session.ts +35 -0
  449. package/src/tui-client/local-chat-turn.ts +239 -0
  450. package/src/tui-client/local-harness-command.ts +63 -0
  451. package/src/tui-client/local-provider-command.ts +184 -0
  452. package/src/user-config.ts +4 -2
  453. package/src/ux-sim/event-monkey.ts +378 -0
  454. package/src/ux-sim/fake-bin.ts +42 -7
  455. package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
  456. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  457. package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
  458. package/src/version/packed-revision.json +1 -1
  459. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +0 -79
  460. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
  463. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
  465. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
  467. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
  468. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +0 -34
  479. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/3498.cf2a15a8a9e5b926.js +0 -226
  485. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +0 -32
  487. package/apps/pwa/out/_next/static/chunks/3837.722e053fb9f321ad.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
  490. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
  491. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
  492. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
  493. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
  494. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
  497. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
  504. package/apps/pwa/out/_next/static/chunks/5446.edf141cff9ef647d.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
  506. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
  517. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
  520. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +0 -41
  527. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
  530. package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
  533. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
  547. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
  549. package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
  603. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/ffdc3a04.b9c23c1b28dd4a96.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
  611. /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → T1mBQqmkwKDLGtyisDCOd}/_ssgManifest.js +0 -0
@@ -10,7 +10,7 @@ import { lastJsonObject, runGraph, verifyReleaseCommandRoot, type GraphRunState
10
10
  import { withOpSeatFlock } from '../../src/steward/resync-tick.js';
11
11
  import { releaseRunUniverse } from './release-universe.js';
12
12
  import { isReleaseVersion } from './release-version.js';
13
- import { changedFilesBetween, clearPartialPlan, planPartialRegate, writePartialPlan } from './gate-partial.js';
13
+ import { changedFilesBetween, clearPartialPlan, planPartialRegate, planStalledShardRecheck, writePartialPlan, writeRecheckPlan } from './gate-partial.js';
14
14
  import { gitClosureTree, testsReachingChanged, TRACEABLE_RELEASE_JSON, type ClosureTree } from './gate-closure.js';
15
15
  import { releaseResumeAcceptedRegressions, releaseResumeGateExecutor, releaseResumeGatePodPool, releaseResumeWaiver, type AcceptedRegression } from './resume.js';
16
16
  import { reserveReleaseResumeAttempt } from './resume-cap.js';
@@ -173,13 +173,50 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
173
173
  const reachesGate = (opts.from === 'gate' || opts.from === 'export-check') && fromIndex >= 0 && gateIndex >= fromIndex;
174
174
  // The default applies only where it can help: a gate re-run on a tip that moved. An unchanged tip re-uses its own
175
175
  // shard results by commit already.
176
- if (opts.partial === false || (auto && (!reachesGate || !tip.changed))) return { requested: false };
176
+ if (opts.partial === false || (auto && (!reachesGate || (!tip.changed && opts.from !== 'gate')))) return { requested: false };
177
177
  const fallback = (reason: string): PartialOutcome => {
178
- debug.log('release-loop.resume', 'partial-fallback', { version: tip.version, reason, auto });
178
+ debug.log('release-loop.resume', 'partial-fallback', { version: tip.version, reason, auto,
179
+ planKind: 'full', remeasureFileCount: 0, preservedShardCount: 0, fallbackReason: reason });
179
180
  return { requested: true, applied: false, reason, ...(auto ? { auto: true as const } : {}) };
180
181
  };
181
182
  if (!reachesGate) return fallback('--partial requires a restart that reaches gate');
182
- if (!tip.changed) return fallback('release branch tip unchanged — nothing new to re-check');
183
+ if (!tip.changed) {
184
+ if (opts.from !== 'gate') return fallback('same-commit stalled-shard recheck requires --from gate');
185
+ const saved = JSON.parse(readFileSync(tip.statePath, 'utf8')) as GraphRunState;
186
+ const gateRecord = saved.nodes.find((node) => node.nodeId === 'gate');
187
+ const previousGate = gateRecord ? lastJsonObject(gateRecord.output) as Record<string, unknown> | undefined : undefined;
188
+ const stalled = previousGate?.stalledShards;
189
+ const summary = previousGate?.partialSummary as { pass?: unknown; fail?: unknown; errors?: unknown; ran?: unknown; files?: unknown } | undefined;
190
+ const measured = previousGate?.partialFailures as { failures?: unknown; errors?: unknown } | undefined;
191
+ if (previousGate?.outcome !== 'error' || previousGate.commit !== tip.to || !Array.isArray(stalled) || !stalled.length || !summary || !measured
192
+ || !['pass', 'fail', 'errors', 'ran', 'files'].every((key) => Number.isSafeInteger(summary[key as keyof typeof summary]) && Number(summary[key as keyof typeof summary]) >= 0)
193
+ || !Array.isArray(measured.failures) || !measured.failures.every((id) => typeof id === 'string')
194
+ || !Array.isArray(measured.errors) || !measured.errors.every((id) => typeof id === 'string')
195
+ || measured.failures.length !== Number(summary.fail) || measured.errors.length !== Number(summary.errors))
196
+ return fallback('same-commit gate has no complete stalled-shard measurement record');
197
+ const stalledFiles: string[] = [];
198
+ for (const item of stalled) {
199
+ if (!item || typeof item !== 'object' || !Array.isArray((item as { files?: unknown }).files)
200
+ || !(item as { files: unknown[] }).files.every((file) => typeof file === 'string')
201
+ || !['incomplete', 'no-output', 'job-failed', 'exit-code', 'unattributed', 'timeout'].includes(String((item as { reason?: unknown }).reason)))
202
+ return fallback('stalled-shard record is malformed');
203
+ stalledFiles.push(...(item as { files: string[] }).files);
204
+ }
205
+ const closure = (deps.closureTree ?? ((commit: string) => gitClosureTree(deps.repo ?? process.cwd(), commit)))(tip.to);
206
+ const tracked = new Set(closure.files);
207
+ const preservedShardCount = Number.isSafeInteger(previousGate?.preservedShardCount)
208
+ && Number(previousGate?.preservedShardCount) >= 0 ? Number(previousGate?.preservedShardCount) : undefined;
209
+ const planned = planStalledShardRecheck({ version: tip.version, measuredCommit: tip.to, forCommit: tip.to,
210
+ failures: measured.failures as string[], errors: measured.errors as string[], stalledFiles,
211
+ ...(preservedShardCount === undefined ? {} : { preservedShardCount }),
212
+ existsAtCommit: (file) => tracked.has(file) });
213
+ if (!planned.ok) return fallback(planned.reason);
214
+ const path = writeRecheckPlan(root, planned.plan);
215
+ debug.log('release-loop.resume', 'stalled-recheck-planned', { version: tip.version, commit: tip.to,
216
+ planKind: planned.plan.kind, remeasureFileCount: planned.plan.files.length,
217
+ preservedShardCount: planned.plan.preservedShardCount ?? 0, fallbackReason: null, path });
218
+ return { requested: true, applied: true, files: planned.plan.files.length, priorCommit: tip.to, ...(auto ? { auto: true as const } : {}) };
219
+ }
183
220
  let prior: { commit?: unknown; failures?: unknown; errors?: unknown } | undefined;
184
221
  for (const location of [...new Set([deps.ledgerRoot ?? releaseLedgerRoot(), root])]) {
185
222
  const path = join(location, 'release', tip.version, 'gate-failures.json');
@@ -39,6 +39,8 @@ export interface ReleaseLoopConfig {
39
39
  gatePodCpu?: number | string | { request?: number | string; limit?: number | string };
40
40
  gateRemote?: string;
41
41
  gateRemoteMirror?: string;
42
+ /** RELEASE-PWA-NODE-RESILIENCE ① — SSH host the `pwa` node runs its scenario suite on (e.g. `node-b`); absent = this machine. No fallback. */
43
+ pwaRemote?: string;
42
44
  opsHosts?: string[];
43
45
  internalDist?: string;
44
46
  opsRestart?: boolean;
@@ -93,7 +93,12 @@ export type Verdict = 'keep' | 'failing' | 'review';
93
93
  export type Proposal = 'delete' | 'shrink' | 'rewrite-cheap' | 'move-out-of-gate' | 'investigate';
94
94
  export interface Td1Disposition { disposition: string; alternative: string; guards: string; why_slow: string }
95
95
  export interface Judged extends Measurement { caught90: number; flags: string[]; verdict: Verdict; effectiveness?: Effectiveness; proposal?: Proposal | null; basis?: string | null }
96
- export interface LedgerLine { at: string; range: string; start: number; end: number; next: number; total: number; commit: string; budgetSecs: number; results: Judged[]; sweepVisited?: number; sweepCostSecs?: number; sweepSlices?: number }
96
+ export interface LedgerLine {
97
+ at: string; range: string; start: number; end: number; next: number; total: number; commit: string; budgetSecs: number; results: Judged[];
98
+ /** Exact non-contiguous selection; `range` encodes these indices in selection order. */
99
+ selectedFiles?: string[]; selectedIndices?: number[];
100
+ sweepVisited?: number; sweepCostSecs?: number; sweepSlices?: number;
101
+ }
97
102
 
98
103
  /** `file\tsecs\t…` (TD1 whole-gate TSV) → seconds per file. */
99
104
  export function costTable(tsv: string): Map<string, number> {
@@ -7,12 +7,13 @@ import { appendFileSync, existsSync, mkdtempSync, mkdirSync, readFileSync, rmSyn
7
7
  import { tmpdir } from 'node:os';
8
8
  import { join } from 'node:path';
9
9
  import { debug } from '../../src/debug/log.js';
10
- import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
10
+ import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/resolve.js';
11
11
  import { CardStore } from '../../src/task-cards/card-store.js';
12
12
  import { GATE_NIGHTLY_AUDITS } from '../release-loop/gate-node.js';
13
13
  import { isCredentialKey } from '../lib/deterministic-env.js';
14
14
  import { appendLedger, costTable, judge, lastLedgerLine, ledgerPath, mainFailureFiles, nightlyAuditLedgerPath, pickRange, propose, td1Dispositions, writeCardDraft, writeMainFailureDay, type LedgerLine, type MainFailureResult, type Measurement, type Td1Disposition } from './lib.js';
15
15
  import { fixedCountAssertions, flakeVerdict, sweepSlice, unreachableImports, type Mutation, type TestRun } from './effectiveness.js';
16
+ import { gateHistory, type GateHistoryRow } from '../release-loop/gate-history.js';
16
17
 
17
18
  type Context = { graphId?: string; input: Record<string, unknown>; outputs: Record<string, Record<string, unknown> | null> };
18
19
  function context(): Context {
@@ -27,6 +28,129 @@ function emit(result: Record<string, unknown> & { outcome: 'ok' | 'fail' | 'erro
27
28
  }
28
29
  const git = (args: string[]) => spawnSync('git', args, { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 }).stdout ?? '';
29
30
 
31
+ /**
32
+ * GATE-FAIL-HISTORY → per-file failure likelihood (boundary ①): a file the landed gate already failed on is picked
33
+ * before one it never failed on, and preexisting/knownEnv repeat offenders outrank one-off introduced/load-flaky hits.
34
+ */
35
+ const GATE_FAIL_WEIGHT = { preexisting: 4, knownEnv: 3, flaky: 3, introduced: 2 } as const;
36
+
37
+ /** Only the buckets the pick order and the prescription both read — no write-only fields. */
38
+ export type GateFailWeight = { file: string; weight: number; preexisting: number; knownEnv: number; flaky: number };
39
+
40
+ export function gateFailWeights(rows: readonly GateHistoryRow[]): Map<string, GateFailWeight> {
41
+ const weights = new Map<string, GateFailWeight>();
42
+ for (const row of rows) {
43
+ const weight = row.preexisting * GATE_FAIL_WEIGHT.preexisting + row.env * GATE_FAIL_WEIGHT.knownEnv
44
+ + row.flaky * GATE_FAIL_WEIGHT.flaky + row.introduced * GATE_FAIL_WEIGHT.introduced;
45
+ if (weight <= 0) continue;
46
+ const file = String(row.file);
47
+ weights.set(file, { file, weight, preexisting: row.preexisting, knownEnv: row.env, flaky: row.flaky });
48
+ }
49
+ return weights;
50
+ }
51
+
52
+ /** Reads the gate's own failure ledger; an unreadable ledger is an empty history, never a failed pick. */
53
+ export function loadGateFailWeights(deps: {
54
+ instanceRoots?: readonly string[]; ledgerRoots?: readonly string[]; rows?: readonly GateHistoryRow[];
55
+ } = {}): Map<string, GateFailWeight> {
56
+ if (deps.rows) return gateFailWeights(deps.rows);
57
+ try {
58
+ const report = gateHistory({
59
+ instanceRoots: deps.instanceRoots ?? [effectiveInstanceRoot()],
60
+ ledgerRoots: deps.ledgerRoots ?? [releaseLedgerRoot()],
61
+ }, { mergedPrs: () => [] });
62
+ return gateFailWeights(report.rows);
63
+ } catch (error) {
64
+ debug.log('test-diet', 'history-read-failed', { error: String(error) });
65
+ return new Map();
66
+ }
67
+ }
68
+
69
+ /**
70
+ * `pickRange` with the history-weighted order on top: every gate-failed file that fits the budget comes first
71
+ * (weight desc, then cheaper), the cursor slice fills the rest. Cursor `next` only advances past cursor files the
72
+ * budget actually selected — an unselected cursor file stays before `next`, so no file is skipped in a daily verdict
73
+ * or a sweep.
74
+ */
75
+ export function pickWithHistory(files: readonly string[], start: number, costs: ReadonlyMap<string, number>, budgetSecs: number,
76
+ weights: ReadonlyMap<string, GateFailWeight>): ReturnType<typeof pickRange> & {
77
+ historyFiles: GateFailWeight[]; selectedIndices: number[]; rangeLabel: string; cursorVisitedCount: number;
78
+ } {
79
+ const range = pickRange(files, start, costs, budgetSecs);
80
+ const cost = (file: string) => costs.get(file) ?? 10;
81
+ const historyFiles = [...weights.values()].filter((entry) => files.includes(entry.file))
82
+ .sort((a, b) => b.weight - a.weight || cost(a.file) - cost(b.file) || a.file.localeCompare(b.file));
83
+ const describeSelection = (selectedFiles: string[]) => {
84
+ const selectedIndices = selectedFiles.map((file) => files.indexOf(file));
85
+ const contiguous = selectedIndices.length > 0
86
+ && selectedIndices.every((index, position) => position === 0 || index === selectedIndices[position - 1]! + 1);
87
+ const rangeLabel = selectedIndices.length === 0 ? '#empty'
88
+ : contiguous ? `#${selectedIndices[0]}~#${selectedIndices.at(-1)}`
89
+ : selectedIndices.map((index) => `#${index}`).join(',');
90
+ return { selectedIndices, rangeLabel };
91
+ };
92
+ if (historyFiles.length === 0) return { ...range, historyFiles, cursorVisitedCount: range.files.length, ...describeSelection(range.files) };
93
+ const ordered: string[] = [];
94
+ let estimatedSecs = 0;
95
+ for (const file of [...historyFiles.map((entry) => entry.file), ...range.files]) {
96
+ if (ordered.includes(file)) continue;
97
+ const added = cost(file);
98
+ if (ordered.length > 0 && estimatedSecs + added > budgetSecs) continue;
99
+ ordered.push(file);
100
+ estimatedSecs += added;
101
+ }
102
+ // 예산을 이력 파일로 채웠을 때: 커서는 실제로 선택한 커서 조각까지만 전진한다.
103
+ // 선택되지 않은 커서 파일을 next 너머로 건너뛰면 일일 판정·sweep에서 영구 누락된다.
104
+ const firstUnpicked = range.files.findIndex((file) => !ordered.includes(file));
105
+ const next = firstUnpicked === -1 ? range.next : (range.start + firstUnpicked) % files.length;
106
+ return { ...range, files: ordered, estimatedSecs, historyFiles, next,
107
+ cursorVisitedCount: range.files.filter((file) => ordered.includes(file)).length, ...describeSelection(ordered) };
108
+ }
109
+
110
+ /** MANUAL-gate-regression-response-recipe §2 T1~T7, plus TA for a verdict that is only a draft for the card. */
111
+ export type CleanseRecipeType = 'T1' | 'T2' | 'T3' | 'T4' | 'T5' | 'T6' | 'T7' | 'TA';
112
+ export type CleanseRecipe = { type: CleanseRecipeType; file: string; action: string; basis: string };
113
+
114
+ const RECIPE_ACTIONS: Record<CleanseRecipeType, string> = {
115
+ T1: 'fixture·단언을 새 계약으로 고쳐 쓴다(제품 동작은 그대로)',
116
+ T2: '제품 회귀 — 제품 동작을 고친다(시험 완화 금지)',
117
+ T3: '규칙 문면을 규칙 원본과 맞춘다',
118
+ T4: '시험 문면을 지금 문안으로 맞춘다(프로토콜·기본 동작은 그대로)',
119
+ T5: '빈 환경 의존을 주입으로 없앤다(credential·경로·도구를 명시 주입)',
120
+ T6: '간섭을 격리한다(단독 실행·임시 HOME·동시성 낮춤)',
121
+ T7: '인프라 실패 — 재게이트하고 TA 카드로 사람에게 넘긴다',
122
+ TA: '결과를 TA 카드로 남긴다(지우기·이동은 사람·주인 확인)',
123
+ };
124
+
125
+ export type RecipeInput = { file: string; verdict: string; reason?: string; flaky?: boolean; effectiveness?: { flake?: string };
126
+ history?: { preexisting: number; knownEnv: number; flaky?: number } };
127
+
128
+ /** Exactly one prescription per verdict — the draft only, never a deletion. */
129
+ export function recipeFor(result: RecipeInput): CleanseRecipe {
130
+ const reason = (result.reason ?? '').toLowerCase();
131
+ const flaky = result.flaky === true || result.effectiveness?.flake === 'flaky';
132
+ const history = result.history;
133
+ // The gate ledger's flaky bucket is the same «history» the pick weighs, so a repeat-flaky file that measures
134
+ // keep still gets the isolation prescription (T6) instead of falling through to a bare TA card.
135
+ const historyFlaky = history?.flaky ?? 0;
136
+ const type: CleanseRecipeType = result.verdict === 'failing'
137
+ ? (/enospc|out of memory|cannot allocate|oomkilled|no space|pod .*(restart|terminat)|preempt/.test(reason) ? 'T7'
138
+ : flaky ? 'T6'
139
+ : /enoent|eacces|no llm provider|command not found|cannot find module|credential|api key|not found: |git config/.test(reason) ? 'T5'
140
+ : /timed out|timeout|waitfor|expected text|wording|문면/.test(reason) ? 'T4'
141
+ : /rules-contract|(^|\/)\.rules\//.test(result.file) ? 'T3'
142
+ : /typeerror|referenceerror|is not a function|is not defined|syntaxerror/.test(reason) ? 'T2'
143
+ : 'T1')
144
+ : history?.knownEnv ? 'T5'
145
+ : flaky || history?.preexisting || historyFlaky > 0 ? 'T6'
146
+ : 'TA';
147
+ const tail = reason.split('\n')[0]?.slice(0, 160) ?? '';
148
+ const historyBasis = history && (history.preexisting > 0 || history.knownEnv > 0 || historyFlaky > 0)
149
+ ? ` · gate history preexisting ${history.preexisting} · knownEnv ${history.knownEnv}`
150
+ + `${historyFlaky > 0 ? ` · flaky ${historyFlaky}` : ''}` : '';
151
+ return { type, file: result.file, action: RECIPE_ACTIONS[type], basis: `${result.verdict}${tail ? `: ${tail}` : ''}${historyBasis}` };
152
+ }
153
+
30
154
  function pick(ctx: Context, sweep = false): number {
31
155
  const files = git(['ls-files', '*.test.ts']).split('\n').filter(Boolean).sort();
32
156
  const costs = costTable(readFileSync(join(process.cwd(), 'docs/measurements/td1-whole-gate-mechanical-2026-10-01.tsv'), 'utf8'));
@@ -35,7 +159,7 @@ function pick(ctx: Context, sweep = false): number {
35
159
  const totalCostSecs = sweep ? files.reduce((sum, file) => sum + (costs.get(file) ?? 10), 0) : 0;
36
160
  // `start` re-looks a slice on purpose; otherwise continue from the ledger cursor.
37
161
  const startAt = typeof ctx.input.start === 'number' && ctx.input.start >= 0 ? ctx.input.start : last?.next ?? 0;
38
- const continuing = ctx.input.start === undefined && last?.sweepVisited && last.sweepVisited < files.length && last.next === startAt && last.total === files.length;
162
+ const continuing = ctx.input.start === undefined && typeof last?.sweepVisited === 'number' && last.sweepVisited < files.length && last.next === startAt && last.total === files.length;
39
163
  const remaining = continuing ? files.length - last.sweepVisited! : files.length;
40
164
  const elapsed = continuing ? last.sweepSlices ?? 0 : 0;
41
165
  const slotsLeft = Math.max(1, 28 - elapsed);
@@ -43,8 +167,13 @@ function pick(ctx: Context, sweep = false): number {
43
167
  slotsLeft, minBudgetSecs: continuing ? last.budgetSecs : 0 }) : undefined;
44
168
  const budgetSecs = sweepPlan?.budgetSecs
45
169
  ?? (typeof ctx.input.budgetSecs === 'number' && ctx.input.budgetSecs > 0 ? ctx.input.budgetSecs : 1800);
46
- const range = pickRange(files, startAt, costs, budgetSecs);
47
- return emit({ outcome: 'ok', summary: `test-diet pick #${range.start}~#${range.end} of ${files.length} (≈${Math.round(range.estimatedSecs)}s)`, ...range, total: files.length, budgetSecs,
170
+ const measuredLastSlice = new Set((last?.results ?? []).map((result) => result.file));
171
+ const cursorParked = last?.next === startAt && last.selectedIndices?.every((index) => index !== startAt);
172
+ // When a prior history-only slice left the cursor parked, force the next slice onto the cursor.
173
+ // Suppressing only the last history winner allows two weighted files to alternate forever.
174
+ const availableHistory = cursorParked ? new Map() : new Map([...loadGateFailWeights()].filter(([file]) => !measuredLastSlice.has(file)));
175
+ const range = pickWithHistory(files, startAt, costs, budgetSecs, availableHistory);
176
+ return emit({ outcome: 'ok', summary: `test-diet pick ${range.rangeLabel} of ${files.length} (≈${Math.round(range.estimatedSecs)}s)`, ...range, total: files.length, budgetSecs,
48
177
  ...(sweep ? { sweep: true, totalCostSecs, slicesNeeded: sweepPlan?.slicesNeeded, sweepElapsed: elapsed } : {}) });
49
178
  }
50
179
 
@@ -180,6 +309,23 @@ function recordNightlyAudit(ctx: Context): number {
180
309
  return emit({ outcome: failing ? 'fail' : 'ok', summary: `nightly audit ${results.length} · failing ${failing}${card ? ' · card draft' : ''}`, failing, ledger: path, ...(card ? { card } : {}) });
181
310
  }
182
311
 
312
+ /** The pick's own gate-history snapshot — `record` reads the files `pick` actually selected from, never a fresh
313
+ * ledger query, so the prescription and the ledger line keep the same basis even if the gate ledger changed
314
+ * between the two graph steps. */
315
+ function pickHistoryFiles(p: Record<string, unknown> | null): GateFailWeight[] {
316
+ const raw = p?.historyFiles;
317
+ if (!Array.isArray(raw)) return [];
318
+ const files: GateFailWeight[] = [];
319
+ for (const entry of raw) {
320
+ if (entry === null || typeof entry !== 'object') continue;
321
+ const x = entry as GateFailWeight;
322
+ if (typeof x.file !== 'string' || typeof x.weight !== 'number' || !Number.isFinite(x.weight)
323
+ || typeof x.preexisting !== 'number' || typeof x.knownEnv !== 'number' || typeof x.flaky !== 'number') continue;
324
+ files.push({ file: x.file, weight: x.weight, preexisting: x.preexisting, knownEnv: x.knownEnv, flaky: x.flaky });
325
+ }
326
+ return files;
327
+ }
328
+
183
329
  export function record(ctx: Context, deps: { createStore?: (root: string) => Pick<CardStore, 'createCard' | 'appendSection' | 'close'>; td1?: ReadonlyMap<string, Td1Disposition> } = {}): number {
184
330
  const p = ctx.outputs.pick;
185
331
  const m = ctx.outputs.measure;
@@ -188,27 +334,61 @@ export function record(ctx: Context, deps: { createStore?: (root: string) => Pic
188
334
  const td1 = deps.td1 ?? td1Dispositions(readFileSync(join(process.cwd(), 'docs/measurements/td1-top200-content-review-2026-10-01.tsv'), 'utf8'));
189
335
  const results = measurements.map((x) => propose(judge(x, git(['log', '--since=90.days', '--format=%s', '--', x.file]).split('\n').filter((s) => /^fix\b/i.test(s)).length), td1));
190
336
  const previous = p.sweep === true ? lastLedgerLine(effectiveInstanceRoot()) : null;
191
- const continuing = previous?.sweepVisited && previous.sweepVisited < Number(p.total)
337
+ const continuing = typeof previous?.sweepVisited === 'number' && previous.sweepVisited < Number(p.total)
192
338
  && previous.next === Number(p.start) && previous.total === Number(p.total);
193
- const visited = p.sweep === true ? Math.min(Number(p.total), (continuing ? previous.sweepVisited! : 0) + results.length) : undefined;
339
+ const visited = p.sweep === true ? Math.min(Number(p.total), (continuing ? previous.sweepVisited! : 0) + Number(p.cursorVisitedCount ?? results.length)) : undefined;
194
340
  const sweepCostSecs = p.sweep === true ? (continuing ? previous.sweepCostSecs ?? 0 : 0) + Number(p.estimatedSecs) : undefined;
195
341
  const sweepSlices = p.sweep === true ? Number(p.sweepElapsed ?? (continuing ? previous.sweepSlices ?? 0 : 0)) + 1 : undefined;
342
+ const root = effectiveInstanceRoot();
343
+ const historyFiles = pickHistoryFiles(p);
344
+ const weights = new Map(historyFiles.map((entry) => [entry.file, entry]));
345
+ const historyFailures = results.map((result) => weights.get(result.file))
346
+ .filter((entry): entry is GateFailWeight => entry !== undefined);
347
+ const slicePreexisting = historyFailures.reduce((sum, entry) => sum + entry.preexisting, 0);
348
+ const slicePreexistingKnownEnv = historyFailures.reduce((sum, entry) => sum + entry.knownEnv, 0);
349
+ // Metric (boundary ③): each ledger line carries its slice's preexisting ⊕ knownEnv totals AND their delta
350
+ // against the previous slice line, so «판마다 이월» is readable row by row — even on a zero line.
351
+ const previousHistory = (lastLedgerLine(root) as { gateHistory?: { preexisting?: number; knownEnv?: number } } | null)?.gateHistory;
352
+ const history = {
353
+ preexisting: slicePreexisting,
354
+ knownEnv: slicePreexistingKnownEnv,
355
+ total: slicePreexisting + slicePreexistingKnownEnv,
356
+ files: historyFailures.map((entry) => entry.file),
357
+ deltaPreexisting: slicePreexisting - Number(previousHistory?.preexisting ?? 0),
358
+ deltaKnownEnv: slicePreexistingKnownEnv - Number(previousHistory?.knownEnv ?? 0),
359
+ };
360
+ const selectedFiles = Array.isArray(p.files) ? p.files.filter((file): file is string => typeof file === 'string') : results.map((result) => result.file);
361
+ const selectedIndices = Array.isArray(p.selectedIndices) && p.selectedIndices.every((index) => typeof index === 'number')
362
+ ? p.selectedIndices as number[] : [];
196
363
  const line = {
197
- at: new Date().toISOString(), range: `#${p.start}~#${p.end}`, start: Number(p.start), end: Number(p.end), next: Number(p.next), total: Number(p.total),
364
+ // start/end/next are cursor coordinates; range + selectedIndices describe the exact weighted selection.
365
+ at: new Date().toISOString(), range: typeof p.rangeLabel === 'string' ? p.rangeLabel : `#${p.start}~#${p.end}`,
366
+ start: Number(p.start), end: Number(p.end), next: Number(p.next), total: Number(p.total), selectedFiles, selectedIndices,
198
367
  commit: String(m?.commit ?? '?'), budgetSecs: Number(p.budgetSecs), results, ...(visited === undefined ? {} : { sweepVisited: visited, sweepCostSecs, sweepSlices }),
368
+ gateHistory: { preexisting: history.preexisting, knownEnv: history.knownEnv, total: history.total,
369
+ deltaPreexisting: history.deltaPreexisting, deltaKnownEnv: history.deltaKnownEnv },
199
370
  };
200
- const root = effectiveInstanceRoot();
201
371
  appendLedger(root, line);
202
372
  const card = writeCardDraft(root, line);
373
+ const recipes = new Map(results.map((result) => {
374
+ const entry = weights.get(result.file);
375
+ return [result.file, recipeFor(entry ? { ...result, history: entry } : result)] as const;
376
+ }));
377
+ const recipeCounts: Record<string, number> = {};
378
+ for (const recipe of recipes.values()) recipeCounts[recipe.type] = (recipeCounts[recipe.type] ?? 0) + 1;
203
379
  const proposals: Record<string, number> = {};
204
380
  for (const result of results) {
205
- if (!result.proposal) continue;
206
- proposals[result.proposal] = (proposals[result.proposal] ?? 0) + 1;
381
+ if (td1.get(result.file)?.disposition === 'keep' && result.verdict === 'keep' && !result.proposal) continue;
382
+ const recipe = recipes.get(result.file)!;
383
+ const historyEntry = weights.get(result.file);
384
+ // YAML이 약속한 «판정마다 처방 카드 초안 하나» — 제안·실패·이력이 없는 keep 판정도 카드를 건너뛰지 않는다.
385
+ const proposal = result.proposal ?? (result.verdict === 'failing' ? 'failing' : historyEntry !== undefined ? `gate-history:${recipe.type}` : `verdict:${recipe.type}`);
386
+ proposals[proposal] = (proposals[proposal] ?? 0) + 1;
207
387
  let store: Pick<CardStore, 'createCard' | 'appendSection' | 'close'> | undefined;
208
388
  try {
209
389
  store = deps.createStore?.(root) ?? new CardStore(root);
210
- const task = store.createCard({ goalId: `test-diet:${result.file}:${result.proposal}`, title: `시험 다이어트 제안 — ${result.file} · ${result.proposal}` });
211
- const observation = { proposal: result.proposal, basis: result.basis, guards: td1.get(result.file)?.guards ?? '',
390
+ const task = store.createCard({ goalId: `test-diet:${result.file}:${proposal}`, title: `시험 다이어트 제안 — ${result.file} · ${proposal} · ${recipe.type}` });
391
+ const observation = { proposal: result.proposal, recipe, basis: result.basis, guards: td1.get(result.file)?.guards ?? '',
212
392
  secs: result.secs, rssMb: result.rssMb, caught90: result.caught90, range: line.range, ...(result.effectiveness ? { effectiveness: result.effectiveness } : {}) };
213
393
  const fingerprint = createHash('sha256').update(JSON.stringify(observation)).digest('hex');
214
394
  const key = `test-diet:${line.commit}:${fingerprint}`;
@@ -233,8 +413,9 @@ export function record(ctx: Context, deps: { createStore?: (root: string) => Pic
233
413
  }
234
414
  debug.log('test-diet', 'proposed', { range: line.range, proposals });
235
415
  const counts = { keep: results.filter((r) => r.verdict === 'keep').length, review: results.filter((r) => r.verdict === 'review').length, failing: results.filter((r) => r.verdict === 'failing').length };
416
+ debug.log('test-diet', 'prescriptions', { range: line.range, recipes: recipeCounts, preexisting: history.preexisting, knownEnv: history.knownEnv });
236
417
  debug.log('test-diet', 'recorded', { range: line.range, ...counts, card: card !== null });
237
- return emit({ outcome: 'ok', summary: `test-diet ${line.range} · keep ${counts.keep} · review ${counts.review} · failing ${counts.failing}${card ? ' · card draft' : ''}`, range: line.range, ...counts, ...(card ? { card } : {}) });
418
+ return emit({ outcome: 'ok', summary: `test-diet ${line.range} · keep ${counts.keep} · review ${counts.review} · failing ${counts.failing}${card ? ' · card draft' : ''}`, range: line.range, ...counts, ...(card ? { card } : {}), recipes: recipeCounts, history });
238
419
  }
239
420
 
240
421
  export function mainFailures(ctx: Context, deps: { root?: string; checkout?: string; runFile?: (file: string, cwd: string) => MainFailureResult; now?: Date } = {}): number {
package/scripts/ux-sim.ts CHANGED
@@ -17,6 +17,7 @@
17
17
  // bun scripts/ux-sim.ts --fault pod-death # 결함 주입: PARTIAL 줄을 남긴 Pod 가 SIGTERM 으로 지워짐 → 호스트 재방출 판정
18
18
  // bun scripts/ux-sim.ts --fault pool-cap # 결함 주입: --pod-pool 에 :N 이 빠진 풀 → 승인 판정(limitedBy)
19
19
  // bun scripts/ux-sim.ts --fault sqlite-busy # 결함 주입: 실제 SQLite 잠금 → 로그 배치 버퍼·복구
20
+ // bun scripts/ux-sim.ts emit child-error-long --json # 사건 주입(L0): 격리 우주 원장에 주입 줄 → 소비자 목록
20
21
  //
21
22
  // ⛔ 이 CLI 는 «실제 위젯 render()» 를 부른다 — 흉내 렌더러가 아니다.
22
23
  import { simRenderLogFrame } from '../src/ux-sim/render-frame.js';
@@ -29,6 +30,44 @@ const PHASES: TurnPhase[] = [
29
30
 
30
31
  const argv = process.argv.slice(2);
31
32
 
33
+ // ── 사건 주입 «이벤트 몽키» (SIM-EVENT-MONKEY · L0) — 자기 플래그를 가진 하위 명령 ──
34
+ // bun scripts/ux-sim.ts emit <kind> [--run <id>] [--variant allowed|refused] [--state-dir <dir>] [--json]
35
+ // bun scripts/ux-sim.ts emit --list
36
+ // ⛔ 운영 우주(~/.elanous)면 쓰기 전에 거부(rc 3). 격리 우주는 ELANOUS_STATE_DIR 또는 --state-dir.
37
+ if (argv[0] === 'emit') {
38
+ // 얇은 별칭 — 해석은 `eln sim emit` 과 «같은» runEventMonkeyCli 하나가 한다.
39
+ const rest = argv.slice(1);
40
+ const EMIT_FLAGS = new Set(['--run', '--variant', '--state-dir', '--json', '--list']);
41
+ const VALUED = new Set(['--run', '--variant', '--state-dir']);
42
+ const unknown = rest.filter((a) => a.startsWith('--') && !EMIT_FLAGS.has(a));
43
+ if (unknown.length > 0) {
44
+ console.error(`⛔ 모르는 인자다: ${unknown.join(' ')} — 아는 것: ${[...EMIT_FLAGS].join(' · ')}`);
45
+ process.exit(2);
46
+ }
47
+ const value = (flag: string): string | undefined => {
48
+ const i = rest.indexOf(flag);
49
+ if (i < 0) return undefined;
50
+ const v = rest[i + 1];
51
+ if (!v || v.startsWith('--')) { console.error(`⛔ ${flag} 에 값이 필요하다`); process.exit(2); }
52
+ return v;
53
+ };
54
+ const { renderEventMonkeyKinds, runEventMonkeyCli } = await import('../src/ux-sim/event-monkey.js');
55
+ if (rest.includes('--list')) { console.log(renderEventMonkeyKinds(rest.includes('--json')).join('\n')); process.exit(0); }
56
+ const positional = rest.filter((a, i) => !a.startsWith('--') && !VALUED.has(rest[i - 1] ?? ''));
57
+ if (positional.length > 1) {
58
+ console.error(`⛔ 사건은 하나만 받는다 — 남는 인자: ${positional.slice(1).join(' ')}`);
59
+ process.exit(2);
60
+ }
61
+ const runId = value('--run');
62
+ const variant = value('--variant');
63
+ const stateDir = value('--state-dir');
64
+ const out = runEventMonkeyCli({ kindName: positional[0], json: rest.includes('--json'),
65
+ ...(runId ? { runId } : {}), ...(variant ? { variant } : {}), ...(stateDir ? { stateDir } : {}) });
66
+ for (const line of out.stdout) console.log(line);
67
+ for (const line of out.stderr) console.error(line);
68
+ process.exit(out.code);
69
+ }
70
+
32
71
  // ⛔⭐ 모르는 인자를 «조용히 삼키지» 않는다 — 이름을 대고 거부한다.
33
72
  //
34
73
  // 🚨 2026-08-27 실측: `--trajectory-list`(오타 · 실제는 `--list-trajectories`)를 쳤더니
@@ -18,8 +18,16 @@ import { elanousSelfAmbientBaseParts } from './self-ambient.js';
18
18
 
19
19
  export const SELF_AMBIENT_FRESH_MS = 30_000;
20
20
  export const SELF_AMBIENT_STALE_MAX_MS = 10 * 60_000;
21
+ export const SELF_AMBIENT_KEEP_WARM_ACTIVE_MS = 25_000;
22
+ export const SELF_AMBIENT_KEEP_WARM_IDLE_MS = 8 * 60_000;
23
+ const SELF_AMBIENT_IDLE_AFTER_MS = 2 * 60_000;
21
24
  const WORKER_TIMEOUT_MS = 60_000;
22
25
 
26
+ /** Keep turn context warm while active; avoid periodic ambient scans during a long idle. */
27
+ export function selfAmbientKeepWarmIntervalMs(idleMs: number): number {
28
+ return idleMs >= SELF_AMBIENT_IDLE_AFTER_MS ? SELF_AMBIENT_KEEP_WARM_IDLE_MS : SELF_AMBIENT_KEEP_WARM_ACTIVE_MS;
29
+ }
30
+
23
31
  interface CacheEntry { at: number; version: number; parts: string[] }
24
32
 
25
33
  export interface SelfAmbientCacheDeps {
@@ -35,6 +35,22 @@ export interface AcpReviewerOpts {
35
35
  timeoutMs?: number;
36
36
  /** One deadline for spawn → initialize → session/new → model select (ms). A child that never answers ACP must not hang the review. Default min(timeoutMs, 60000). */
37
37
  handshakeTimeoutMs?: number;
38
+ /**
39
+ * ACP-REVIEW-VIA-TEAMCLAUDE: how a `claude` review without an explicit `backendSpec` finds the teamclaude
40
+ * (cct) route. Default (production, non-injected) = `resolveTeamclaudeReviewRoute()`; an injected agent
41
+ * without this seam does not probe the host.
42
+ */
43
+ resolveClaudeRoute?: () => import('../self-dev/review-provider-fallback.js').TeamclaudeReviewRoute
44
+ | Promise<import('../self-dev/review-provider-fallback.js').TeamclaudeReviewRoute>;
45
+ }
46
+
47
+ /** ACP claude reviews read the repo with tools and ran 228–345s in practice (OPC #25934); 300s cut them. */
48
+ const ACP_CLAUDE_REVIEW_TIMEOUT_SEC = 600;
49
+ const ACP_REVIEW_TIMEOUT_SEC = 300;
50
+
51
+ /** Default per-review deadline (seconds) when the caller gives none. */
52
+ export function defaultAcpReviewTimeoutSec(backend: string): number {
53
+ return canonicalizeBackendId(backend) === 'claude' ? ACP_CLAUDE_REVIEW_TIMEOUT_SEC : ACP_REVIEW_TIMEOUT_SEC;
38
54
  }
39
55
 
40
56
  /**
@@ -96,6 +112,26 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
96
112
  // The injected seam deliberately accepts arbitrary test backends. The
97
113
  // production path alone resolves aliases and transport through the factory.
98
114
  const backend = canonicalizeBackendId(requestedBackend);
115
+ const timeoutMs = opts.timeoutMs ?? defaultAcpReviewTimeoutSec(backend) * 1000;
116
+ // ACP-REVIEW-VIA-TEAMCLAUDE (대표 10-21): a claude review goes through teamclaude (multi-account proxy) when it
117
+ // answers with a base URL — same cct spawn as the subscription lane. No answer = the prior path, recorded.
118
+ let backendSpec = opts.backendSpec;
119
+ let childEnv = opts.env;
120
+ const resolveClaudeRoute = backend === 'claude' && !opts.backendSpec
121
+ ? opts.resolveClaudeRoute ?? (injected ? undefined
122
+ : async () => (await import('../self-dev/review-provider-fallback.js')).resolveTeamclaudeReviewRoute())
123
+ : undefined;
124
+ if (resolveClaudeRoute) {
125
+ let route: import('../self-dev/review-provider-fallback.js').TeamclaudeReviewRoute;
126
+ try { route = await resolveClaudeRoute(); } catch { route = { reason: 'teamclaude-unavailable' }; }
127
+ if (route.spawn) { backendSpec = route.spawn.backendSpec; childEnv = route.spawn.env; }
128
+ debug.log('review.acp', 'claude-route', {
129
+ viaTeamclaude: Boolean(route.spawn),
130
+ baseUrlSet: Boolean(childEnv?.ANTHROPIC_BASE_URL),
131
+ timeoutSec: Math.round(timeoutMs / 1000),
132
+ reason: route.reason,
133
+ });
134
+ }
99
135
  // ⛔⭐⭐⭐ 백엔드 해석은 «`try` 밖»이라 여기서 던지면 아래 `catch` 의 `acp-review/error` 가
100
136
  // «안 걸린다**. 그래서 `--acp-backend claude-code`(미등록) 같은 오타를 주면 레지스트리가
101
137
  // ***`Unknown ACP backend "claude-code". Known: …"`*** 라는 «완벽한» 오류를 던지는데도
@@ -105,14 +141,13 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
105
141
  // ⇒ 이 한 줄만 자기 catch 로 감싼다(전체 try 를 앞당기면 `start` 관측이 그 안으로 들어간다).
106
142
  let transport: string | null;
107
143
  try {
108
- transport = injected ? null : opts.backendSpec?.transport ?? getAcpBackend(backend).transport ?? 'acp';
144
+ transport = injected ? null : backendSpec?.transport ?? getAcpBackend(backend).transport ?? 'acp';
109
145
  } catch (e) {
110
146
  debug.log('acp-review', 'error', {
111
147
  requestedBackend, backend, stage: 'resolve-backend', message: (e as Error).message,
112
148
  }, { level: 'error' });
113
149
  throw e;
114
150
  }
115
- const timeoutMs = opts.timeoutMs ?? 300_000;
116
151
  debug.log('acp-review', 'start', {
117
152
  requestedBackend,
118
153
  backend,
@@ -130,7 +165,7 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
130
165
  let capabilitiesObserved = false;
131
166
  const agentOpts: Omit<AcpAgentOpts, 'backendId'> = {
132
167
  cwd: opts.cwd,
133
- ...(opts.backendSpec ? { backendSpec: opts.backendSpec, env: opts.env } : {}),
168
+ ...(backendSpec ? { backendSpec, env: childEnv } : {}),
134
169
  log: (message) => debug.log('acp-review', 'agent-log', { backend, message }),
135
170
  onCapabilities: (capabilities) => {
136
171
  capabilitiesObserved = true;
@@ -159,7 +194,7 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
159
194
  // chat agents, whose callbacks and lifecycle must not be mutated here.
160
195
  // Grok's start can hang before the manager registers the subprocess;
161
196
  // own it directly so the handshake timeout can stop that child.
162
- const directAgent = injected || Boolean(opts.backendSpec) || backend === 'grok';
197
+ const directAgent = injected || Boolean(backendSpec) || backend === 'grok';
163
198
  const reviewManager = directAgent ? undefined : new AcpAgentManager();
164
199
  let agent: AcpAgent | undefined;
165
200
  let text = '';
@@ -684,7 +684,21 @@ const LONG_BRACKETED_SENTINEL = new RegExp(String.raw`^[([(【]\s*(?:[-—–]
684
684
  const KNOWN_NO_FINDING_REMARKS = new Set([
685
685
  // #27349 저장 JSON의 실제 무소견 문구.
686
686
  '문서 전용 변경이고 의도된 산출물이 실제로 존재하며 배선 누락·죽은 코드·Goodhart 해당 없음',
687
+ // #29974 ACP 실측: 단독 (없음) 뒤에 차단 결함 부재와 통과 근거를 적은 닫힌 문장.
688
+ '막는 결함은 찾지 못했다. ref → 전체 SHA 고정, 이미지 SHA12 태그, Job 쪽 `imageCommit==source.sha`·`image==shelfImage` 가드까지 한 줄로 이어진다.',
687
689
  ]);
690
+ // #30028 ACP 저장 리뷰의 긍정 수용 서술. 광범위한 의미 추정보다 원문을 고정한다.
691
+ const KNOWN_POSITIVE_FINDINGS = new Set([
692
+ '없음. 수용 기준은 코드와 시험 기준으로 충족한다.',
693
+ '프로토타입 키(`constructor`·`__proto__`)를 Map 으로 바르게 센다.',
694
+ '분모는 `task-agent/entrance-denominator` 별도 이벤트로만 나간다. `task-agent/action` 은 그대로다.',
695
+ 'retro 사실과 tasks cover 집계는 분모 줄이 있든 없든 같다. 시험(`retro-cli.test.ts`)이 이를 고정하고, 임시 폴더는 `finally` 의 `rmSync` 로 지운다.',
696
+ // 이 후속 PR 자체의 ACP r2: 닫힌 무소견 문장.
697
+ '없음 — 막는 결함은 찾지 못했다.',
698
+ ]);
699
+ function isPositiveNoFinding(text: string): boolean {
700
+ return KNOWN_POSITIVE_FINDINGS.has(text);
701
+ }
688
702
  /** 괄호 안 `없음` 뒤 설명이 닫힌 무소견 문법에 정확히 들어가는가. */
689
703
  function isLongNoFindingBracket(text: string): boolean {
690
704
  const m = LONG_BRACKETED_SENTINEL.exec(text.trim());
@@ -699,8 +713,11 @@ function isLongNoFindingBracket(text: string): boolean {
699
713
  export function isNoneSentinelFinding(finding: string): boolean {
700
714
  const text = finding.trim();
701
715
  if (!text || isBracketedPlaceholder(text)) return true;
716
+ if (isPositiveNoFinding(text)) return true;
702
717
  if (/^[-—–]+$/.test(text)) return true;
703
718
  const markerText = text.replace(/^[—–-]+\s*|\s*[—–-]+$/g, '').trim();
719
+ const leadingNone = /^[((]\s*(?:없음|none)\s*[))]\s+(.+)$/i.exec(markerText);
720
+ if (leadingNone && KNOWN_NO_FINDING_REMARKS.has(leadingNone[1]!.trim())) return true;
704
721
  if (markerText && (BARE_SENTINEL.test(markerText) || DASH_ONLY_SENTINEL.test(markerText) || DASH_WRAPPED_BRACKETED_SENTINEL.test(markerText))) return true;
705
722
  const bracketed = BRACKETED_SENTINEL.exec(markerText);
706
723
  if (bracketed) {