elanous 0.2.35 → 0.2.36

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 (686) 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/chunks/{d06f9160.a3d9062f95de8ad7.js → 053a429e.9a63436527cc751c.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +287 -0
  5. package/apps/pwa/out/_next/static/chunks/{4346.8601952e73bf5803.js → 1201.afbfc5b1c5e5cbe4.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +64 -0
  11. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +36 -0
  12. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +149 -0
  15. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{3103.0df8da390948bb84.js → 2500.cbc1257b774aae52.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/{7644.17e37ba6f1d4226e.js → 2683.c9773a0c589b031b.js} +3 -3
  20. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +24 -0
  21. package/apps/pwa/out/_next/static/chunks/{4718-17d2af636796a330.js → 275-02ea4c2a33980422.js} +3 -3
  22. package/apps/pwa/out/_next/static/chunks/2812ca6a.3b9f4a7a08885744.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{8714.ff0b7ce3ec3e3ae2.js → 2941.3c3546f96bc6efa7.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +24 -0
  26. package/apps/pwa/out/_next/static/chunks/{9214.63a510d39178e997.js → 2986.45d7652e4f13557e.js} +2 -2
  27. package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/3136.30aaaa5fa03662a3.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{3677-4215f826f6aa68e5.js → 3148-98efd4869d660a87.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +226 -0
  31. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3324.a09703033abcbd2f.js +34 -0
  34. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +8 -0
  36. package/apps/pwa/out/_next/static/chunks/3410.7f9af5ab77cbe65f.js +115 -0
  37. package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +32 -0
  38. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +286 -0
  40. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/{9512.5a76207a730e0491.js → 3727.7949ccaacaa71242.js} +2 -2
  42. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/{8557-e7898769499cd56f.js → 3757-180308bc61021b05.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +74 -0
  45. package/apps/pwa/out/_next/static/chunks/{359-2250789a2d3499e7.js → 3840-5825d56d46976a92.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{da5176c6.6773b6c5994e1d99.js → 3a3d9966.cc4d4585a2708e7c.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +104 -0
  51. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/{9952.5daf5f94063a2b3e.js → 4286.b70c4520306817e8.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/4304.e9b2512834a9e23e.js +23 -0
  54. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{938.66ad1ef0e5abae1c.js → 4615.8525eb0add35eba6.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +148 -0
  57. package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +93 -0
  59. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/{6236.e18cced2d5ba6afb.js → 528.38ce20ef8aa251ff.js} +16 -16
  61. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +122 -0
  62. package/apps/pwa/out/_next/static/chunks/{3408.21d1570602f4b6c0.js → 552.b7d061ad91eeac51.js} +2 -2
  63. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5711.957b095705c12560.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/{1530.0e612369b6fd7ea0.js → 575.d929793a53f27c4b.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/599.c39c571b6733f2a2.js +41 -0
  70. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +79 -0
  71. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +27 -0
  84. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/6925.562d532110879886.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/{7385.50a308a477bdfc21.js → 6943.c6b24124853a47b2.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/{630.fe5a46428d63b013.js → 727.7deb87749b0a343a.js} +1 -1
  88. package/apps/pwa/out/_next/static/chunks/{2018.a741297bce759490.js → 7481.39f7a4654907bf6e.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/{8444.4c26b379ca2b9596.js → 771.c3cdb6c1f7f47c02.js} +17 -17
  92. package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{3589.5444a06bcf6e775c.js → 7891.03f910124a737985.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +62 -0
  100. package/apps/pwa/out/_next/static/chunks/{b2f6ba4d.fb56fdbbf798df33.js → 873d6c12.09bd499f57171543.js} +1 -1
  101. package/apps/pwa/out/_next/static/chunks/{5101.e32282718f99ed6f.js → 8904.7d51af2dc033965c.js} +2 -2
  102. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +90 -0
  104. package/apps/pwa/out/_next/static/chunks/{5637.281e5dec4ea6ecf1.js → 914.8abefd48d579547b.js} +2 -2
  105. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/{4705-194e64e47ca0fbdb.js → 9250-072df22eaadaa6b5.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +77 -0
  111. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{8637.47f5b35afcae5e6b.js → 9514.131c52cc75fe6439.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{1674.2a65fd5668e1cc5f.js → 9789.60f723d18097ec30.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9f31e478.fefcbcd3c388ebc5.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{0368f25d-ad84af92fefee68f.js → ccae1c4b-0cf414f5eff1b10d.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/{cbe38a15.5a032598e39970c6.js → ceba0382.650712b56b85b582.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/{b6705a4f-b9a9047de9eecfd0.js → da5ecc5c-b005ad8cac737d57.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{56d372f2.681ab4ec4c998fae.js → f9a61e4d.1fc2c1dbdd49fe46.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +1 -0
  183. package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → uC-N0emedeNOFuaBQFv-I}/_buildManifest.js +1 -1
  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/docs/goal-context/05-authoring-lessons.jsonl +47 -0
  278. package/docs/goal-context/README.md +3 -0
  279. package/graphs/default-loop.yaml +6 -1
  280. package/graphs/implement-loop.yaml +24 -0
  281. package/graphs/release/recipes.yaml +6 -0
  282. package/graphs/release/release-loop.yaml +17 -4
  283. package/graphs/wizard/recipes.yaml +44 -0
  284. package/graphs/wizard/wizard-loop.yaml +44 -0
  285. package/graphs/work/research-report.yaml +2 -0
  286. package/package.json +1 -1
  287. package/scripts/ci-typecheck-changed.ts +139 -5
  288. package/scripts/coord-role-pack.ts +1 -1
  289. package/scripts/first10-gate.ts +416 -0
  290. package/scripts/fleet/wsl-node-setup.sh +432 -0
  291. package/scripts/release-loop/docs-node.ts +204 -8
  292. package/scripts/release-loop/gate-node.ts +249 -53
  293. package/scripts/release-loop/node-verdict.ts +2 -0
  294. package/scripts/release-loop/resume-cap.ts +14 -34
  295. package/scripts/release-loop/resume-release.ts +37 -11
  296. package/scripts/release-loop/traffic-node.ts +59 -0
  297. package/scripts/release-loop/traffic-transition.ts +159 -0
  298. package/scripts/rhythm/daily.ts +137 -3
  299. package/scripts/ux-sim.ts +53 -0
  300. package/skills/README.md +1 -0
  301. package/src/acp/core-turn-bridge.ts +48 -6
  302. package/src/agent/delegate-hint.ts +16 -0
  303. package/src/agent/runner.ts +82 -2
  304. package/src/agent/task-notification.ts +56 -10
  305. package/src/agent/types.ts +4 -0
  306. package/src/agent-substrate/pr-reviewer.ts +55 -3
  307. package/src/agent-substrate/review-intent.ts +29 -2
  308. package/src/agent-substrate/review-observation.ts +3 -0
  309. package/src/agent-substrate/self-review-cli.ts +168 -16
  310. package/src/autopilot/mission-codebase-gate.ts +141 -12
  311. package/src/autopilot/pr-manager.ts +25 -5
  312. package/src/boot/daemon-tools/self-implement.ts +1 -0
  313. package/src/budget/usage-outcomes.ts +8 -4
  314. package/src/capture/tui-self-report.ts +102 -0
  315. package/src/chat/goal-continue-verdict.ts +41 -0
  316. package/src/chat/index.ts +30 -4
  317. package/src/chat/internal-turn-origin.ts +1 -0
  318. package/src/chat/paste-fold.ts +86 -0
  319. package/src/chat/tool-render/block.ts +32 -0
  320. package/src/chat/tool-render/dispatch.ts +2 -20
  321. package/src/chat/tool-render/result-text.ts +98 -0
  322. package/src/chat/turn-typeahead.ts +70 -7
  323. package/src/cli/config-audit.ts +119 -0
  324. package/src/cli/doctor-cli.ts +22 -0
  325. package/src/cli/guardian-cli.ts +10 -0
  326. package/src/cli/herdr-cli.ts +34 -0
  327. package/src/cli/light-entry-route.ts +6 -3
  328. package/src/cli/log-event-names.ts +2 -0
  329. package/src/cli/make-cli.ts +247 -11
  330. package/src/cli/msg-cli.ts +117 -3
  331. package/src/cli/pr-cli.ts +29 -16
  332. package/src/cli/pr-land-base-read.ts +11 -2
  333. package/src/cli/pr-land-heavy-remote.ts +6 -3
  334. package/src/cli/pr-land-overlap-evidence.ts +23 -4
  335. package/src/cli/pr-land-recovery.ts +117 -1
  336. package/src/cli/pty-takeover-cli.ts +8 -7
  337. package/src/cli/release-cli.ts +21 -5
  338. package/src/cli/release-single-flight.ts +1 -1
  339. package/src/cli/tasks-card-show.ts +162 -0
  340. package/src/cli/tasks-cli.ts +574 -356
  341. package/src/cli/tasks-read-cli.ts +197 -0
  342. package/src/core-turn/run-core-turn.ts +4 -2
  343. package/src/core-turn/run-goal-loop.ts +73 -16
  344. package/src/core-turn/types.ts +6 -1
  345. package/src/dashboard/context/keys.ts +8 -31
  346. package/src/dashboard/index.ts +202 -49
  347. package/src/dashboard/input/agent-wake.ts +7 -1
  348. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
  349. package/src/dashboard/input/chat-main-slash-command.ts +4 -2
  350. package/src/dashboard/input/goal-continue.ts +210 -0
  351. package/src/dashboard/input/goal-interim.ts +2 -0
  352. package/src/dashboard/input/internal-turn.ts +2 -8
  353. package/src/dashboard/input/seat-autowake.ts +9 -7
  354. package/src/dashboard/input/turn-autoheal.ts +52 -0
  355. package/src/dashboard/seat-boot-preamble.ts +132 -5
  356. package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
  357. package/src/dashboard/slash-runtime/dashboard-handlers.ts +3 -2
  358. package/src/dashboard/slash-runtime/model-choices.ts +15 -0
  359. package/src/dashboard/stale-install-check.ts +3 -99
  360. package/src/debug/batch-queue.ts +119 -0
  361. package/src/debug/tui-log-tag.ts +67 -0
  362. package/src/display/agent-surface.ts +7 -0
  363. package/src/domains/standalone-log-sink.ts +15 -2
  364. package/src/esc-abort-gate.ts +69 -0
  365. package/src/git-fs/worktree.ts +95 -1
  366. package/src/graph-runner/graph-cli.ts +18 -0
  367. package/src/graph-runner/runner.ts +20 -11
  368. package/src/graph-wizard/generate.ts +108 -4
  369. package/src/graph-wizard/steps.ts +15 -0
  370. package/src/grounding/proactive-ground.ts +86 -0
  371. package/src/harness/control-inbox.ts +49 -1
  372. package/src/harness/harness-cli-command.ts +51 -7
  373. package/src/harness/harness-incidents.ts +52 -1
  374. package/src/harness/pod-control-send.ts +33 -5
  375. package/src/harness/self-send-remote.ts +69 -0
  376. package/src/harness/self-send-routing-guard.ts +6 -0
  377. package/src/harness/self-send-target.ts +4 -3
  378. package/src/index.ts +327 -12
  379. package/src/input-core/context-key-runtime.ts +21 -0
  380. package/src/light-cli.ts +6 -1
  381. package/src/llm-wellformed.ts +70 -0
  382. package/src/llm.ts +35 -4
  383. package/src/loops/msg-wake.ts +35 -39
  384. package/src/loops/orchestrator/inbox.ts +59 -11
  385. package/src/loops/orchestrator/knowhow-pack.ts +364 -0
  386. package/src/loops/orchestrator/tick.ts +5 -1
  387. package/src/maturity/feature-maturity.ts +1 -1
  388. package/src/models/prompts.ts +17 -2
  389. package/src/msg/msg-post-office.ts +116 -0
  390. package/src/mss/logging/log-store.ts +79 -22
  391. package/src/nexus/api/decisions-route.ts +38 -18
  392. package/src/nexus/api/graph-wizard-api.ts +20 -2
  393. package/src/nexus/boot/register-mcp-clients.ts +263 -38
  394. package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
  395. package/src/onboarding/first-run.ts +37 -6
  396. package/src/onboarding/web-first.ts +43 -11
  397. package/src/ops/overview-collect.ts +12 -6
  398. package/src/ops/overview.ts +3 -3
  399. package/src/persona/loader.ts +11 -0
  400. package/src/persona/types.ts +8 -0
  401. package/src/prompt-library/session-guidance.ts +14 -0
  402. package/src/provider-summary.ts +8 -0
  403. package/src/pty-shell/herdr-agent-report.ts +118 -9
  404. package/src/pty-shell/herdr-prompt.ts +266 -0
  405. package/src/pty-shell/pty-control-ipc.ts +151 -8
  406. package/src/pty-shell/pty-special-keys.ts +42 -2
  407. package/src/pty-shell/stale-install-check.ts +99 -0
  408. package/src/pty-shell/tui-run-state.ts +14 -2
  409. package/src/release-loop/auto-start.ts +20 -2
  410. package/src/release-loop/checklist.ts +76 -4
  411. package/src/release-loop/rehearsal.ts +36 -20
  412. package/src/repl/index.ts +19 -1
  413. package/src/seat-loop/knowhow-lint.ts +1 -1
  414. package/src/self-dev/decompose-proposal.ts +172 -20
  415. package/src/self-dev/decompose.ts +61 -0
  416. package/src/self-dev/dev-cli.ts +37 -3
  417. package/src/self-dev/dev-pipeline.ts +8 -2
  418. package/src/self-dev/draft-triage-rules.ts +31 -0
  419. package/src/self-dev/glm-credential-guard.ts +77 -0
  420. package/src/self-dev/graph-journey-nodes.ts +1 -0
  421. package/src/self-dev/graph-journey-route.ts +12 -2
  422. package/src/self-dev/orchestrate-cli.ts +68 -3
  423. package/src/self-dev/orchestrate.ts +116 -17
  424. package/src/self-dev/run-supervisor.ts +55 -2
  425. package/src/self-dev/run-types.ts +1 -1
  426. package/src/self-health/autoheal.ts +153 -0
  427. package/src/self-health/signatures.ts +6 -0
  428. package/src/self-implement/device-first.ts +116 -0
  429. package/src/self-implement/doctor-visit.ts +239 -1
  430. package/src/self-implement/evidence-command-budget.ts +80 -0
  431. package/src/self-implement/goal-author-cli.ts +1 -0
  432. package/src/self-implement/goal-author-decompose.ts +265 -4
  433. package/src/self-implement/goal-author.ts +33 -8
  434. package/src/self-implement/goal-elaborate.ts +176 -22
  435. package/src/self-implement/goal-refine.ts +3 -0
  436. package/src/self-implement/graph-variant.ts +40 -6
  437. package/src/self-implement/headless-elanous-driver.ts +19 -3
  438. package/src/self-implement/off-diff-evidence.ts +58 -6
  439. package/src/self-implement/orchestrator.ts +222 -21
  440. package/src/self-implement/pod-warm-pool-profile.ts +1 -0
  441. package/src/self-implement/pwa-import-graph.ts +1 -1
  442. package/src/self-implement/rework-policy.ts +30 -0
  443. package/src/self-implement/run-ledger.ts +108 -0
  444. package/src/self-implement/run-ttl.ts +38 -24
  445. package/src/self-implement/scope-adjacency.ts +3 -1
  446. package/src/self-implement/seams.ts +60 -4
  447. package/src/self-implement/wiring-check.ts +358 -0
  448. package/src/shell-env-bootstrap.ts +11 -4
  449. package/src/skills/runner.ts +4 -2
  450. package/src/skills/tools/agent.ts +290 -48
  451. package/src/skills/tools/schedule-wakeup.ts +23 -4
  452. package/src/skills/tools/shell.ts +61 -6
  453. package/src/skills/tools/terminal-modal-inject.ts +1 -2
  454. package/src/skills/tools/terminal-modal.ts +10 -8
  455. package/src/skills/url-router.ts +41 -1
  456. package/src/smart-wizard/run.ts +66 -0
  457. package/src/status/bar.ts +34 -6
  458. package/src/status/status-provider-info.ts +37 -6
  459. package/src/steward/rejudge-tick.ts +10 -2
  460. package/src/steward/ta-repair-event-collect.ts +17 -6
  461. package/src/task-agent/actions.ts +3 -1
  462. package/src/task-agent/land-queue.ts +21 -8
  463. package/src/task-agent/live-moves.ts +22 -6
  464. package/src/task-agent/mission.ts +30 -0
  465. package/src/task-agent/rejudge-on-head.ts +15 -0
  466. package/src/task-agent/repair-cycle.ts +138 -32
  467. package/src/task-agent/repair-next-move.ts +31 -3
  468. package/src/task-agent/repair-outcomes.ts +29 -0
  469. package/src/task-agent/repair-worker.ts +14 -4
  470. package/src/task-agent/shadow.ts +41 -3
  471. package/src/task-agent/task-card-prefix.ts +2 -0
  472. package/src/task-agent/task-hand.ts +477 -22
  473. package/src/task-agent/task-parent-role-llm.ts +36 -0
  474. package/src/task-agent/tier-split.ts +78 -9
  475. package/src/task-orchestrator/surfaces/pod-account-broker.ts +9 -0
  476. package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
  477. package/src/task-orchestrator/surfaces/pod-command-job.ts +86 -5
  478. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
  479. package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
  480. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +11 -0
  481. package/src/task-orchestrator/surfaces/pod-pool.ts +76 -4
  482. package/src/task-orchestrator/surfaces/pod-provenance.ts +8 -2
  483. package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
  484. package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
  485. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
  486. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
  487. package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
  488. package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
  489. package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
  490. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +4 -0
  491. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +485 -36
  492. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
  493. package/src/task-orchestrator/surfaces/self-implement-pod.ts +396 -19
  494. package/src/task-orchestrator/surfaces/self-implement.ts +42 -2
  495. package/src/tool-runtime/index.ts +15 -2
  496. package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
  497. package/src/tty-foreground.ts +155 -0
  498. package/src/tui/chat/goal-interim.ts +173 -0
  499. package/src/tui/chat/log-view.ts +205 -18
  500. package/src/tui/chat/self-health-status.ts +232 -0
  501. package/src/tui/entry.ts +370 -81
  502. package/src/tui/input/composer.ts +8 -1
  503. package/src/tui/slash/compact-command.ts +7 -0
  504. package/src/tui/slash/compact.ts +1 -7
  505. package/src/tui/slash/resume.ts +75 -0
  506. package/src/tui-client/local-chat-turn.ts +45 -2
  507. package/src/tui-client/next-dashboard-runtime.ts +8 -0
  508. package/src/tui-client/next-loop-command.ts +70 -0
  509. package/src/tui-client/next-wakeup.ts +191 -0
  510. package/src/tui.ts +37 -0
  511. package/src/ui/modal-adapter.ts +2 -2
  512. package/src/ux-sim/classic-tui-seat-scenarios.ts +516 -0
  513. package/src/ux-sim/cli-config-audit-device.ts +121 -0
  514. package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
  515. package/src/ux-sim/event-monkey.ts +3 -2
  516. package/src/ux-sim/fake-bin.ts +45 -0
  517. package/src/ux-sim/fake-herdr.ts +238 -0
  518. package/src/ux-sim/fake-llm.ts +111 -6
  519. package/src/ux-sim/fault-glm-no-credential.ts +116 -0
  520. package/src/ux-sim/fault-nextmove-dispatch.ts +102 -1
  521. package/src/ux-sim/fault-scope-escape-lift.ts +33 -6
  522. package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
  523. package/src/ux-sim/goal-device.ts +619 -0
  524. package/src/ux-sim/in-process-cli.ts +22 -5
  525. package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
  526. package/src/ux-sim/mock-authoring-first-run.ts +97 -0
  527. package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
  528. package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
  529. package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
  530. package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
  531. package/src/ux-sim/next-tui-seat-scenarios.ts +631 -0
  532. package/src/ux-sim/onboarding-first-run-device.ts +269 -0
  533. package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
  534. package/src/ux-sim/subagent-tools-device.ts +81 -0
  535. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
  536. package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
  537. package/src/version/packed-revision.json +1 -1
  538. package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +0 -32
  540. package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +0 -41
  541. package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +0 -24
  542. package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +0 -74
  543. package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +0 -148
  553. package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +0 -34
  555. package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +0 -77
  556. package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +0 -62
  559. package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +0 -90
  560. package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +0 -36
  563. package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +0 -79
  565. package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +0 -122
  567. package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/4441-875b97f5821ed58a.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +0 -286
  570. package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +0 -24
  573. package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +0 -23
  582. package/apps/pwa/out/_next/static/chunks/5483-dd5d7697f6bdb106.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +0 -287
  586. package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +0 -8
  593. package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +0 -27
  595. package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +0 -93
  597. package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +0 -149
  604. package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +0 -104
  605. package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +0 -226
  615. package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +0 -64
  617. package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +0 -115
  622. package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/morning/page-47c5d4db587266bd.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/term/page-dc0a532f5b9196ec.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +0 -1
  686. /package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → uC-N0emedeNOFuaBQFv-I}/_ssgManifest.js +0 -0
@@ -13,6 +13,7 @@ import remarkParse from 'remark-parse';
13
13
  import { unified } from 'unified';
14
14
 
15
15
  import { parseGoalType, type GoalType } from '../self-implement/goal-author.js';
16
+ import { DEVICE_FIRST_STEP } from '../self-implement/device-first.js';
16
17
  import type { DesignCheckOutcome } from '../design/design-check.js';
17
18
  import type { DesignGateResult } from '../design/design-gate.js';
18
19
  import type { PriorDraftFinding } from '../self-implement/prior-draft-findings.js';
@@ -525,6 +526,30 @@ function goalFileBlock(goalFile: string | undefined): Block | undefined {
525
526
  : undefined;
526
527
  }
527
528
 
529
+ /** tier-split 이 골 본문에 남긴 조각 표지를 리뷰의 책임 경계로 옮긴다. */
530
+ function sliceReviewScopeBlock(goal: string): Block | undefined {
531
+ const fencedLines = topLevelCodeLines(goal);
532
+ const lines = goal.split('\n').filter((_, index) => !fencedLines.has(index));
533
+ const match = lines.map((line) => /^\s*조각\s+(\d+)\/(\d+)\s*—/.exec(line)).find(Boolean);
534
+ if (!match) return undefined;
535
+ const index = Number(match[1]);
536
+ const total = Number(match[2]);
537
+ if (!Number.isSafeInteger(index) || !Number.isSafeInteger(total) || index < 1 || total < 2 || index > total) return undefined;
538
+
539
+ const deviceStep = `동작: ${DEVICE_FIRST_STEP}`;
540
+ const device = lines.some((line) => line.split('·').some((part) => {
541
+ const stage = part.trimStart();
542
+ return stage === deviceStep || stage.startsWith(`${deviceStep} `);
543
+ }));
544
+ const title = '조각 계약 — 리뷰 범위';
545
+ const scopeLines = [
546
+ `${title}\n조각 ${index}/${total} — 현재 조각의 동작·변경 파일·자기 완료 경계로 이 PR을 판정한다.`,
547
+ ...(index < total ? ['다음 조각 몫과 부모 전체 완료 경계의 미완료만으로 이 조각의 must-fix를 만들지 말 것.'] : []),
548
+ ...(device ? ['장치 조각: 호출부 없는 export의 소비자는 다음 피처 조각이다. 이 조각에서 호출부 부재만으로 must-fix를 만들지 말고 장치 시험과 사용 가능한 인터페이스를 판정한다.'] : []),
549
+ ];
550
+ return { title, text: scopeLines.join('\n') };
551
+ }
552
+
528
553
  function isLightweightGoal(goal: string): boolean {
529
554
  try {
530
555
  const tree = unified().use(remarkParse).use(remarkGfm).parse(goal) as MarkdownNode;
@@ -599,6 +624,7 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
599
624
  const boundaries = i.scopeBoundaries ?? mined.scopeBoundaries;
600
625
  const unverifiedBoundaryCandidates = mined.unverifiedBoundaryCandidates;
601
626
  const goalType = goalTypeBlock(i.goal);
627
+ const sliceScope = sliceReviewScopeBlock(i.goal);
602
628
  // ⚠️ 목표 블록에는 **추출된 절을 뺀 나머지**를 넣는다(리뷰 should-fix) — 골 원문을 통째로 넣고
603
629
  // 그 안의 수용기준을 다시 목록으로 붙이면 **같은 내용이 두 번** 들어가 4000자 예산을 먹고,
604
630
  // 후순위 블록(스코프 경계)이 불필요하게 잘린다.
@@ -631,7 +657,7 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
631
657
  const context = lightweightGoalContext(i.goal, i.goalFile!.trim());
632
658
  const boundaryBlock = listBlock('의도적 스코프 경계', boundaries);
633
659
  const liteBlocks = [
634
- acceptanceBlock, context, boundaryBlock, shardBoundary, priorFindings, applied,
660
+ acceptanceBlock, context, boundaryBlock, sliceScope, shardBoundary, priorFindings, applied,
635
661
  runFacts, goalType, preexisting, importerTestsNotRun,
636
662
  gateEvidence, designCheck, designGate, shardSiblings, coverage, claims,
637
663
  listBlock('검증 못 한 경계 후보 (결정 아님 — 이것만으로 must-fix 를 면제하지도, 만들지도 말 것)', unverifiedBoundaryCandidates),
@@ -648,6 +674,7 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
648
674
  // ⚠️ 이것은 «렌더 순서»만 바꾼다 — 예산 배분 순서(`order`)와 보호 블록은 아래에서 따로 정한다.
649
675
  const blocks: Block[] = [
650
676
  runFacts,
677
+ sliceScope,
651
678
  priorFindings,
652
679
  goalFile,
653
680
  goalType,
@@ -667,7 +694,7 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
667
694
  listBlock('검증 못 한 경계 후보 (결정 아님 — 이것만으로 must-fix 를 면제하지도, 만들지도 말 것)', unverifiedBoundaryCandidates),
668
695
  ].filter((b): b is Block => Boolean(b));
669
696
 
670
- const protectedBlocks = blocks.filter((block) => block.title === '수용기준' || block.title === '의도적 스코프 경계');
697
+ const protectedBlocks = blocks.filter((block) => block.title === '수용기준' || block.title === '의도적 스코프 경계' || block === sliceScope);
671
698
  // ⛔⭐ **증거가 목표보다 먼저다**(실측 수리). 종전 순서는 `[보호블록, 목표, 나머지]` 였고, 골이
672
699
  // 15,383자면 `목표` 가 남은 예산을 통째로 먹어 자식의 `EVIDENCE/RESULT` 가 **제목만 남고
673
700
  // `…[N개 생략됨]`** 이 됐다. 그러면 리뷰는 *"실행하지 않았다 · 증거가 없다"* 를 적고 — 그것이
@@ -100,6 +100,8 @@ interface ReviewObservation {
100
100
  readonly mustFix: number;
101
101
  /** 목표 범위를 이유로 되돌리거나 분리하라는 MUST-FIX의 관측용 빈도. */
102
102
  readonly scopeRevertMustFix: number;
103
+ /** SCOPE-ESCAPE-AS-REFINE — must-fix 에서 shouldFix 로 강등된 범위-되돌림 지적 수. */
104
+ readonly scopeRevertDemoted: number;
103
105
  readonly shouldFix: number;
104
106
  /** ⭐ 지적 **식별용** 앞부분. 이게 있어야 "같은 지적이 반복되나"를 로그만으로 볼 수 있다. */
105
107
  readonly mustFixItems: readonly string[];
@@ -197,6 +199,7 @@ export function buildReviewObservation(input: ReviewObservationInput): ReviewObs
197
199
  ...(review?.failureReason ? { failureReason: safeLogText(review.failureReason) } : {}),
198
200
  mustFix: mustFix.length,
199
201
  scopeRevertMustFix: mustFix.filter(isScopeRevertMustFix).length,
202
+ scopeRevertDemoted: review?.scopeRevertDemoted?.length ?? 0,
200
203
  shouldFix: shouldFix.length,
201
204
  mustFixItems: clip(mustFix),
202
205
  shouldFixItems: clip(shouldFix),
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // index.ts 의 액션은 옵션 파싱과 실제 의존 배선만 남는다(얇은 껍데기).
16
16
 
17
- import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
17
+ import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
18
18
  import { homedir, tmpdir } from 'node:os';
19
19
  import { dirname, join } from 'node:path';
20
20
  import { effectiveInstanceRoot } from '../instance/resolve.js';
@@ -139,27 +139,36 @@ export interface SelfReviewCliOutcome {
139
139
  }
140
140
 
141
141
  /** Saved results are round evidence only when their PR, exact head and reviewed status agree. */
142
- export function savedReviewHeads(pr: string, root = effectiveInstanceRoot()): string[] {
142
+ function savedReviewRecords(pr: string, root = effectiveInstanceRoot()): Array<{ head: string; reviewedAt: number }> {
143
143
  const dir = join(root, 'review-results');
144
144
  let names: string[];
145
145
  try { names = readdirSync(dir); } catch { return []; }
146
146
  // Manual review saves in the operating house also use head10; the JSON's full head is authoritative.
147
147
  const matching = new RegExp(`^.+-${pr}-([a-f0-9]{7,40})\\.json$`, 'i');
148
- const heads = new Set<string>();
148
+ const records = new Map<string, { head: string; reviewedAt: number }>();
149
149
  for (const name of names) {
150
150
  const match = matching.exec(name);
151
151
  if (!match) continue;
152
152
  try {
153
- const raw: unknown = JSON.parse(readFileSync(join(dir, name), 'utf8'));
153
+ const recordPath = join(dir, name);
154
+ const raw: unknown = JSON.parse(readFileSync(recordPath, 'utf8'));
154
155
  if (!raw || typeof raw !== 'object' || Array.isArray(raw)) continue;
155
156
  const result = raw as Record<string, unknown>;
156
157
  const head = result.headCommit;
157
158
  if (String(result.pr) !== pr || result.reviewed !== true || typeof head !== 'string'
158
159
  || !COMMIT_OID.test(head) || !head.toLowerCase().startsWith(match[1]!.toLowerCase())) continue;
159
- heads.add(head.toLowerCase());
160
+ const normalized = head.toLowerCase();
161
+ const existing = records.get(normalized);
162
+ const reviewedAt = typeof result.reviewedAt === 'number' && Number.isFinite(result.reviewedAt)
163
+ ? result.reviewedAt : statSync(recordPath).mtimeMs;
164
+ if (!existing || reviewedAt > existing.reviewedAt) records.set(normalized, { head: normalized, reviewedAt });
160
165
  } catch { /* corrupt or partial result is not a completed round */ }
161
166
  }
162
- return [...heads];
167
+ return [...records.values()];
168
+ }
169
+
170
+ export function savedReviewHeads(pr: string, root = effectiveInstanceRoot()): string[] {
171
+ return savedReviewRecords(pr, root).map(({ head }) => head);
163
172
  }
164
173
 
165
174
  function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string | null {
@@ -178,14 +187,42 @@ function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string |
178
187
  } catch { return null; }
179
188
  }
180
189
 
190
+ function readCapOverride(pr: string): { head: string; reason: string } | undefined {
191
+ try {
192
+ const value = JSON.parse(readFileSync(join(effectiveInstanceRoot(), 'review-results', `cap-override-${pr}.json`), 'utf8')) as Record<string, unknown>;
193
+ if (String(value.pr) !== pr || typeof value.head !== 'string' || !COMMIT_OID.test(value.head)
194
+ || typeof value.reason !== 'string' || !value.reason.trim()) return undefined;
195
+ return { head: value.head.toLowerCase(), reason: value.reason };
196
+ } catch { return undefined; }
197
+ }
198
+
181
199
  function claimCapOverride(pr: string, head: string, reason: string, now: number): boolean {
182
200
  const dir = join(effectiveInstanceRoot(), 'review-results');
183
201
  try {
184
202
  mkdirSync(dir, { recursive: true });
185
- // wx is atomic across concurrent CLI processes; a PR receives one recorded exception.
186
- writeFileSync(join(dir, `cap-override-${pr}.json`), JSON.stringify({ pr, head, reason, claimedAt: now }) + '\n', { flag: 'wx' });
203
+ const normalizedHead = head.toLowerCase();
204
+ const authorizationPath = join(dir, `cap-override-${pr}.json`);
205
+ // The first over-cap review creates the durable, PR-scoped authorization record atomically.
206
+ writeFileSync(authorizationPath, JSON.stringify({ pr, head: normalizedHead, reason, claimedAt: now, use: 'initial-authorization' }) + '\n', { flag: 'wx' });
187
207
  return true;
188
- } catch { return false; }
208
+ } catch {
209
+ // An OP authorization applies to later heads of this PR while the allowlist remains active.
210
+ // Keep the initial claim immutable, and atomically record each additional head separately so
211
+ // retries of the same head cannot spend the grant twice.
212
+ try {
213
+ const authorization = JSON.parse(readFileSync(join(dir, `cap-override-${pr}.json`), 'utf8')) as Record<string, unknown>;
214
+ const authorizedHead = authorization.head;
215
+ if (String(authorization.pr) !== pr || typeof authorization.reason !== 'string' || !authorization.reason.trim()
216
+ || authorization.reason !== reason
217
+ || typeof authorizedHead !== 'string' || !COMMIT_OID.test(authorizedHead)
218
+ || authorizedHead.toLowerCase() === head.toLowerCase()) return false;
219
+ const normalizedHead = head.toLowerCase();
220
+ writeFileSync(join(dir, `cap-override-${pr}-head-${normalizedHead}.json`), JSON.stringify({
221
+ pr, head: normalizedHead, reason, claimedAt: now, use: 'subsequent-head', authorizationHead: authorizedHead.toLowerCase(),
222
+ }) + '\n', { flag: 'wx' });
223
+ return true;
224
+ } catch { return false; }
225
+ }
189
226
  }
190
227
 
191
228
  /** OP owns this list. Missing, unreadable, or malformed traffic never grants a review exception. */
@@ -1343,6 +1380,34 @@ export function selfReviewJsonLine(results: readonly unknown[]): string {
1343
1380
  return JSON.stringify(results.length === 1 ? results[0] : results) + '\n';
1344
1381
  }
1345
1382
 
1383
+ // Normalize only whole-item forms whose complete text is an explicit no-finding
1384
+ // sentinel. Any extra clause stays in mustFix (fail-closed).
1385
+ const NO_FINDING_REVIEW_NOTE_ALLOWLIST: readonly RegExp[] = [
1386
+ /^(?:없음|해당\s*없음|none|nothing|n\/a)[.!。]?$/i,
1387
+ /^\((?:없음|해당\s*없음|none|nothing|n\/a)\)[.!。]?$/i,
1388
+ /^\(이 조각에서 확인된 코어 결함 없음\s*[—–-]\s*명시 intent 기준 mustFix 는 비움\)$/i,
1389
+ /^\(이 조각에서 검증된 (?:차단 )?결함은 발견되지 않음(?:\s*\(mustFix \[\]\))?\)$/i,
1390
+ ];
1391
+
1392
+ function isNoFindingReviewNote(finding: string): boolean {
1393
+ const wholeItem = finding.trim();
1394
+ return NO_FINDING_REVIEW_NOTE_ALLOWLIST.some((form) => form.test(wholeItem));
1395
+ }
1396
+
1397
+ function normalizeSavedReviewMustFix(result: Record<string, unknown>): { result: Record<string, unknown>; count: number } {
1398
+ if (!Array.isArray(result.mustFix)) return { result, count: 0 };
1399
+ const noFindingNotes = result.mustFix.filter((finding): finding is string =>
1400
+ typeof finding === 'string' && isNoFindingReviewNote(finding));
1401
+ if (noFindingNotes.length === 0) return { result, count: 0 };
1402
+ const retained = result.mustFix.filter((finding) =>
1403
+ typeof finding !== 'string' || !isNoFindingReviewNote(finding));
1404
+ const existingNotes = Array.isArray(result.noFindingNotes) ? result.noFindingNotes : [];
1405
+ return {
1406
+ result: { ...result, mustFix: retained, noFindingNotes: [...existingNotes, ...noFindingNotes] },
1407
+ count: noFindingNotes.length,
1408
+ };
1409
+ }
1410
+
1346
1411
  export async function runSelfReviewCliCommand(
1347
1412
  prArgs: string[],
1348
1413
  opts: SelfReviewCliOpts,
@@ -1440,7 +1505,9 @@ async function runSelfReviewCliCommandPinned(
1440
1505
  return { results: opts.json ? [{ error: message, requestedModel }] : [], failed: 1 };
1441
1506
  }
1442
1507
  const configuredReviewModel = opts.configuredReviewModel?.trim() || undefined;
1443
- const model = useAcp ? `acp:${acpBackend}${acpModel ? `/${acpModel}` : ''}` : (opts.model || envModel || configuredReviewModel || roleFallbackModel || tierModel('better'));
1508
+ // REVIEW-MODEL-ALIAS-PROVIDER: provider pinning needs GLM's OpenRouter model id, not the bare alias.
1509
+ const explicitApiModel = requestedModel?.toLowerCase() === 'glm' ? ROLE_REVIEWER_FALLBACK_MODEL : opts.model;
1510
+ const model = useAcp ? `acp:${acpBackend}${acpModel ? `/${acpModel}` : ''}` : (explicitApiModel || envModel || configuredReviewModel || roleFallbackModel || tierModel('better'));
1444
1511
  const configuredReviewSelected = !opts.model?.trim() && !envModel && Boolean(configuredReviewModel);
1445
1512
  let roleReviewer: { llm: (prompt: string, images?: readonly ReviewImage[]) => Promise<string>; model: string } | undefined;
1446
1513
  let roleReviewerUnavailableReason: string | undefined;
@@ -1482,16 +1549,17 @@ async function runSelfReviewCliCommandPinned(
1482
1549
  const previousHeads = savedReviewHeads(pr);
1483
1550
  const previousRoundCount = previousHeads.length;
1484
1551
  const reason = opts.overCapReason?.trim();
1552
+ const authorization = previousRoundCount >= 5 ? readCapOverride(pr) : undefined;
1485
1553
  deps.observeDoctorReview?.('round-counted', { pr, previousRoundCount, round: previousRoundCount + 1 });
1486
1554
  const opAllowed = previousRoundCount >= 5 && opAllowsReviewOverCap(pr);
1487
1555
  if (previousRoundCount >= 5) {
1488
1556
  deps.observeDoctorReview?.('cap-attempt', { pr, previousRoundCount, round: previousRoundCount + 1, reasonProvided: Boolean(reason), opAllowed }, { level: 'warn' });
1489
1557
  }
1490
- if (previousRoundCount >= 5 && (!reason || !opAllowed)) {
1558
+ if (previousRoundCount >= 5 && (!opAllowed || (!authorization && !reason))) {
1491
1559
  const refusalHead = prHeadCommit(pr, deps).value;
1492
1560
  const message = !opAllowed
1493
1561
  ? `PR ${pr}: r5 상한 초과 리뷰는 OP traffic.json reviewOverCapAllow 허용 목록에 있어야 합니다.`
1494
- : `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다. 새 리뷰는 --over-cap-reason <사유>로 PR당 한 번만 허용됩니다.`;
1562
+ : `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다. OP 허용 상태와 --over-cap-reason <사유>가 필요합니다.`;
1495
1563
  deps.observeDoctorReview?.('cap-refused', { pr, head: refusalHead, previousRoundCount, round: previousRoundCount + 1, reason: opAllowed ? 'missing-reason' : 'not-op-allowlisted' }, { level: 'warn' });
1496
1564
  deps.error(message);
1497
1565
  if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: refusalHead });
@@ -1499,9 +1567,69 @@ async function runSelfReviewCliCommandPinned(
1499
1567
  continue;
1500
1568
  }
1501
1569
  const diffRead = readDiffAtHead(pr, deps);
1502
- if (previousRoundCount >= 5 && reason) {
1503
- // Claim only the exact SHA-pinned diff that the reviewer will see; never spend the sole
1504
- // exception on a separately read head that may move before readDiffAtHead.
1570
+ if (previousRoundCount >= 5 && authorization && diffRead.headCommit.toLowerCase() === authorization.head) {
1571
+ const message = `PR ${pr}: 동일 head는 이미 승인 소모 기록이 있습니다.`;
1572
+ deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: 'same-head-already-used' }, { level: 'warn' });
1573
+ deps.error(message);
1574
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1575
+ failed += 1;
1576
+ continue;
1577
+ }
1578
+ if (previousRoundCount >= 5 && authorization && reason && reason !== authorization.reason) {
1579
+ const message = `PR ${pr}: 기존 PR 승인의 사유와 일치하지 않습니다.`;
1580
+ deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: 'authorization-reason-mismatch' }, { level: 'warn' });
1581
+ deps.error(message);
1582
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1583
+ failed += 1;
1584
+ continue;
1585
+ }
1586
+ let mergeOnlyDeltaRange: { base: string; head: string } | undefined;
1587
+ if (previousRoundCount >= 5 && authorization) {
1588
+ const git = deps.git;
1589
+ if (!git || diffRead.source !== 'sha-pinned' || diffRead.headCommitState !== 'known'
1590
+ || diffRead.currentHeadCommitState !== 'known' || diffRead.stale || diffRead.diff.status !== 0) {
1591
+ const message = `PR ${pr}: 후속 head의 merge-only 여부를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
1592
+ deps.error(message);
1593
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1594
+ failed += 1;
1595
+ continue;
1596
+ }
1597
+ const savedRecords = savedReviewRecords(pr);
1598
+ const latestReviewed = savedRecords.reduce<(typeof savedRecords)[number] | undefined>(
1599
+ (latest, record) => !latest || record.reviewedAt > latest.reviewedAt ? record : latest, undefined,
1600
+ );
1601
+ const classificationBase = latestReviewed?.head ?? authorization.head;
1602
+ const ancestry = git(['merge-base', '--is-ancestor', classificationBase, diffRead.headCommit], 10_000);
1603
+ const parents = git(['rev-list', '--parents', '-n', '1', diffRead.headCommit], 10_000);
1604
+ const parentFields = parents.stdout.trim().split(/\s+/);
1605
+ const headIsMerge = parentFields.length > 2;
1606
+ const deltaHead = headIsMerge ? parentFields[1] : diffRead.headCommit;
1607
+ if ((ancestry.status !== 0 && ancestry.status !== 1) || parents.status !== 0 || parentFields[0]?.toLowerCase() !== diffRead.headCommit.toLowerCase()
1608
+ || !COMMIT_OID.test(deltaHead) || classificationBase === diffRead.headCommit.toLowerCase()) {
1609
+ const message = `PR ${pr}: 후속 head ancestry 또는 parent 정보를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
1610
+ deps.error(message);
1611
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1612
+ failed += 1;
1613
+ continue;
1614
+ }
1615
+ // A non-ancestor head can be a force-push rewind or rebase. It is still
1616
+ // reviewed from the pinned full PR diff; only a proven descendant can
1617
+ // qualify for the merge-only delta path.
1618
+ if (ancestry.status === 0) {
1619
+ // Non-merge commits brought in from main are reachable but are not on
1620
+ // this first-parent line. A merge-only head ends at its first parent;
1621
+ // a later PR commit remains in the candidate range.
1622
+ const commits = git(['rev-list', '--first-parent', '--no-merges', `${classificationBase}..${deltaHead}`], 10_000);
1623
+ if (commits.status !== 0) {
1624
+ const message = `PR ${pr}: 후속 head의 PR 변경 여부를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
1625
+ deps.error(message);
1626
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1627
+ failed += 1;
1628
+ continue;
1629
+ }
1630
+ if (commits.stdout.trim() === '') mergeOnlyDeltaRange = { base: classificationBase, head: diffRead.headCommit.toLowerCase() };
1631
+ }
1632
+ } else if (previousRoundCount >= 5 && reason) {
1505
1633
  const claimable = diffRead.source === 'sha-pinned' && diffRead.headCommitState === 'known'
1506
1634
  && diffRead.currentHeadCommitState === 'known' && !diffRead.stale && diffRead.diff.status === 0;
1507
1635
  if (!claimable || !claimCapOverride(pr, diffRead.headCommit, reason, deps.now())) {
@@ -1514,6 +1642,25 @@ async function runSelfReviewCliCommandPinned(
1514
1642
  }
1515
1643
  deps.observeDoctorReview?.('cap-override', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason }, { level: 'warn' });
1516
1644
  }
1645
+ if (mergeOnlyDeltaRange) {
1646
+ const delta = deps.git?.(['diff', '--no-ext-diff', `${mergeOnlyDeltaRange.base}...${mergeOnlyDeltaRange.head}`], 25_000);
1647
+ if (!delta || delta.status !== 0) {
1648
+ const message = `PR ${pr}: merge-only 후속 head의 delta diff를 고정할 수 없습니다.`;
1649
+ deps.error(message);
1650
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1651
+ failed += 1;
1652
+ continue;
1653
+ }
1654
+ diffRead.diff = delta;
1655
+ diffRead.baseCommit = mergeOnlyDeltaRange.base;
1656
+ }
1657
+ if (previousRoundCount >= 5 && authorization && !claimCapOverride(pr, diffRead.headCommit, authorization.reason, deps.now())) {
1658
+ const message = `PR ${pr}: 후속 head 승인 사용 기록을 남기지 못했습니다.`;
1659
+ deps.error(message);
1660
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1661
+ failed += 1;
1662
+ continue;
1663
+ }
1517
1664
  const localHeadComparison = compareLocalHead(pr, { value: diffRead.headCommit, state: diffRead.headCommitState }, deps);
1518
1665
  const { diff } = diffRead;
1519
1666
  const baseReviewerContext = hasProvidedReviewerContext
@@ -1887,10 +2034,15 @@ async function runSelfReviewCliCommandPinned(
1887
2034
  if (review.reviewed === true) failed += 1;
1888
2035
  } else {
1889
2036
  const path = join(effectiveInstanceRoot(), 'review-results', `${opts.save}-${pr}-${diffRead.headCommit.slice(0, 12)}.json`);
1890
- const result = results.at(-1);
2037
+ const rawResult = results.at(-1);
2038
+ const normalized = rawResult && typeof rawResult === 'object'
2039
+ ? normalizeSavedReviewMustFix(rawResult)
2040
+ : { result: rawResult, count: 0 };
2041
+ const result = normalized.result;
1891
2042
  try {
1892
2043
  mkdirSync(dirname(path), { recursive: true });
1893
2044
  writeFileSync(path, selfReviewJsonLine([result]));
2045
+ if (normalized.count > 0) deps.log('mustfix-normalized', { pr, head: diffRead.headCommit, count: normalized.count });
1894
2046
  } catch (error) {
1895
2047
  failed += 1;
1896
2048
  deps.error(`PR ${pr}: --save 실패: ${error instanceof Error ? error.message : String(error)}`);
@@ -28,6 +28,116 @@ import { llmUsageCostFields } from '../budget/llm-cost.js';
28
28
 
29
29
  const execFileAsync = promisify(execFile);
30
30
 
31
+ /** git 서브프로세스 대역 — term grep 동시성 계약을 실제 git 없이 재기 위한 교체점. */
32
+ export type ExecFileLike = (
33
+ file: string,
34
+ args: readonly string[],
35
+ options: { cwd?: string; encoding: 'utf-8'; maxBuffer: number },
36
+ ) => Promise<{ stdout: string; stderr?: string }>;
37
+
38
+ const defaultExecFile: ExecFileLike = execFileAsync as unknown as ExecFileLike;
39
+ let execFileImpl: ExecFileLike = defaultExecFile;
40
+
41
+ /** 테스트 seam — null/미지정이면 실제 git 서브프로세스로 되돌린다. */
42
+ export function setExecFileForTest(fn?: ExecFileLike | null): void {
43
+ execFileImpl = fn ?? defaultExecFile;
44
+ }
45
+
46
+ /** term 별 git grep 동시 실행 상한(기본 3 · OP 06:3x 실측 13개 동시 부하 101 을 막는다). */
47
+ export const TERM_GREP_CONCURRENCY = 3;
48
+ let termGrepConcurrency: number = TERM_GREP_CONCURRENCY;
49
+
50
+ /** 테스트 seam — 상한 없음(Infinity)과 결과 불변을 비교하기 위해 올린다. */
51
+ export function setTermGrepConcurrencyForTest(value?: number | null): void {
52
+ termGrepConcurrency = value ?? TERM_GREP_CONCURRENCY;
53
+ }
54
+
55
+ /** 상한 클램프 — 풀 크기와 관측값이 같은 규칙을 쓰게 한 곳에 둔다. */
56
+ function effectiveConcurrency(concurrency: number, width: number): number {
57
+ const limit = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : width;
58
+ return Math.max(1, Math.min(limit, width));
59
+ }
60
+
61
+ /** 동시 실행 상한 풀 — 결과 순서는 입력 순서 그대로(순위 계산이 순서에 의존하지 않게). */
62
+ async function mapWithConcurrency<T, R>(
63
+ items: readonly T[],
64
+ concurrency: number,
65
+ worker: (item: T) => Promise<R>,
66
+ ): Promise<R[]> {
67
+ const results = new Array<R>(items.length);
68
+ const size = effectiveConcurrency(concurrency, items.length);
69
+ let cursor = 0;
70
+ await Promise.all(
71
+ Array.from({ length: size }, async () => {
72
+ for (let index = cursor++; index < items.length; index = cursor++) {
73
+ results[index] = await worker(items[index]!);
74
+ }
75
+ }),
76
+ );
77
+ return results;
78
+ }
79
+
80
+ /** cwd seam 복원의 **단일 소유** — `process.chdir` 로 되돌리는 곳은 이 묶음(acquire/release) 하나뿐이다.
81
+ *
82
+ * ⛔ 왜 «생산» 이 소유하나: 한 번의 grounding 런은 persistent 코드 채널·skill 도구처럼 **임의 코드**를
83
+ * 지나고(`dispatchTool` → shell·pty), 그 코드가 cwd 를 옮긴 채 끝날 수 있다. 되돌리기를 «각 의존성» 에
84
+ * 맡기면 런이 마감(타임아웃)·예외로 끝나는 순간 그 되돌리기가 통째로 빠지고, 다음 런의 seam
85
+ * (`deps.cwd ?? process.cwd()`)이 **엉뚱한 트리를 저장소 루트로 읽어** 조용히 0건 grounding 을 낸다
86
+ * (#29343 r3 지적: 타임아웃 뒤 cwd seam 오염).
87
+ *
88
+ * ⛔ 소유는 «런마다» 가 아니라 «겹친 런 묶음» 하나다 — cwd 는 프로세스 전역이므로 런별 스냅샷은 겹침에서
89
+ * 깨진다(A 가 임시 트리로 옮긴 사이 B 가 시작하면 B 가 그 임시 트리를 «시작 자리» 로 저장하고, A 가 되돌린
90
+ * 뒤 B 가 다시 임시 트리로 되돌린다). ⇒ 첫 런이 시작 자리를 한 번 스냅샷하고, 겹쳐 들어온 런은 그 값을
91
+ * seam 으로 «물려받으며», 마지막으로 나가는 런만 되돌린다. 마감으로 «버려진» 런도 본문이 끝날 때까지
92
+ * holder 로 남으므로, 마감 뒤에 재개된 본문이 cwd 를 옮겨도 그 뒤의 런은 오염된 자리를 seam 으로 읽지 않고
93
+ * 본문이 끝나는 순간 되돌려진다.
94
+ * ⛔ 복원 보장의 «경계»: 복원은 런의 수명 안에서만 소유한다. 호출자가 마감으로 버렸는데 본문이 «끝나지
95
+ * 않으면» 전역 cwd 는 그 본문이 끝날 때까지 옮겨진 채 남는다 — 이 함수에는 호출자의 마감 신호가 들어오지
96
+ * 않고, 진행 중인 본문 밑의 cwd 를 남이 바꾸면 그 본문을 깨뜨린다. 그 사이 보장되는 것은 «겹쳐 들어온
97
+ * grounding 런의 seam 이 오염된 자리를 읽지 않는다» 이고, 본문이 끝나는 순간 마지막 holder 가 되돌린다
98
+ * (mission-codebase-gate.test.ts «마감 뒤 재개» 시험이 이 경계를 그대로 잰다).
99
+ * ⛔ 되돌리기 실패는 grounding 결과를 바꾸지 않되 «조용히 삼키지» 않는다 — `mission.grounding`
100
+ * `cwd-restore-failed` 로 남긴다(기존 이벤트 형식은 그대로). */
101
+ interface CwdSeamOwner { root: string; holders: number }
102
+ let cwdSeamOwner: CwdSeamOwner | null = null;
103
+
104
+ /** 소유 토큰 — `owned=false` 면 이 런은 묶음에 들지 않았다(시작 자리를 못 읽었다) ⇒ 되돌릴 것도 없다.
105
+ * ⛔ 절대 throw 하지 않는다: 지워진 cwd 에서도 `deps.cwd` 를 받은 호출은 예전처럼 진행해야 한다. */
106
+ interface CwdSeamLease { root: string | null; owned: boolean }
107
+
108
+ function acquireCwdSeam(): CwdSeamLease {
109
+ if (!cwdSeamOwner) {
110
+ let root: string;
111
+ try { root = process.cwd(); } catch { return { root: null, owned: false }; }
112
+ cwdSeamOwner = { root, holders: 0 };
113
+ }
114
+ cwdSeamOwner.holders += 1;
115
+ return { root: cwdSeamOwner.root, owned: true };
116
+ }
117
+
118
+ function releaseCwdSeam(lease: CwdSeamLease): void {
119
+ if (!lease.owned) return;
120
+ const owner = cwdSeamOwner;
121
+ if (!owner) return;
122
+ owner.holders -= 1;
123
+ if (owner.holders > 0) return;
124
+ cwdSeamOwner = null;
125
+ let current: string | null = null;
126
+ try { current = process.cwd(); } catch { /* 지워진 자리 — 아래에서 되돌린다 */ }
127
+ if (current === owner.root) return;
128
+ try {
129
+ process.chdir(owner.root);
130
+ } catch (e) {
131
+ try {
132
+ debug.log('mission.grounding', 'cwd-restore-failed', {
133
+ root: owner.root,
134
+ current,
135
+ error: e instanceof Error ? e.message.slice(0, 200) : String(e).slice(0, 200),
136
+ }, { level: 'warn' });
137
+ } catch { /* 관측 실패가 grounding 을 바꾸지 않는다 */ }
138
+ }
139
+ }
140
+
31
141
  function logLlmUsage(site: 'codebase-gate-injected' | 'codebase-gate-dynamic', model: string, usage: LLMUsage): void {
32
142
  try {
33
143
  debug.log('llm.usage', 'llm-usage', {
@@ -215,28 +325,37 @@ export function commonTermCoverageWeight(matchLines: number): number {
215
325
  }
216
326
 
217
327
  async function searchRepository(terms: string[], limit: number, cwd: string | undefined, paths: string[], commonPaths = paths): Promise<string[]> {
218
- if (!terms.length) return [];
328
+ // 같은 키워드는 한 번만 실행한다 — 실행·랭킹이 같은 목록을 쓰므로 결과는 결정적이다.
329
+ const uniqueTerms = [...new Set(terms)];
330
+ if (!uniqueTerms.length) return [];
219
331
  const fileTerms = new Map<string, Set<string>>(); // file → 매칭된 서로 다른 term
220
332
  const fileLines = new Map<string, number>(); // file → 총 매칭 라인 수
221
333
  const fileTermLines = new Map<string, Map<string, number>>(); // file → term별 매칭 라인 수
222
334
  const tooCommon = new Set<string>(); // 200+ 파일 매칭 = 밀도 감쇠 대상
223
- const trackedPaths = await execFileAsync('git', ['ls-files', '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
335
+ const trackedPaths = await execFileImpl('git', ['ls-files', '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
224
336
  .then(({ stdout }) => stdout.split('\n').filter(Boolean))
225
337
  .catch(() => [] as string[]);
226
- const pathMatches = new Map(terms.map((term) => [term, trackedPaths.filter((file) => file.toLowerCase().includes(term)).length]));
227
- // term별 git grep 을 병렬 실행(순차 spawnSync ~16초 → 병렬 ~2초). git grep=현재 워킹트리
228
- // 파일 검색(history 아님)·gitignore/바이너리 자동 제외. 호출자가 코드와 문서를 분리한다.
229
- const perTerm = await Promise.all(terms.map(async (t) => {
338
+ const pathMatches = new Map(uniqueTerms.map((term) => [term, trackedPaths.filter((file) => file.toLowerCase().includes(term)).length]));
339
+ // term별 git grep 을 동시 실행 상한 풀(기본 3)로 돌린다 — 무제한 병렬은 mbp 1분 부하 101·git grep
340
+ // 13개 동시(OP 06:3x 실측)를 만들었다. git grep=현재 워킹트리 파일 검색(history 아님)·
341
+ // gitignore/바이너리 자동 제외. 호출자가 코드와 문서를 분리한다.
342
+ const termGrepStartedAt = Date.now();
343
+ const perTerm = await mapWithConcurrency(uniqueTerms, termGrepConcurrency, async (t) => {
230
344
  try {
231
345
  // -c: file:count. -i 무시·-I 바이너리제외. term 하나씩(어느 term 이 걸렸는지 추적).
232
- const { stdout } = await execFileAsync('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 });
346
+ const { stdout } = await execFileImpl('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 });
233
347
  const rows = stdout.split('\n').filter(Boolean);
234
- const commonRows = commonPaths === paths ? rows : await execFileAsync('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...commonPaths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
348
+ const commonRows = commonPaths === paths ? rows : await execFileImpl('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...commonPaths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
235
349
  .then(({ stdout }) => stdout.split('\n').filter(Boolean))
236
350
  .catch(() => [] as string[]);
237
351
  return { t, rows, commonCount: commonRows.length };
238
352
  } catch { return { t, rows: [] as string[], commonCount: 0 }; } // git grep no-match = exit 1(throw) → 빈 결과
239
- }));
353
+ });
354
+ debug.log('grounding.search', 'term-grep-batch', {
355
+ terms: uniqueTerms.length,
356
+ concurrency: effectiveConcurrency(termGrepConcurrency, uniqueTerms.length),
357
+ ms: Date.now() - termGrepStartedAt,
358
+ });
240
359
  for (const { t, rows, commonCount } of perTerm) {
241
360
  if (commonCount > 200) {
242
361
  tooCommon.add(t);
@@ -260,7 +379,7 @@ async function searchRepository(terms: string[], limit: number, cwd: string | un
260
379
  const cover = [...ts].reduce((total, term) => total + (tooCommon.has(term)
261
380
  ? commonTermCoverageWeight(termLines?.get(term) ?? 0)
262
381
  : 1), 0);
263
- const nameTerms = terms.filter((t) => f.toLowerCase().includes(t));
382
+ const nameTerms = uniqueTerms.filter((t) => f.toLowerCase().includes(t));
264
383
  const nameWeight = nameTerms.reduce((total, term) => {
265
384
  const matches = pathMatches.get(term) ?? 0;
266
385
  // 경로상 유일한 식별자는 강한 +25를 유지하고, 공유 조각은 매칭 경로 수에 반비례해 감쇠한다.
@@ -531,8 +650,12 @@ export async function groundMissionInCodebase(
531
650
  goal: string, deps: { cwd?: string; seedPaths?: readonly string[]; searchTerms?: SearchTermFn; skillIndex?: SkillIndexFn; pickSkills?: SkillPickFn; recallMemory?: RecallMemoryFn; recallSelf?: RecallSelfFn; refDigest?: RefDigestFn; persistent?: PersistentGroundingDeps | false } & CapsuleGroundingDeps = {},
532
651
  ): Promise<CodebaseGrounding> {
533
652
  // 호출자가 준 root를 모든 저장소 채널과 corpus 관측에 공유한다. 미지정 호출은 기존처럼 프로세스 cwd를 쓴다.
653
+ // ⛔ seam 은 «읽기» 만 하지 않는다 — 시작 자리를 소유자(acquireCwdSeam)에게서 받고 finally 에서 돌려준다.
654
+ // 겹친 런은 첫 런의 스냅샷을 물려받으므로, 다른 런이 옮겨 놓은 cwd 를 시작 자리로 읽지 않는다.
655
+ const cwdLease = acquireCwdSeam();
534
656
  const cwdSource = deps.cwd === undefined ? 'process' : 'caller';
535
- const searchRoot = deps.cwd ?? process.cwd();
657
+ // 시작 자리를 못 읽었으면(지워진 cwd) 소유하지 않는다 — caller root 는 그대로 쓰고, 미지정이면 예전처럼 process.cwd() 가 판정한다.
658
+ const searchRoot = deps.cwd ?? cwdLease.root ?? process.cwd();
536
659
  const startedAt = performance.now();
537
660
  let searchTermsElapsedMs = 0;
538
661
  let persistentElapsedMs = 0;
@@ -695,7 +818,13 @@ export async function groundMissionInCodebase(
695
818
  debug.log('mission.grounding', 'corpus', { grounded: false, reason: 'error', cwd: searchRoot, cwdSource, error: e instanceof Error ? e.message.slice(0, 200) : String(e).slice(0, 200), persistentEvidence: null, persistentStopReason: null, codeChannel: 'failed' }, { level: 'warn' });
696
819
  return { grounded: false, context: '', files: [], persistentEvidence: [], skillFacts: [], codeFacts: [], memoryFacts: [], documentFacts: [], refFacts: [], ptyFacts: [] };
697
820
  } finally {
698
- observeTiming();
821
+ // 정상·예외·타임아웃 어느 경로로 끝났든 소유를 돌려준다 — 마지막 holder 가 시작 자리로 되돌린다.
822
+ // 되돌리기를 관측보다 «먼저» 둔다: 관측이 무엇을 하든 복원이 빠지지 않는다.
823
+ try {
824
+ releaseCwdSeam(cwdLease);
825
+ } finally {
826
+ observeTiming();
827
+ }
699
828
  }
700
829
  }
701
830
 
@@ -533,17 +533,37 @@ function reuseSameCellPr(run: CmdRunner, input: UpsertPrInput, target: NonNullab
533
533
  if (!runKey) return fail(input.runId ? 'new run id invalid for scratch ref' : 'run id required for scratch ref');
534
534
  const scratch = `self-impl/pr-create-r${runKey}-${randomUUID()}`;
535
535
  const scratchRef = `refs/heads/${scratch}`;
536
+ // ⛔ push 보고는 원격의 진실이 아니다 — ref 를 만든 뒤에도 exit≠0 으로 끝날 수 있고, 삭제가
537
+ // 실패로 보고돼도 이미 지워졌을 수 있다. 그래서 새 draft 결과가 확정되는 즉시 **이 시도가
538
+ // 만든 scratch ref 하나만** 상대로 「남았나 보고 → 지운다」. 지우지 못하면 그 이유를 원장에
539
+ // 남긴다(다른 ref·가지·PR 은 건드리지 않는다).
540
+ const reapScratchRef = (outcome: 'branch-created' | 'create-refused' | 'upload-failed'): void => {
541
+ // 업로드가 실패로 보고돼도 원격에 ref 가 남아 있을 수 있다 — 먼저 읽고 건너뛰면 «읽은 뒤
542
+ // 늦게 착지한» ref 가 남는 창이 생긴다. 그래서 결과와 무관하게 늘 삭제를 시도하고,
543
+ // 원격이 «그런 ref 없음» 이라 답하면 이미 없는 것이므로 정리 실패로 세지 않는다.
544
+ let removed = run('git', ['-C', cwd, 'push', 'origin', `:${scratchRef}`]);
545
+ if (!removed.ok && isTransientPushFailure(removed.err || removed.out))
546
+ removed = run('git', ['-C', cwd, 'push', 'origin', `:${scratchRef}`]);
547
+ if (removed.ok) return;
548
+ if (/remote ref does not exist/i.test(`${removed.err ?? ''}\n${removed.out ?? ''}`)) {
549
+ debug.log('autopilot.pr-manager', 'same-cell-scratch-absent', { scratchRef, outcome });
550
+ return;
551
+ }
552
+ debug.log('autopilot.pr-manager', 'same-cell-scratch-cleanup-failed',
553
+ { scratchRef, outcome, detail: removed.err || removed.out,
554
+ stderr: removed.err ?? '', stdout: removed.out, truncated: false }, { level: 'warn' });
555
+ };
536
556
  const uploaded = run('git', ['-C', cwd, 'push', 'origin', `HEAD:${scratchRef}`]);
537
- if (!uploaded.ok) return fail(`new run object upload failed: ${(uploaded.err || uploaded.out).slice(0, 220)}`);
557
+ if (!uploaded.ok) {
558
+ reapScratchRef('upload-failed');
559
+ return fail(`new run object upload failed: ${(uploaded.err || uploaded.out).slice(0, 220)}`);
560
+ }
538
561
  const repository = run('gh', ['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner'], { cwd });
539
562
  const repoName = repository.out.trim();
540
563
  const createdRef = repository.ok && /^[^/\s]+\/[^/\s]+$/.test(repoName)
541
564
  ? run('gh', ['api', '--method', 'POST', `repos/${repoName}/git/refs`, '-f', `ref=${newRef}`, '-f', `sha=${localHead.out.trim()}`], { cwd })
542
565
  : { ok: false, out: '', err: 'repository identity unavailable' };
543
- const removedScratch = run('git', ['-C', cwd, 'push', 'origin', `:${scratchRef}`]);
544
- if (!removedScratch.ok) debug.log('autopilot.pr-manager', 'same-cell-scratch-cleanup-failed',
545
- { scratchRef, detail: removedScratch.err || removedScratch.out,
546
- stderr: removedScratch.err ?? '', stdout: removedScratch.out, truncated: false }, { level: 'warn' });
566
+ reapScratchRef(createdRef.ok ? 'branch-created' : 'create-refused');
547
567
  if (!createdRef.ok) return fail(`new run branch create refused: ${(createdRef.err || createdRef.out).slice(0, 220)}`);
548
568
  const stateLabels = new Set(labelsForAxis('state').map(label => label.name));
549
569
  const labels = [...new Set([...(input.labels ?? []).filter(label => !stateLabels.has(label as typeof PR_LABEL_NAMES.running)),
@@ -286,6 +286,7 @@ export async function dispatchSelfImplement(
286
286
  goalFile = (await authorGoal(goalSourceText, ctx.cwd, {
287
287
  goalTitle: feature,
288
288
  decomposeSteps: createDecomposeSteps(ctx.signal, {
289
+ repositoryRoot: ctx.cwd,
289
290
  ...(adversarialReview !== undefined ? { adversarialReview } : {}),
290
291
  ...(recentStepCounts !== undefined ? { recentStepCounts } : {}),
291
292
  }),