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
@@ -458,6 +458,10 @@ export async function loadFreshCodexAuthState(
458
458
  });
459
459
  return state;
460
460
  }
461
+ if (process.env.ELANOUS_REMOTE_CODEX_ACCESS_ONLY === '1') {
462
+ observeCodexAuth('no-credential', { storeKey: account.storeKey, mirrorPath: mirrorPath ?? null, reason: 'access-only-expiring' });
463
+ return null;
464
+ }
461
465
  observeCodexAuth('refresh-start', {
462
466
  storeKey: account.storeKey, remainingSeconds: remainingSeconds(state),
463
467
  mirrorPath: mirrorPath ?? null, bufferMs: CODEX_REFRESH_BUFFER_MS,
@@ -602,6 +606,9 @@ export async function refreshCodexAccountHome(
602
606
  now?: () => number;
603
607
  } = {},
604
608
  ): Promise<CodexAccountRefreshResult> {
609
+ if (process.env.ELANOUS_REMOTE_CODEX_ACCESS_ONLY === '1') {
610
+ return { ok: false, kind: 'no-tokens', message: '원격 access 미러는 refresh 권한이 없다' };
611
+ }
605
612
  // ⛔ The CEO's default account (~/.codex) is shared with the official CLI — refreshing it here
606
613
  // rotates the refresh token out from under that CLI. Named accounts only.
607
614
  if (name === DEFAULT_CODEX_ACCOUNT) {
@@ -13,7 +13,7 @@ import type { ResourceView } from '../control-plane/ledger.js';
13
13
  import { cardPrNumber, type TaskCard } from '../task-agent/task-hand.js';
14
14
  import { measureLandingThroughput, type LandingThroughput } from '../task-agent/cover.js';
15
15
  import {
16
- okCell, unmeasured, type Cell, type CapacityInfo, type ChecklistCounts, type LaunchableInfo, type LoopRow, type MachineRow,
16
+ okCell, unmeasured, type Cell, type CapacityInfo, type ChecklistCounts, type IoPressure, type LaunchableInfo, type LoopRow, type MachineRow,
17
17
  type OverviewSnapshot, type OwnerTaskRow, type ParentsInfo, type PodMemberRow, type ReleaseRunInfo, type ScheduleInfo,
18
18
  type SchedulerMetrics,
19
19
  } from './overview.js';
@@ -161,6 +161,20 @@ function collectRelease(root: string, version: string | null, schedules: Release
161
161
  return { version: versionCell, run, schedule, checklist };
162
162
  }
163
163
 
164
+ /**
165
+ * 하트비트가 실어 온 I/O 압박(diskIo.io · PSI 10초 평균)을 꺼낸다.
166
+ * 못 잼(맥 · /proc/pressure/io 없음 · 항목 빠짐)은 null — «0%» 로 굳히지 않는다.
167
+ */
168
+ function ioPressureOf(diskIo: unknown): IoPressure | null {
169
+ const cell = (diskIo as { io?: { status?: unknown; value?: { someAvg10?: unknown; fullAvg10?: unknown } } } | null | undefined)?.io;
170
+ if (!cell || cell.status !== 'ok') return null;
171
+ const someAvg10 = cell.value?.someAvg10;
172
+ const fullAvg10 = cell.value?.fullAvg10;
173
+ if (typeof someAvg10 !== 'number' || !Number.isFinite(someAvg10)) return null;
174
+ if (typeof fullAvg10 !== 'number' || !Number.isFinite(fullAvg10)) return null;
175
+ return { someAvg10, fullAvg10 };
176
+ }
177
+
164
178
  function collectMachines(root: string, ledgerRows: ResourceView[] | Error, poolSpec: string | null, psOut: string | Error, now: number): OverviewSnapshot['machines'] {
165
179
  const expected = new Set<string>();
166
180
  const pods: PodMemberRow[] = [];
@@ -181,7 +195,7 @@ function collectMachines(root: string, ledgerRows: ResourceView[] | Error, poolS
181
195
  for (const r of machines) expected.add(r.machine);
182
196
  for (const name of [...expected].sort()) {
183
197
  const row = machines.find((r) => r.machine === name);
184
- const load = (row?.attrs as { load?: { loadAvg?: number[]; cpuCount?: number; freeMem?: number; totalMem?: number; observedAt?: number } } | undefined)?.load;
198
+ const load = (row?.attrs as { load?: { loadAvg?: number[]; cpuCount?: number; freeMem?: number; totalMem?: number; observedAt?: number; diskIo?: unknown } } | undefined)?.load;
185
199
  if (!row || !load || !Array.isArray(load.loadAvg)) { hosts.push({ name, load: unmeasured('control ledger heartbeat', '하트비트 없음') }); continue; }
186
200
  const observed = typeof load.observedAt === 'number' ? load.observedAt : row.observedAt;
187
201
  const [l1, l5, l15] = load.loadAvg;
@@ -192,7 +206,8 @@ function collectMachines(root: string, ledgerRows: ResourceView[] | Error, poolS
192
206
  }
193
207
  const age = Math.max(0, Math.round((now - observed) / 1000));
194
208
  const value = { load1: l1, load5: l5, load15: l15, cpuCount: load.cpuCount,
195
- freeGb: load.freeMem / GB, totalGb: load.totalMem / GB, ageSeconds: age };
209
+ freeGb: load.freeMem / GB, totalGb: load.totalMem / GB, ageSeconds: age,
210
+ ioPressure: ioPressureOf(load.diskIo) };
196
211
  hosts.push({ name, load: age > HEARTBEAT_STALE_S
197
212
  ? unmeasured('control ledger heartbeat', `낡음(${age}초)`, iso(observed))
198
213
  : okCell(value, 'control ledger heartbeat', iso(observed)) });
@@ -51,7 +51,14 @@ export interface LaunchableInfo {
51
51
  interim: true;
52
52
  }
53
53
  export interface CapacityInfo { podUsed: number; podTarget: number; localUsed: number; localMax: number; free: number }
54
- export interface MachineLoad { load1: number; load5: number; load15: number; cpuCount: number; freeGb: number; totalGb: number; ageSeconds: number }
54
+ /** 리눅스 PSI(/proc/pressure/io · 10초 평균) — 적어도 한 작업이 I/O 를 기다린 시간 비율(%). 100 이면 늘 막혀 있었다. */
55
+ export interface IoPressure { someAvg10: number; fullAvg10: number }
56
+
57
+ export interface MachineLoad {
58
+ load1: number; load5: number; load15: number; cpuCount: number; freeGb: number; totalGb: number; ageSeconds: number;
59
+ /** 하트비트가 실어 온 I/O 압박. 못 잼(맥·/proc/pressure/io 없음)은 null — 축에서 빼지 «넉넉»으로 읽지 않는다. */
60
+ ioPressure?: IoPressure | null;
61
+ }
55
62
  export interface MachineRow { name: string; load: Cell<MachineLoad> }
56
63
  export interface PodMemberRow { context: string; capacity: number; occupied: Cell<number> }
57
64
  export interface ParentsInfo { count: number; staleOver6h: number; oldestHours: number | null }
@@ -100,10 +107,10 @@ export interface OverviewSnapshot {
100
107
 
101
108
  export interface VerdictResult { verdict: Verdict; reasons: string[]; nextActions: string[] }
102
109
 
103
- /** 부하/코어가 이 값을 넘으면 «기계 압박»(흐름 저하의 사유). 디스크 I/O 신호는 OVW-MACHINE-HB 전까지 없다. */
110
+ /** 부하/코어가 이 값을 넘으면 «기계 압박»(흐름 저하의 사유). */
104
111
  export const LOAD_PER_CORE_PRESSURE = 3;
105
112
 
106
- /** 자원 지도의 축 어휘(닫힌 집합 · RES-FLOOR-BINDING). I/O·게이트 예약은 이 칸에 원천이 없어 늘 제외다. */
113
+ /** 자원 지도의 축 어휘(닫힌 집합 · RES-FLOOR-BINDING). 게이트 예약은 이 칸에 원천이 없어 늘 제외다. */
107
114
  export type ResourceKind = 'memory' | 'cpu' | 'io' | 'slots' | 'gate';
108
115
 
109
116
  /** 구속 조건 — 남은 비율이 최소인 축. 남은 비율 = 남은 양/전체 양(CPU 는 압박선 LOAD_PER_CORE_PRESSURE×코어를 전체로 본다). */
@@ -111,7 +118,7 @@ export interface ResourceBinding {
111
118
  kind: ResourceKind;
112
119
  label: string;
113
120
  remainingRatio: number;
114
- /** 남은 양/전체 양의 사람 표기 — `5/64GB` · `0/54코어(압박선 3/코어)` · `0/46자리`. */
121
+ /** 남은 양/전체 양의 사람 표기 — `5/64GB` · `0/54코어(압박선 3/코어)` · `4/100(압박 96% · full 61% · 10초 평균)` · `0/46자리`. */
115
122
  remainingText: string;
116
123
  }
117
124
 
@@ -125,8 +132,9 @@ function remainingAmount(n: number): string {
125
132
 
126
133
  /**
127
134
  * 구속 조건 규칙(RES-FLOOR-BINDING) — 메모리·CPU·I/O·슬롯·게이트 예약 중 «남은 비율 최소»인 축이 흐름을 묶는다.
128
- * 못 잰 축(하트비트 없는 호스트 · 용량 못 잼 · 원천 없는 I/O·게이트 예약)은 후보에서 뺀다 — «넉넉»으로도 «바닥»으로도 읽지 않는다.
129
- * 측정 축이 하나도 없으면 null. 동율은 정해진 순서(호스트 순 메모리→CPU, 그 다음 슬롯)의 첫 축이 이긴다.
135
+ * 못 잰 축(하트비트 없는 호스트 · 용량 못 잼 · 하트비트에 PSI 가 없는 I/O · 원천이 없는 게이트 예약)은 후보에서 뺀다
136
+ * — «넉넉»으로도 «바닥»으로도 읽지 않는다.
137
+ * 측정 축이 하나도 없으면 null. 동율은 정해진 순서(호스트 순 메모리→CPU→I/O, 그 다음 슬롯)의 첫 축이 이긴다.
130
138
  */
131
139
  export function bindingResource(s: OverviewSnapshot): ResourceBinding | null {
132
140
  const candidates: ResourceBinding[] = [];
@@ -142,6 +150,11 @@ export function bindingResource(s: OverviewSnapshot): ResourceBinding | null {
142
150
  const remaining = Math.max(0, cpuCap - l.load5);
143
151
  candidates.push({ kind: 'cpu', label: `${host.name} CPU`, remainingRatio: ratio01(remaining / cpuCap), remainingText: `${remainingAmount(remaining)}/${cpuCap.toFixed(0)}코어(압박선 ${LOAD_PER_CORE_PRESSURE}/코어)` });
144
152
  }
153
+ const io = l.ioPressure;
154
+ if (io) {
155
+ const remaining = Math.max(0, 100 - io.someAvg10);
156
+ candidates.push({ kind: 'io', label: `${host.name} I/O`, remainingRatio: ratio01(remaining / 100), remainingText: `${remainingAmount(remaining)}/100(압박 ${remainingAmount(io.someAvg10)}% · full ${remainingAmount(io.fullAvg10)}% · 10초 평균)` });
157
+ }
145
158
  }
146
159
  const capacity = s.tasks.capacity.value;
147
160
  if (capacity && capacity.podTarget + capacity.localMax > 0) {
@@ -280,7 +293,7 @@ export function renderOverview(s: OverviewSnapshot, v: VerdictResult, meta: { el
280
293
  lines.push(`일꾼 ${owners} · 끝 ${show(s.tasks.done, String)}`);
281
294
  lines.push(` 발사 가능 ${show(s.tasks.launchable, (l) => `${l.count}${l.interim ? '(임시 술어)' : ''} · 대상 경로 없음 ${l.skipped.noTargetPath} · 선행 미완 ${l.skipped.predecessorOpen} · 이미 넘김 ${l.skipped.alreadyHanded}`)}`);
282
295
  lines.push(` 빈 자리 ${show(s.tasks.capacity, (c) => `${c.free} (Pod ${c.podUsed}/${c.podTarget} · 로컬 ${c.localUsed}/${c.localMax})`)} [${s.tasks.capacity.source}]`);
283
- const hosts = s.machines.hosts.map((h) => `${h.name} ${show(h.load, (l) => `${l.load1.toFixed(0)}/${l.cpuCount}코어 여유 ${l.freeGb.toFixed(0)}/${l.totalGb.toFixed(0)}GB (${l.ageSeconds}s 전)`)}`);
296
+ const hosts = s.machines.hosts.map((h) => `${h.name} ${show(h.load, (l) => `${l.load1.toFixed(0)}/${l.cpuCount}코어 여유 ${l.freeGb.toFixed(0)}/${l.totalGb.toFixed(0)}GB${l.ioPressure ? ` · I/O 압박 ${l.ioPressure.someAvg10}% · full ${l.ioPressure.fullAvg10}%` : ''} (${l.ageSeconds}s 전)`)}`);
284
297
  lines.push(`기계 ${hosts.join(' · ') || '못 잼(하트비트 원장 비어 있음)'}`);
285
298
  lines.push(` Pod ${s.machines.pods.map((p) => `${p.context} ${show(p.occupied, String)}/${p.capacity}`).join(' · ') || '못 잼(풀 설정 없음)'}`);
286
299
  lines.push(` 하니스 부모(이 기계) ${show(s.machines.parents, (p) => `${p.count} · 6h 넘음 ${p.staleOver6h}${p.oldestHours !== null ? ` · 최고 ${p.oldestHours}h` : ''}`)}`);
@@ -5,9 +5,13 @@ import { join } from 'node:path';
5
5
  import { effectiveInstanceRoot } from '../instance/resolve.js';
6
6
  import { withFileLockSync } from '../storage/file-lock.js';
7
7
  import { resolveHostId } from '../platform/host-id.js';
8
+ import { spawnSync } from 'node:child_process';
8
9
 
9
10
  export interface PrToolCommandResult { ok: boolean; out: string; err?: string }
10
11
  export type PrToolCommand = (command: string, args: readonly string[], opts?: { cwd?: string }) => PrToolCommandResult;
12
+ export interface PrToolCall { command: string; args: readonly string[]; opts?: { cwd?: string } }
13
+ /** PR-CENSUS-PARALLEL: run every call with at most `concurrency` in flight; results stay in input order. */
14
+ export type PrToolParallelCommand = (calls: readonly PrToolCall[], concurrency: number) => PrToolCommandResult[];
11
15
  export type Seat = 'OP' | 'TC' | 'MK' | 'UX';
12
16
  export interface OpenPr {
13
17
  number: number;
@@ -23,6 +27,8 @@ export interface OpenPr {
23
27
  cellId: string | null;
24
28
  cardId?: string | null;
25
29
  cardMarkerPresent?: boolean;
30
+ /** «조각 i/N — 부모 <칸>» 표지가 있으면 그 조각 번호(없으면 null) — sibling-slice 판정용. */
31
+ slice?: { slice: number; total: number } | null;
26
32
  hunks?: readonly DiffHunk[];
27
33
  }
28
34
  export type Inventory = { status: 'checked'; prs: readonly OpenPr[] } | { status: 'unknown'; reason: string };
@@ -35,6 +41,7 @@ export interface GuardReason { code: GuardCode; detail: string; prs?: readonly n
35
41
  /** PR-GUARD-HUNK-WARN (대표 10-17): 줄 겹침은 기본 경고 — 착지 쪽 스마트 머지가 푼다. 'refuse' = 옛 거부 동작. */
36
42
  export type HunkOverlapMode = 'refuse' | 'warn';
37
43
  export interface GuardVerdict { status: 'allow' | 'refuse' | 'unknown'; reasons: readonly GuardReason[]; warnings: readonly GuardReason[];
44
+ sameCellConflicts?: readonly { pr: number; cardId: string | null; slice?: { slice: number; total: number } | null }[];
38
45
  sameCellReuse?: { number: number; branch: string; headSha: string; cellId: string; cardId: string; legacyBound?: true } }
39
46
 
40
47
  const SEATS = ['OP', 'TC', 'MK', 'UX'] as const;
@@ -45,6 +52,126 @@ const MAX_FILES = 3000; // GitHub does not expose more than 3000 PR files.
45
52
  const UNMEASURED_WINDOW_MS = 60 * 60 * 1000;
46
53
  const UNMEASURED_ALLOW_COUNT = 3;
47
54
 
55
+ export const DEFAULT_DIFF_CONCURRENCY = 6;
56
+ const DIFF_CACHE_MAX = 2000;
57
+ const DIFF_CACHE_MAX_BYTES = 64 * 1024 * 1024;
58
+ const DIFF_CACHE_ENTRY_MAX_BYTES = 4 * 1024 * 1024;
59
+ const PARALLEL_CALL_TIMEOUT_MS = 120_000;
60
+ /** Whole pool ceiling, independent of the call count — a stuck pool fails (inventory unknown) instead of hanging the guard. */
61
+ const PARALLEL_POOL_TIMEOUT_MS = 10 * 60 * 1000;
62
+ const PARALLEL_MAX_BUFFER = 256 * 1024 * 1024;
63
+
64
+ /** `gh pr diff` patches keyed by PR number ⊕ head sha. A head sha fixes the diff, so a retry or a second guard
65
+ * call in the same process never refetches it. Bounded by entry count and total bytes (the oldest entry leaves
66
+ * first); a single patch above the per-entry limit is not cached at all. */
67
+ export class CensusDiffCache {
68
+ private readonly entries = new Map<string, { patch: string; bytes: number }>();
69
+ private totalBytes = 0;
70
+ constructor(private readonly max = DIFF_CACHE_MAX, private readonly maxBytes = DIFF_CACHE_MAX_BYTES,
71
+ private readonly entryMaxBytes = DIFF_CACHE_ENTRY_MAX_BYTES) {}
72
+ private key(number: number, headSha: string): string { return `${number}@${headSha}`; }
73
+ private drop(key: string): void {
74
+ const entry = this.entries.get(key);
75
+ if (!entry) return;
76
+ this.totalBytes -= entry.bytes;
77
+ this.entries.delete(key);
78
+ }
79
+ get(number: number, headSha: string): string | undefined { return this.entries.get(this.key(number, headSha))?.patch; }
80
+ set(number: number, headSha: string, patch: string): void {
81
+ const key = this.key(number, headSha);
82
+ this.drop(key);
83
+ const bytes = Buffer.byteLength(patch, 'utf8');
84
+ if (bytes > this.entryMaxBytes || bytes > this.maxBytes) return;
85
+ while (this.entries.size > 0 && (this.entries.size >= this.max || this.totalBytes + bytes > this.maxBytes)) {
86
+ const oldest = this.entries.keys().next().value;
87
+ if (oldest === undefined) break;
88
+ this.drop(oldest);
89
+ }
90
+ this.entries.set(key, { patch, bytes });
91
+ this.totalBytes += bytes;
92
+ }
93
+ get size(): number { return this.entries.size; }
94
+ get bytes(): number { return this.totalBytes; }
95
+ clear(): void { this.entries.clear(); this.totalBytes = 0; }
96
+ }
97
+ /** Process-lifetime cache for production callers (PR creation guard · `pr open-guard`). Tests pass their own. */
98
+ export const sharedCensusDiffCache = new CensusDiffCache();
99
+ export function resetCensusDiffCache(): void { sharedCensusDiffCache.clear(); }
100
+
101
+ // Runs inside a child `bun`/`node` so the synchronous inventory API can still fan out. stdin: { calls, concurrency,
102
+ // timeoutMs } · stdout: one result per call, input order. Each call runs in its own process group (detached) so a
103
+ // per-call timeout, or this pool ending on SIGTERM/SIGINT/SIGHUP from the outer ceiling, kills the whole group —
104
+ // no `gh` (or its children) outlives the pool.
105
+ const PARALLEL_SCRIPT = `
106
+ const { spawn } = require('node:child_process');
107
+ const live = new Set();
108
+ const killGroup = pid => { try { process.kill(-pid, 'SIGKILL'); } catch { try { process.kill(pid, 'SIGKILL'); } catch {} } };
109
+ const killAll = () => { for (const pid of live) killGroup(pid); live.clear(); };
110
+ for (const signal of ['SIGTERM', 'SIGINT', 'SIGHUP']) process.on(signal, () => { killAll(); process.exit(124); });
111
+ process.on('exit', killAll);
112
+ let input = '';
113
+ process.stdin.setEncoding('utf8');
114
+ process.stdin.on('data', chunk => { input += chunk; });
115
+ process.stdin.on('end', () => {
116
+ const { calls, concurrency, timeoutMs } = JSON.parse(input);
117
+ const results = new Array(calls.length);
118
+ let next = 0;
119
+ const one = index => new Promise(resolve => {
120
+ const call = calls[index];
121
+ const out = []; const err = [];
122
+ let settled = false; let timedOut = false; let timer;
123
+ let child;
124
+ const finish = result => {
125
+ if (settled) return; settled = true; clearTimeout(timer);
126
+ if (child && child.pid) { killGroup(child.pid); live.delete(child.pid); }
127
+ results[index] = result; resolve();
128
+ };
129
+ try { child = spawn(call.command, call.args, { cwd: call.cwd || undefined, stdio: ['ignore', 'pipe', 'pipe'], detached: true }); }
130
+ catch (error) { results[index] = { ok: false, out: '', err: String(error && error.message || error) }; resolve(); return; }
131
+ if (child.pid) live.add(child.pid);
132
+ timer = setTimeout(() => { timedOut = true; if (child.pid) killGroup(child.pid); }, timeoutMs);
133
+ child.stdout.on('data', chunk => out.push(chunk));
134
+ child.stderr.on('data', chunk => err.push(chunk));
135
+ child.on('error', error => finish({ ok: false, out: '', err: String(error && error.message || error) }));
136
+ child.on('close', (code, signal) => finish({ ok: code === 0 && !signal && !timedOut, out: Buffer.concat(out).toString('utf8').trim(),
137
+ err: [Buffer.concat(err).toString('utf8').trim(), timedOut ? 'timed out after ' + timeoutMs + 'ms' : signal ? 'terminated by ' + signal : ''].filter(Boolean).join('\\n') }));
138
+ });
139
+ const worker = async () => { while (next < calls.length) { const index = next++; await one(index); } };
140
+ Promise.all(Array.from({ length: Math.max(1, Math.min(concurrency, calls.length)) }, worker))
141
+ .then(() => process.stdout.write(JSON.stringify(results)));
142
+ });
143
+ `;
144
+
145
+ /** Real-spawn {@link PrToolParallelCommand}: one child runtime fans out the calls with a bounded pool. Any failure of
146
+ * the pool itself (including the fixed pool ceiling) returns every call as failed, so the caller's conservative
147
+ * unknown rule applies. `timeoutMs` = per call · `poolTimeoutMs` = whole pool (tests inject short values). */
148
+ export function spawnParallelCommands(calls: readonly PrToolCall[], options: { concurrency?: number; env?: NodeJS.ProcessEnv; timeoutMs?: number; poolTimeoutMs?: number } = {}): PrToolCommandResult[] {
149
+ if (calls.length === 0) return [];
150
+ const concurrency = Math.max(1, Math.floor(options.concurrency ?? DEFAULT_DIFF_CONCURRENCY));
151
+ const timeoutMs = options.timeoutMs ?? PARALLEL_CALL_TIMEOUT_MS;
152
+ const failAll = (err: string) => calls.map(() => ({ ok: false, out: '', err }));
153
+ try {
154
+ const r = spawnSync(process.execPath, ['-e', PARALLEL_SCRIPT], {
155
+ input: JSON.stringify({ calls: calls.map(call => ({ command: call.command, args: [...call.args], cwd: call.opts?.cwd })), concurrency, timeoutMs }),
156
+ encoding: 'utf-8', maxBuffer: PARALLEL_MAX_BUFFER, timeout: options.poolTimeoutMs ?? PARALLEL_POOL_TIMEOUT_MS, killSignal: 'SIGTERM',
157
+ ...(options.env ? { env: options.env } : {}),
158
+ });
159
+ if ((r.error as NodeJS.ErrnoException | undefined)?.code === 'ENOBUFS') return failAll('parallel output exceeded 256MiB (ENOBUFS)');
160
+ if ((r.error as NodeJS.ErrnoException | undefined)?.code === 'ETIMEDOUT' || r.signal) return failAll(`parallel runner timed out or was killed (${r.signal ?? 'ETIMEDOUT'})`);
161
+ if (r.status !== 0) return failAll(`parallel runner rc=${r.status}: ${(r.stderr ?? '').trim().slice(0, 300)}`);
162
+ const parsed: unknown = JSON.parse(r.stdout ?? '');
163
+ if (!Array.isArray(parsed) || parsed.length !== calls.length) return failAll('parallel runner result shape mismatch');
164
+ return parsed.map(row => {
165
+ const value = row as { ok?: unknown; out?: unknown; err?: unknown } | null;
166
+ return value && typeof value.ok === 'boolean' && typeof value.out === 'string'
167
+ ? { ok: value.ok, out: value.out, err: typeof value.err === 'string' ? value.err : '' }
168
+ : { ok: false, out: '', err: 'parallel runner row missing' };
169
+ });
170
+ } catch (error) {
171
+ return failAll(`parallel runner: ${error instanceof Error ? error.message : String(error)}`);
172
+ }
173
+ }
174
+
48
175
  function unknown(reason: string): Inventory { return { status: 'unknown', reason }; }
49
176
  function seatValue(value: unknown): Seat | null { return SEATS.find(seat => seat === value) ?? null; }
50
177
  function seatFromLabels(labels: readonly string[]): Seat | null {
@@ -60,6 +187,15 @@ export function cardIdFromBody(body: string): string | null {
60
187
  export function hasCardMarker(body: string): boolean {
61
188
  return /^\s*(?:[-*]\s*)?카드\s*:/m.test(body);
62
189
  }
190
+ /** 골/PR 본문의 «조각 i/N — 부모 <칸>» 표지 → {slice,total}. 표지 없으면 null, 1≤i≤N 아니면 null. */
191
+ export function sliceMarkerFromBody(body: string): { slice: number; total: number } | null {
192
+ const m = /^\s*(?:[-*]\s*)?(?:«\s*)?조각\s*(\d+)\s*\/\s*(\d+)\s*(?:»)?\s*—\s*부모\s+\S[^\r\n]*$/m.exec(body);
193
+ if (!m) return null;
194
+ const slice = Number(m[1]);
195
+ const total = Number(m[2]);
196
+ return Number.isSafeInteger(slice) && Number.isSafeInteger(total) && slice >= 1 && total >= 1 && slice <= total
197
+ ? { slice, total } : null;
198
+ }
63
199
 
64
200
  export function parseDiffHunks(patch: string): DiffHunk[] {
65
201
  const hunks: DiffHunk[] = [];
@@ -92,8 +228,8 @@ export function parseDiffHunks(patch: string): DiffHunk[] {
92
228
  }
93
229
 
94
230
  /** `gh api --paginate --slurp` must return every REST page, including the last page. */
95
- function pages(run: PrToolCommand, endpoint: string, cwd?: string): readonly unknown[] {
96
- const result = run('gh', ['api', '--paginate', '--slurp', endpoint], cwd ? { cwd } : undefined);
231
+ function pagesArgs(endpoint: string): string[] { return ['api', '--paginate', '--slurp', endpoint]; }
232
+ function parsePages(result: PrToolCommandResult, endpoint: string): readonly unknown[] {
97
233
  if (!result.ok) throw new Error(`gh api ${endpoint}: ${result.err || result.out || '조회 실패'}`);
98
234
  let parsed: unknown;
99
235
  try { parsed = JSON.parse(result.out); } catch { throw new Error(`gh api ${endpoint}: JSON 오류`); }
@@ -102,6 +238,9 @@ function pages(run: PrToolCommand, endpoint: string, cwd?: string): readonly unk
102
238
  }
103
239
  return parsed.flat();
104
240
  }
241
+ function pages(run: PrToolCommand, endpoint: string, cwd?: string): readonly unknown[] {
242
+ return parsePages(run('gh', pagesArgs(endpoint), cwd ? { cwd } : undefined), endpoint);
243
+ }
105
244
 
106
245
  function object(value: unknown): Record<string, unknown> {
107
246
  if (value === null || typeof value !== 'object' || Array.isArray(value)) throw new Error('PR 응답 행 형식 오류');
@@ -116,29 +255,59 @@ function date(value: unknown, name: string): string {
116
255
  if (!Number.isFinite(Date.parse(raw))) throw new Error(`${name} 날짜 오류`);
117
256
  return raw;
118
257
  }
119
- function pathsForPr(run: PrToolCommand, number: number, cwd?: string): string[] {
120
- const rows = pages(run, `repos/{owner}/{repo}/pulls/${number}/files?per_page=100`, cwd);
258
+ function filesEndpoint(number: number): string { return `repos/{owner}/{repo}/pulls/${number}/files?per_page=100`; }
259
+ function pathsFromFilesResult(result: PrToolCommandResult, number: number): string[] {
260
+ const rows = parsePages(result, filesEndpoint(number));
121
261
  if (rows.length >= MAX_FILES) throw new Error(`PR #${number}: 파일 ${MAX_FILES}개 GitHub 상한에 닿음`);
122
262
  return rows.map(row => text(object(row).filename, `PR #${number} 파일명`));
123
263
  }
124
264
 
125
- /** Fast file projection; the REST page census below remains the authority for which PRs exist. */
126
- function projectedFiles(run: PrToolCommand, count: number, cwd?: string): Map<number, string[]> {
265
+ interface FileProjection {
266
+ files: Map<number, string[]>;
267
+ /** Set when the one-shot list produced nothing usable — every PR then takes the REST file fallback. */
268
+ failure?: string;
269
+ /** Rows the projection could not vouch for (malformed · file list shorter than changedFiles, e.g. >100 files). */
270
+ skipped: number;
271
+ }
272
+
273
+ /** Fast file projection; the REST page census below remains the authority for which PRs exist. A failed or partial
274
+ * projection is never silent: the reason and skipped row count go to the `diff-scan` observation. */
275
+ function projectedFiles(run: PrToolCommand, count: number, cwd?: string): FileProjection {
127
276
  const result = run('gh', ['pr', 'list', '--state', 'open', '--limit', String(Math.max(count, 1)), '--json', 'number,changedFiles,files'], cwd ? { cwd } : undefined);
128
- if (!result.ok) return new Map();
277
+ if (!result.ok) return { files: new Map(), skipped: 0, failure: `gh pr list 실패: ${(result.err || result.out || 'rc≠0').trim().slice(0, 200)}` };
129
278
  let rows: unknown;
130
- try { rows = JSON.parse(result.out); } catch { return new Map(); }
131
- if (!Array.isArray(rows)) return new Map();
279
+ try { rows = JSON.parse(result.out); } catch { return { files: new Map(), skipped: 0, failure: `gh pr list JSON 오류 (${result.out.length}자)` }; }
280
+ if (!Array.isArray(rows)) return { files: new Map(), skipped: 0, failure: 'gh pr list 응답이 배열 아님' };
132
281
  const projection = new Map<number, string[]>();
282
+ let skipped = 0;
133
283
  for (const value of rows) {
134
284
  try {
135
285
  const row = object(value);
136
- if (!Number.isSafeInteger(row.number) || (row.number as number) <= 0 || !Number.isSafeInteger(row.changedFiles) || (row.changedFiles as number) < 0 || !Array.isArray(row.files)) continue;
286
+ if (!Number.isSafeInteger(row.number) || (row.number as number) <= 0 || !Number.isSafeInteger(row.changedFiles) || (row.changedFiles as number) < 0 || !Array.isArray(row.files)) { skipped += 1; continue; }
137
287
  const paths = row.files.map(file => text(object(file).path, 'PR 파일명'));
138
288
  if (paths.length === row.changedFiles && paths.length < MAX_FILES && !projection.has(row.number as number)) projection.set(row.number as number, paths);
139
- } catch { /* malformed projection: REST file endpoint below decides this PR */ }
289
+ else skipped += 1;
290
+ } catch { skipped += 1; /* malformed projection: REST file endpoint below decides this PR */ }
140
291
  }
141
- return projection;
292
+ if (rows.length > 0 && projection.size === 0) return { files: projection, skipped, failure: `gh pr list ${rows.length}행 모두 사용 불가` };
293
+ return { files: projection, skipped };
294
+ }
295
+
296
+ /** Run `calls` through the bounded pool when given, else one by one with the injected runner, stopping at the first
297
+ * failure (the historical order and call count). The result may be shorter than `calls` only in that sequential case. */
298
+ function runCalls(run: PrToolCommand, calls: readonly PrToolCall[], runParallel: PrToolParallelCommand | undefined, concurrency: number, what: string): PrToolCommandResult[] {
299
+ if (runParallel) {
300
+ const results = runParallel(calls, concurrency);
301
+ if (results.length !== calls.length) throw new Error(`${what} 결과 ${results.length}/${calls.length}건 · 판정 불가`);
302
+ return results;
303
+ }
304
+ const results: PrToolCommandResult[] = [];
305
+ for (const call of calls) {
306
+ const result = run(call.command, call.args, call.opts);
307
+ results.push(result);
308
+ if (!result.ok) break;
309
+ }
310
+ return results;
142
311
  }
143
312
 
144
313
  export function readOpenPrs(run: PrToolCommand, options: {
@@ -146,10 +315,28 @@ export function readOpenPrs(run: PrToolCommand, options: {
146
315
  seatOfPr?: (pr: { number: number; headRefName: string; body: string; labels: readonly string[] }) => Seat | null;
147
316
  includeDraftCommitDates?: boolean;
148
317
  candidateFiles?: readonly string[];
318
+ /** Bounded parallel REST-file fallback and diff fetch. Absent ⇒ the injected `run`, one by one (historical order and call count). */
319
+ runParallel?: PrToolParallelCommand;
320
+ /** Operations default {@link DEFAULT_DIFF_CONCURRENCY} (6) — production callers do not pass it; for test injection. */
321
+ diffConcurrency?: number;
322
+ /** Absent ⇒ no cache. Production callers pass {@link sharedCensusDiffCache}. */
323
+ diffCache?: CensusDiffCache;
149
324
  } = {}): Inventory {
325
+ const started = Date.now();
326
+ const callOpts = options.cwd ? { opts: { cwd: options.cwd } } : {};
327
+ const concurrency = options.runParallel ? Math.max(1, Math.floor(options.diffConcurrency ?? DEFAULT_DIFF_CONCURRENCY)) : 1;
328
+ const scan = { openPrs: 0, projected: 0, restFallback: 0, projectionFailed: false, projectionReason: undefined as string | undefined,
329
+ projectionSkipped: 0, fileOverlap: 0, patchFetched: 0, cacheHits: 0 };
330
+ let status: 'checked' | 'inventory-unknown' | 'files-failed' | 'diff-failed' | 'commit-date-failed' = 'inventory-unknown';
331
+ const logDiffScan = () => {
332
+ debug.log('pr-tool.census', 'diff-scan', { ...scan, concurrency, elapsedMs: Date.now() - started, status });
333
+ };
150
334
  try {
151
335
  const rows = pages(run, 'repos/{owner}/{repo}/pulls?state=open&per_page=100', options.cwd);
152
- const projected = projectedFiles(run, rows.length, options.cwd);
336
+ const projection = projectedFiles(run, rows.length, options.cwd);
337
+ scan.projectionFailed = projection.failure !== undefined;
338
+ scan.projectionReason = projection.failure;
339
+ scan.projectionSkipped = projection.skipped;
153
340
  const prs: OpenPr[] = [];
154
341
  const seen = new Set<number>();
155
342
  for (const value of rows) {
@@ -166,26 +353,69 @@ export function readOpenPrs(run: PrToolCommand, options: {
166
353
  const headSha = text(head.sha, `PR #${number} head sha`);
167
354
  const body = typeof row.body === 'string' ? row.body : '';
168
355
  const seat = seatValue(options.seatOfPr?.({ number: number as number, headRefName, body, labels: labelNames })) ?? seatFromLabels(labelNames);
169
- const pr: OpenPr = {
356
+ prs.push({
170
357
  number: number as number, headRefName, title: text(row.title, `PR #${number} title`), draft: row.draft,
171
358
  updatedAt: date(row.updated_at, `PR #${number} updated_at`), headSha, labels: labelNames,
172
- files: projected.get(number as number) ?? pathsForPr(run, number as number, options.cwd), seat,
359
+ files: projection.files.get(number as number) ?? [], seat,
173
360
  cellId: cellIdFromBody(body), cardId: cardIdFromBody(body), cardMarkerPresent: hasCardMarker(body),
174
- };
175
- if (options.candidateFiles?.some(file => pr.files.includes(file))) {
176
- const patch = run('gh', ['pr', 'diff', String(number), '--patch'], options.cwd ? { cwd: options.cwd } : undefined);
177
- if (!patch.ok) throw new Error(`PR #${number}: 수정 줄 조회 실패: ${patch.err || patch.out}`);
361
+ slice: sliceMarkerFromBody(body),
362
+ });
363
+ }
364
+ scan.openPrs = prs.length;
365
+ // Files: PRs the one-shot projection did not cover take the REST file endpoint — in the pool when given.
366
+ const restPrs = prs.filter(pr => !projection.files.has(pr.number));
367
+ scan.projected = prs.length - restPrs.length;
368
+ scan.restFallback = restPrs.length;
369
+ if (restPrs.length) {
370
+ status = 'files-failed';
371
+ const results = runCalls(run, restPrs.map(pr => ({ command: 'gh', args: pagesArgs(filesEndpoint(pr.number)), ...callOpts })), options.runParallel, concurrency, 'PR 파일 조회');
372
+ // The first failure in input order decides the reason; one failure keeps the whole inventory unknown.
373
+ // Invariant: a result is missing only after an earlier failure (sequential stop), which throws first. Still,
374
+ // a missing result is a failure (unknown), never an empty file list.
375
+ restPrs.forEach((pr, index) => {
376
+ const result = results[index];
377
+ if (!result) throw new Error(`PR #${pr.number}: 파일 조회 결과 없음 · 판정 불가`);
378
+ pr.files = pathsFromFilesResult(result, pr.number);
379
+ });
380
+ }
381
+ // Diffs: only PRs sharing a candidate file; a cached (number, headSha) patch is not refetched.
382
+ const pendingDiffs: OpenPr[] = [];
383
+ for (const pr of prs) {
384
+ if (!options.candidateFiles?.some(file => pr.files.includes(file))) continue;
385
+ scan.fileOverlap += 1;
386
+ const cached = options.diffCache?.get(pr.number, pr.headSha);
387
+ if (cached !== undefined) { pr.hunks = parseDiffHunks(cached); scan.cacheHits += 1; }
388
+ else pendingDiffs.push(pr);
389
+ }
390
+ if (pendingDiffs.length) {
391
+ status = 'diff-failed';
392
+ const results = runCalls(run, pendingDiffs.map(pr => ({ command: 'gh', args: ['pr', 'diff', String(pr.number), '--patch'], ...callOpts })), options.runParallel, concurrency, '수정 줄 조회');
393
+ scan.patchFetched = results.length;
394
+ pendingDiffs.forEach((pr, index) => {
395
+ const patch = results[index];
396
+ if (!patch) throw new Error(`PR #${pr.number}: 수정 줄 조회 결과 없음 · 판정 불가`);
397
+ if (!patch.ok) throw new Error(`PR #${pr.number}: 수정 줄 조회 실패: ${patch.err || patch.out}`);
398
+ });
399
+ pendingDiffs.forEach((pr, index) => {
400
+ const patch = results[index]!;
178
401
  pr.hunks = parseDiffHunks(patch.out);
402
+ options.diffCache?.set(pr.number, pr.headSha, patch.out);
403
+ });
404
+ }
405
+ if (options.includeDraftCommitDates) {
406
+ status = 'commit-date-failed';
407
+ for (const pr of prs) {
408
+ if (!pr.draft) continue;
409
+ const commit = run('gh', ['api', `repos/{owner}/{repo}/commits/${pr.headSha}`, '--jq', '.commit.committer.date'], options.cwd ? { cwd: options.cwd } : undefined);
410
+ if (!commit.ok) throw new Error(`PR #${pr.number}: 마지막 커밋 날짜 조회 실패: ${commit.err || commit.out}`);
411
+ pr.lastCommitAt = date(commit.out.trim(), `PR #${pr.number} 마지막 커밋`);
179
412
  }
180
- if (pr.draft && options.includeDraftCommitDates) {
181
- const commit = run('gh', ['api', `repos/{owner}/{repo}/commits/${headSha}`, '--jq', '.commit.committer.date'], options.cwd ? { cwd: options.cwd } : undefined);
182
- if (!commit.ok) throw new Error(`PR #${number}: 마지막 커밋 날짜 조회 실패: ${commit.err || commit.out}`);
183
- pr.lastCommitAt = date(commit.out.trim(), `PR #${number} 마지막 커밋`);
184
- }
185
- prs.push(pr);
186
413
  }
414
+ status = 'checked';
415
+ logDiffScan();
187
416
  return { status: 'checked', prs };
188
417
  } catch (error) {
418
+ logDiffScan();
189
419
  return unknown(error instanceof Error ? error.message : String(error));
190
420
  }
191
421
  }
@@ -222,7 +452,7 @@ export function censusOpenPrs(inventory: Inventory, now = Date.now()): Census {
222
452
  return result;
223
453
  }
224
454
 
225
- export function guardNewPr(input: { files: readonly string[] | null; seat?: Seat | null; seatCap?: number; cellId?: string | null; cardId?: string | null; boundPrNumber?: number; hunks?: readonly DiffHunk[]; hunkOverlap?: HunkOverlapMode }, inventory: Inventory): GuardVerdict {
455
+ export function guardNewPr(input: { files: readonly string[] | null; seat?: Seat | null; seatCap?: number; cellId?: string | null; cardId?: string | null; slice?: { slice: number; total: number } | null; boundPrNumber?: number; hunks?: readonly DiffHunk[]; hunkOverlap?: HunkOverlapMode }, inventory: Inventory): GuardVerdict {
226
456
  if (!input.files || input.files.length === 0 || input.files.some(file => !file || file.startsWith('/') || file.includes('..'))) {
227
457
  const reasons: GuardReason[] = [{ code: 'candidate-unknown', detail: '새 PR 변경 파일을 확인할 수 없음' }];
228
458
  debug.log('pr.tool', 'guard-refuse', { status: 'unknown', reasons });
@@ -275,10 +505,14 @@ export function guardNewPr(input: { files: readonly string[] | null; seat?: Seat
275
505
  && input.boundPrNumber === sameCell[0].number;
276
506
  const reusable = status === 'refuse' && reasons.length === 1 && reasons[0]?.code === 'same-cell'
277
507
  && input.cardId && sameCell.length === 1 && (sameCell[0]?.cardId === input.cardId || legacyBound)
508
+ && (input.slice?.slice ?? null) === (sameCell[0]?.slice?.slice ?? null)
509
+ && (input.slice?.total ?? null) === (sameCell[0]?.slice?.total ?? null)
278
510
  && sameCell[0].headRefName && /^[0-9a-f]{40}$/i.test(sameCell[0].headSha)
279
511
  ? { number: sameCell[0].number, branch: sameCell[0].headRefName, headSha: sameCell[0].headSha,
280
512
  cellId: input.cellId!, cardId: input.cardId, ...(legacyBound ? { legacyBound: true as const } : {}) } : undefined;
281
- return { status, reasons, warnings, ...(reusable ? { sameCellReuse: reusable } : {}) };
513
+ return { status, reasons, warnings,
514
+ ...(sameCell.length ? { sameCellConflicts: sameCell.map(pr => ({ pr: pr.number, cardId: pr.cardId ?? null, slice: pr.slice ?? null })) } : {}),
515
+ ...(reusable ? { sameCellReuse: reusable } : {}) };
282
516
  }
283
517
 
284
518
  /** Persist the unknown-read budget across harness processes sharing one instance state root. */
@@ -251,6 +251,13 @@ function recordPtyLifecycle(event: PtyLifecycleEvent, row: PtyManifestRow, now:
251
251
  exitCode: row.exitCode,
252
252
  startedAt: row.startedAt,
253
253
  closedAt: row.closedAt,
254
+ // 시작·종료·오류·산출을 같은 seatId 한 흐름으로 대조할 수 있게
255
+ // 매니페스트 행의 자리 정체성과 산출 총량을 원장 이벤트에도 싣는다.
256
+ ...(row.seat ? { seat: row.seat } : {}),
257
+ ...(row.purpose ? { purpose: row.purpose } : {}),
258
+ outputBytesTotal: row.outputBytesTotal,
259
+ ...(row.lastControlAt === undefined ? {} : { lastControlAt: row.lastControlAt }),
260
+ ...(row.turnState ? { turnState: row.turnState, turnAt: row.turnAt } : {}),
254
261
  },
255
262
  });
256
263
  if (seq === 0) debug.log('pty.manifest', 'ledger-write-failed', { ptyId: row.id, event });
@@ -132,6 +132,28 @@ function mentionedPaths(text: string): string[] {
132
132
  return [...text.matchAll(PATH_TOKEN)].map((match) => match[1]!).filter((path) => !path.split('/').includes('..'));
133
133
  }
134
134
 
135
+ /** `docs/goal-context/03-verification-menu.md` §선택 원칙: merge SHA·타입검사는 수용선이 아니다. */
136
+ export const MERGE_OR_TYPECHECK_ONLY_REAL_WARNING = '- 완료 경계 실물: merge sha·타입검사만으로는 실물이 아니다 — docs/goal-context/03-verification-menu.md 에서 동작을 재는 방법을 고른다';
137
+ /** 통합 이력·정적 타입 상태만 말하는 낱말(조사 뗀 꼴). 이 밖의 낱말이 하나라도 있으면 실물 주장으로 본다. */
138
+ const MERGE_OR_TYPECHECK_WORD = /^(?:pr|merge|merged|머지|병합|착지|landed|land|sha|merge-sha|commit|커밋|origin|main|tsc|typecheck|type-check|typecheck-changed|타입검사|타입|검사|type|check|changed|통과|pass|passed|green|clean|errors?|error|오류|에러|없음|후|뒤|완료|확인|and|및|만|됨|된다)$/i;
139
+ const MERGE_OR_TYPECHECK_SIGNAL = /^(?:merge|merged|머지|병합|착지|landed|land|sha|merge-sha|tsc|typecheck|type-check|타입검사)$/i;
140
+ const KOREAN_PARTICLE_TAIL = /(?:했다|했음|하였다|했고|함|으로|로|이|가|은|는|을|를|와|과|에|의|만|됨|된|된다)$/u;
141
+
142
+ /** 「완료 경계 실물」 값이 merge sha·PR 착지·타입검사 낱말로만 이뤄졌나(동작 관측이 하나도 없나). */
143
+ export function isMergeOrTypecheckOnlyEvidence(value: string): boolean {
144
+ const words = value.split(/[\s.!?。…~`'"·,⊕+()[\]:;/=|→-]+/u).map((word) => word.replace(/^#/, '')).filter(Boolean);
145
+ if (!words.length) return false;
146
+ let signal = false;
147
+ for (const raw of words) {
148
+ if (/^\d+$/.test(raw) || /^[0-9a-f]{7,40}$/i.test(raw)) continue;
149
+ let word = raw;
150
+ for (let strip = 0; strip < 3 && !MERGE_OR_TYPECHECK_WORD.test(word); strip++) word = word.replace(KOREAN_PARTICLE_TAIL, '');
151
+ if (!MERGE_OR_TYPECHECK_WORD.test(word)) return false;
152
+ if (MERGE_OR_TYPECHECK_SIGNAL.test(word)) signal = true;
153
+ }
154
+ return signal;
155
+ }
156
+
135
157
  /** Shadow check at checklist authorship. Callers supply the origin/main file probe and merged-PR file reader. */
136
158
  export function inspectChecklistTargetPaths(input: {
137
159
  title: string; evidence?: string; refs?: readonly string[]; dispatchKind?: ChecklistDispatchKind;
@@ -179,6 +201,8 @@ export function inspectChecklistTargetPaths(input: {
179
201
  if (!lines.some((line) => line.startsWith(`- 완료 경계 ${label}:`) && line.slice(`- 완료 경계 ${label}:`.length).trim()))
180
202
  warnings.push(`- 완료 경계 ${label}: 줄이 없다`);
181
203
  }
204
+ const real = lines.find((line) => line.startsWith('- 완료 경계 실물:'))?.slice('- 완료 경계 실물:'.length).trim();
205
+ if (real && isMergeOrTypecheckOnlyEvidence(real)) warnings.push(MERGE_OR_TYPECHECK_ONLY_REAL_WARNING);
182
206
  }
183
207
  if (!warnings.length) return { targets, warnings, candidates: [] };
184
208
  const sources = [input.title, input.evidence ?? '', ...(input.refs ?? [])].join('\n');