elanous 0.2.19 → 0.2.21

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 (509) 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/MObU8ujkMciAKr6ljAV05/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/088d8e8a.8069543d082bec12.js +160 -0
  5. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +148 -0
  6. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/119fc678.6f591cdb84ca5791.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +309 -0
  9. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 1268.0840ff91e083fcbd.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1307-c97eba9fb72a9a5e.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +122 -0
  12. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +149 -0
  13. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +79 -0
  14. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +24 -0
  16. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +27 -0
  21. package/apps/pwa/out/_next/static/chunks/1948.5f35b39eef222a94.js +5 -0
  22. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{2977-e38442e86289f1d3.js → 211-9c9090c59e2c5907.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +36 -0
  31. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +286 -0
  32. package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +94 -0
  45. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/3522-1de1319d028ac89c.js +25 -0
  49. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +74 -0
  54. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +34 -0
  59. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +115 -0
  61. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/4588.ad3364cb7fb97ada.js +86 -0
  63. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +77 -0
  66. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +90 -0
  70. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5977-59fedea50d13c762.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +8 -0
  75. package/apps/pwa/out/_next/static/chunks/{4847.56f5bc454fbcc827.js → 6110.1297d4093fdfbb0d.js} +2 -2
  76. package/apps/pwa/out/_next/static/chunks/6158.566c890adc06a459.js +2 -0
  77. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +64 -0
  78. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +287 -0
  80. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +226 -0
  81. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6767.8e6c5f6e744fcd9f.js +38 -0
  83. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7175-350f4ce2873bc038.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +41 -0
  91. package/apps/pwa/out/_next/static/chunks/{1470.98a6ab61ccb4131c.js → 726.83532d69452ee24b.js} +1 -1
  92. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 7327-2d69fb321ba73389.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +24 -0
  95. package/apps/pwa/out/_next/static/chunks/7630.2b9a68659053ff4e.js +193 -0
  96. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/7899.597af4a9996c907f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/79b78388.663188133449d707.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8194.484f51e273d9abd2.js +217 -0
  105. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +104 -0
  109. package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/88729267.9c6c000157c83f2f.js +62 -0
  111. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +93 -0
  113. package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{7647.2fcd30d894d5ee30.js → 935.4ddaa99fc1d1126c.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +23 -0
  118. package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +62 -0
  120. package/apps/pwa/out/_next/static/chunks/9832.2ab2e818013574c7.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/a9f2b54d-40c16bd0efdb04b8.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-111cabe4d1fd69ae.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/{page-b70cd005d9169e25.js → page-be8b4615c919e36c.js} +1 -1
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-f23484de467c9ea3.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/d70879db.c66c56a95a91efc6.js +66 -0
  174. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → f6231284-45726550aba08fca.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/{2ea96958.e8c7e112de50b067.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/f8626309.a4e5d362b1d55e59.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +1 -0
  183. package/apps/pwa/out/_next/static/css/{d3427996da11e480.css → b9d8151e48998417.css} +1 -1
  184. package/apps/pwa/out/_next/static/css/e81df11490b4413b.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +24 -24
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +23 -23
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -0
  223. package/apps/pwa/out/live-run/index.txt +35 -0
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/graphs/demo/editor-recipes.yaml +22 -0
  279. package/graphs/drafts/recipes.yaml +4 -4
  280. package/graphs/implement-loop.yaml +277 -5
  281. package/graphs/retro/daily.yaml +25 -0
  282. package/graphs/retro/recipes.yaml +24 -0
  283. package/package.json +1 -1
  284. package/scripts/ask-marker-check.ts +3 -1
  285. package/scripts/coord-channel-watch.sh +31 -4
  286. package/scripts/docs-lint.ts +4 -1
  287. package/scripts/land-global-checks.ts +89 -0
  288. package/scripts/lib/pch-regress-map.ts +2 -1
  289. package/scripts/marketing/generate-ax-brief.ts +18 -1
  290. package/scripts/measure-nl-routing-corpus.ts +11 -3
  291. package/scripts/release-loop/gate-node.ts +296 -25
  292. package/scripts/release-loop/gate-timing.ts +116 -7
  293. package/scripts/release-loop/preflight.ts +6 -4
  294. package/scripts/release-loop/publish-window.ts +141 -0
  295. package/scripts/release-loop/release-docs.ts +1 -4
  296. package/scripts/release-loop/release-universe.ts +38 -0
  297. package/scripts/release-loop/resume-release.ts +4 -1
  298. package/scripts/release-loop/shard-plan.ts +50 -5
  299. package/scripts/release-loop/unattended-release.ts +10 -2
  300. package/scripts/release-story/draft.ts +5 -1
  301. package/scripts/retro/shadow-compare.ts +71 -0
  302. package/scripts/rhythm/daily.ts +8 -2
  303. package/src/agent-mission/driver.ts +34 -6
  304. package/src/autopilot/build/llm-conflict-merge.ts +132 -7
  305. package/src/autopilot/build/merge-intent.ts +135 -7
  306. package/src/away/release-watch.ts +20 -3
  307. package/src/browser-cdp/client.ts +10 -5
  308. package/src/cli/config-drift.ts +513 -0
  309. package/src/cli/log-event-names.ts +4 -0
  310. package/src/cli/ops-cli.ts +11 -0
  311. package/src/cli/ops-overview-cli.ts +50 -0
  312. package/src/cli/pod-cli.ts +1 -0
  313. package/src/cli/pr-cli.ts +20 -0
  314. package/src/cli/release-cli.ts +20 -5
  315. package/src/cli/retro-cli.ts +78 -0
  316. package/src/cli/tasks-cli.ts +200 -8
  317. package/src/dashboard/index.ts +40 -4
  318. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -4
  319. package/src/dashboard/slash-runtime/help-from-registry.ts +57 -31
  320. package/src/domains/outbound-log-probe.ts +6 -1
  321. package/src/esc-abort-gate.ts +3 -1
  322. package/src/graph-runner/graph-cli.ts +57 -0
  323. package/src/graph-runner/graph-run-api.ts +218 -0
  324. package/src/graph-runner/runner.ts +11 -1
  325. package/src/graph-wizard/archetypes.ts +88 -0
  326. package/src/graph-wizard/generate.ts +545 -0
  327. package/src/graph-wizard/saved-steps.ts +120 -0
  328. package/src/graph-wizard/steps.ts +193 -0
  329. package/src/harness/harness-cli-command.ts +482 -59
  330. package/src/harness/harness-queue.ts +315 -25
  331. package/src/harness/harness-salvage-cli.ts +62 -0
  332. package/src/hq/fence-outcomes.ts +63 -0
  333. package/src/hq/fence-wrapper.ts +33 -0
  334. package/src/hq/hq.ts +11 -1
  335. package/src/index.ts +76 -10
  336. package/src/intake-plane/digest.ts +18 -11
  337. package/src/maturity/feature-maturity.ts +4 -3
  338. package/src/nexus/api/draft-metrics.ts +114 -0
  339. package/src/nexus/api/graph-kinds.ts +10 -4
  340. package/src/nexus/api/graph-wizard-api.ts +53 -0
  341. package/src/nexus/api/graphs-api.ts +220 -10
  342. package/src/nexus/api/harness-traversal.ts +205 -0
  343. package/src/nexus/api/http-server.ts +69 -3
  344. package/src/nexus/api/loop-edges.ts +4 -2
  345. package/src/nexus/api/ops-api.ts +22 -7
  346. package/src/nexus/api/ops-board-route.ts +48 -0
  347. package/src/nexus/outbound/router.ts +28 -8
  348. package/src/onboarding/entry-hints.ts +5 -0
  349. package/src/onboarding/first-run.ts +3 -0
  350. package/src/onboarding.ts +24 -6
  351. package/src/ops/overview-collect.ts +345 -0
  352. package/src/ops/overview-seat-era.ts +90 -0
  353. package/src/ops/overview.ts +223 -0
  354. package/src/release-loop/feature-store.ts +14 -11
  355. package/src/release-loop/gate-shards.ts +163 -0
  356. package/src/release-loop/release-schedule.ts +6 -2
  357. package/src/retro/daily.ts +372 -0
  358. package/src/seat-loop/op-decide.ts +173 -0
  359. package/src/seat-loop/seat-loop.ts +60 -3
  360. package/src/seat-loop/seat-report.ts +58 -3
  361. package/src/self-dev/ask-launch-flow.ts +9 -6
  362. package/src/self-dev/ask-launch-io.ts +52 -2
  363. package/src/self-dev/ask-path-candidates.ts +40 -2
  364. package/src/self-dev/draft-sweep.ts +371 -16
  365. package/src/self-dev/draft-triage-rules.ts +19 -4
  366. package/src/self-dev/graph-journey-nodes.ts +157 -0
  367. package/src/self-dev/graph-journey-route.ts +105 -0
  368. package/src/self-dev/launch-preflight.ts +43 -3
  369. package/src/self-dev/pr-preview.ts +84 -16
  370. package/src/self-dev/release-path-guard.ts +7 -4
  371. package/src/self-implement/blocked-draft-policy.ts +101 -0
  372. package/src/self-implement/execution-clarification.ts +11 -0
  373. package/src/self-implement/frozen-merges.ts +23 -0
  374. package/src/self-implement/gate-env-retry.ts +83 -0
  375. package/src/self-implement/goal-author.ts +14 -0
  376. package/src/self-implement/heal-intake.ts +3 -0
  377. package/src/self-implement/orchestrator.ts +234 -6
  378. package/src/self-implement/run-stop.ts +123 -0
  379. package/src/self-implement/run-ttl.ts +258 -0
  380. package/src/self-implement/salvage-retention.ts +123 -0
  381. package/src/self-implement/seams.ts +7 -0
  382. package/src/self-implement/self-implement-cli.ts +2 -0
  383. package/src/self-implement/self-implement-runtime.ts +12 -0
  384. package/src/self-implement/sibling-resync.ts +223 -0
  385. package/src/self-implement/stop-autoheal.ts +204 -0
  386. package/src/session-runtime/index.ts +5 -3
  387. package/src/shell-env-bootstrap.ts +17 -3
  388. package/src/task-agent/board.ts +1 -1
  389. package/src/task-agent/card-evidence.ts +105 -10
  390. package/src/task-agent/judge.ts +7 -0
  391. package/src/task-agent/live-moves.ts +120 -20
  392. package/src/task-agent/mission.ts +1 -1
  393. package/src/task-agent/parent-host.ts +315 -0
  394. package/src/task-agent/shadow.ts +10 -1
  395. package/src/task-agent/task-hand.ts +16 -4
  396. package/src/task-orchestrator/surfaces/pod-command-job.ts +60 -11
  397. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +4 -0
  398. package/src/task-orchestrator/surfaces/pod-gate-deps.ts +123 -0
  399. package/src/task-orchestrator/surfaces/pod-install-slots.ts +89 -0
  400. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -10
  401. package/src/task-orchestrator/surfaces/pod-pool.ts +147 -34
  402. package/src/task-orchestrator/surfaces/self-implement-pod.ts +58 -9
  403. package/src/telegram-commands.ts +41 -0
  404. package/src/testing/real-cli-spawn.ts +106 -0
  405. package/src/tool-runtime/browser-runtime.ts +87 -3
  406. package/src/tool-runtime/index.ts +1 -0
  407. package/src/user-config.ts +76 -7
  408. package/src/version/packed-revision.json +1 -1
  409. package/apps/pwa/out/_next/static/J5H7BvqgSI8DUjtRRcA_S/_buildManifest.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/1157-cba0e8553d35a980.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/171-23a877ed11720de9.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/2336-e830c777eb6bce04.js +0 -1
  416. package/apps/pwa/out/_next/static/chunks/2375-e061bb24cd2b5cde.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/3094.67339318c7f72a3a.js +0 -2
  419. package/apps/pwa/out/_next/static/chunks/338-ceb956612dcfaa86.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/3395-835e4ceaa6335ba4.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  422. package/apps/pwa/out/_next/static/chunks/3441-be82e3595aef3a20.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/3689-89905039bf3e7257.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/3822-6f268bc26c6a84ac.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/4457-d7df81c90f9d0268.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/4551-77dadae76f6cbace.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/4978.6fd93b974441e87f.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/5012-f746f6549b869f91.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/62-5bfed1e23790b745.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/6320-9bc8561fde416e07.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/649-ca96d1c5d09e02b8.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/6726-85a7db59b288c53f.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/6735-33267c4630d0d963.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/7633-141682015873beb6.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/8067-143791231c99bd02.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/8430-a10cfba8ef282d4e.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/8870-9614a213b990b10b.js +0 -25
  447. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/9454-12c2f30dea62291c.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/976-4a9b4ebdca7c739a.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/9989-15cdf568bafa9fc8.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/ae787e4c-e5b1ef00b2dbceca.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/app/approvals/page-deef5ee191830f14.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-b193da485f9a14b2.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/app/board/page-b6e1a79df0e214f4.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/app/botlab/page-e84df4d907f703c7.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/app/bots/page-a5fb9a5db89ae4ea.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/app/ceo/page-1499f481d7fc52d6.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/app/chat/page-c7cf753aeb648790.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/app/consult/page-4118469e514e10fd.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/app/control/page-e968f7630654332a.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/app/decisions/page-505915052f947022.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c2f962fb4a3b06c6.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/app/editor/page-7b5ed0bd8a589ec4.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/app/exec/page-cf8193250dd42dd4.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/app/field/page-cf3f5dfa35dea8e9.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/app/inside/page-5b29d9b06ceadade.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/app/intake/page-a15e7fcc283e9ca7.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/app/layout-d2915e7b70ff3d0e.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/loops/page-2595f0eba29f57e1.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/app/market/page-c776322454156e36.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-77bbd17f4435aa10.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/app/morning/page-049689e611ecc936.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/app/not-found-85954a4fb09c44eb.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e773e552e1068ee6.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5633c4bfa7684b4a.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d829b92bd01b4994.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-061c317fc771becf.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a45ece8865ed4b6.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/app/page-0be990618c0d56bd.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/app/reflection/page-bfea4865dc244b73.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d6ba8e337741484.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/app/sessions/page-76a88b55d816482e.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-bba1542df59f61ce.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/app/settings/page-4185c95689bb372e.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b699e1a8d5d34b8b.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/app/setup/page-c225e338c31bf274.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/app/share/page-449353f70507ca1f.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/app/showroom/page-90b889714102476d.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f1ee7fbeb7f96ddc.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/app/term/page-d59a95e1434dfaa0.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/app/today/page-71491a23414d1a47.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/app/trace/page-de7112bdb65fa4fe.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/app/vault/page-feb4d0d88079660d.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f17d887b40dd6b1d.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/workflows/page-8da77be2192bcd5d.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72c3b9a5e9582b29.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3afe4c8d0c48c39.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/main-app-b9308f2d8a931531.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/webpack-6f35f9d892fa630b.js +0 -1
  507. package/apps/pwa/out/_next/static/css/85f53c6f35d11382.css +0 -1
  508. /package/apps/pwa/out/_next/static/{J5H7BvqgSI8DUjtRRcA_S → MObU8ujkMciAKr6ljAV05}/_ssgManifest.js +0 -0
  509. /package/skills/project-onboarding/{skill.md → SKILL.md} +0 -0
@@ -0,0 +1,173 @@
1
+ // OP-LOOP-DECIDE — the OP seat loop filters open decision cards instead of a Claude OP session doing it by hand.
2
+ // Delegation = 대표 10-06 COO card filtering rule (feedback_coo_filters_decision_cards) ⊕ 10-07 scope-card default b.
3
+ // Config `loops.seat.opDecide.mode` = shadow (default · record only) | live (decide / route).
4
+ import { debug } from '../debug/log.js';
5
+ import type { DecisionEntry, DecisionLedger } from '../decisions/decision-ledger.js';
6
+ import type { SeatId } from '../seat-dispatch/seat-questions.js';
7
+ import { releasePathHold } from '../self-dev/release-path-guard.js';
8
+
9
+ export type OpDecideMode = 'shadow' | 'live';
10
+ export type OpDecideRule = 'repeat-stop' | 'scope-expand' | 'scope-sensitive' | 'scope-release-path' | 'scope-unknown' | 'run-blocking' | 'forbidden';
11
+ export type OpDecideVerdict =
12
+ | { verdict: 'auto'; rule: OpDecideRule; choice: string; reason: string }
13
+ | { verdict: 'route'; rule: OpDecideRule; to: SeatId | 'CEO'; reason: string };
14
+ export type OpDecideCandidate = { kind: 'decision-filter'; id: string; mode: OpDecideMode } & OpDecideVerdict;
15
+
16
+ export const OP_DECIDE_AGENT = 'seat-loop:OP';
17
+ export const OP_DECIDE_DELEGATION = '대표 10-06 COO 카드 거르기 규칙 · 10-07 범위 카드 기본 b(돈·보안·비밀·공개 경로만 유지)';
18
+
19
+ /** Categories that must reach the CEO whatever the recommendation says (rule 3). */
20
+ const FORBIDDEN_CATEGORIES: ReadonlySet<DecisionEntry['category']> = new Set(['money', 'security', 'secret', 'publish']);
21
+ const FORBIDDEN_WORDS = /특허|patent|외부\s*계약|계약서|contract/i;
22
+
23
+ /** Path segments that keep a scope card open — money · security · secret · public (rule 2 exception). */
24
+ const SENSITIVE_PATH: ReadonlyArray<{ kind: 'money' | 'security' | 'secret' | 'public'; pattern: RegExp }> = [
25
+ { kind: 'secret', pattern: /(^|[/._-])(secrets?|credentials?|\.env|keychain|apns|backup-key)([/._-]|$)|\.(pem|p8|p12|key)$/i },
26
+ { kind: 'security', pattern: /(^|[/._-])(auth|oauth|security|sandbox|permissions?|acl|csp|tokens?|crypto)([/._-]|$)/i },
27
+ { kind: 'money', pattern: /(^|[/._-])(money|finance|billing|payments?|payouts?|refunds?|revenue|pricing|stripe|invoices?|checkout|wallet|trad(e|ing)|broker|budget|quota)([/._-]|$)/i },
28
+ { kind: 'public', pattern: /(^|\/)(README|CHANGELOG|LICENSE|NOTICE)(\.[a-z]+)?$|(^|[/._-])(publish|public|homepage|site|npm)([/._-]|$)|^\.github\/workflows\/|^scripts\/release-loop\/release-publish/i },
29
+ ];
30
+
31
+ export function sensitivePathKind(file: string): 'money' | 'security' | 'secret' | 'public' | undefined {
32
+ return SENSITIVE_PATH.find(({ pattern }) => pattern.test(file))?.kind;
33
+ }
34
+
35
+ const SCOPE_QUESTION = /outside the authored target paths/i;
36
+
37
+ /** Outside-file names listed on a harness scope card; undefined when the card carries no complete list. */
38
+ export function scopeOutsideFiles(card: Pick<DecisionEntry, 'pendingQuestion'>): string[] | undefined {
39
+ const text = card.pendingQuestion ?? '';
40
+ const at = text.indexOf('Outside files:');
41
+ if (at < 0) return undefined;
42
+ // «… N more outside file(s) not shown» anywhere after the list header — a hidden file cannot be vetted.
43
+ if (/more outside file/i.test(text.slice(at))) return undefined;
44
+ const lines = text.slice(at + 'Outside files:'.length).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
45
+ const files: string[] = [];
46
+ for (const line of lines) {
47
+ if (!line.startsWith('- ')) break;
48
+ // «… N more outside file(s) not shown» — a hidden file cannot be vetted.
49
+ if (/more outside file/i.test(line)) return undefined;
50
+ const name = line.slice(2).replace(/\s+\(declared-path sibling test: [a-z]+\)$/, '').trim();
51
+ if (name) files.push(name);
52
+ }
53
+ return files.length ? files : undefined;
54
+ }
55
+
56
+ function optionKey(card: DecisionEntry, label: RegExp): string | undefined {
57
+ return card.options.find((option) => label.test(option.label))?.key;
58
+ }
59
+
60
+ export function isRepeatStopCard(card: DecisionEntry): boolean {
61
+ return card.raisedBy.agent === 'seat-loop' && / 반복 착지 0$/.test(card.title);
62
+ }
63
+
64
+ export function isScopeCard(card: DecisionEntry): boolean {
65
+ return card.raisedBy.agent === 'harness' && (card.category === 'scope' || card.category === 'irreversible')
66
+ && SCOPE_QUESTION.test(`${card.title}\n${card.pendingQuestion ?? ''}`) && !!card.resume;
67
+ }
68
+
69
+ /** Judge one open card. undefined = not this filter's card (left alone). */
70
+ export function judgeOpDecision(card: DecisionEntry, runOwner: (runId: string) => SeatId | undefined = () => undefined): OpDecideVerdict | undefined {
71
+ if (card.status !== 'open') return undefined;
72
+ const repeat = isRepeatStopCard(card);
73
+ const scope = isScopeCard(card);
74
+ const runId = card.resume?.runId;
75
+ if (!repeat && !scope && !runId) return undefined;
76
+ if (FORBIDDEN_CATEGORIES.has(card.category) || FORBIDDEN_WORDS.test(`${card.title}\n${card.scqa.s}`)) {
77
+ return { verdict: 'route', rule: 'forbidden', to: 'CEO', reason: `${card.category} 범주·금지 낱말 — 자동 결정 금지, 대표 카드로 남김` };
78
+ }
79
+ if (repeat) {
80
+ const stop = optionKey(card, /^멈춘다$/);
81
+ const recommended = 'option' in card.recommendation ? card.recommendation.option : undefined;
82
+ if (stop && recommended === stop) {
83
+ return { verdict: 'auto', rule: 'repeat-stop', choice: stop, reason: `반복 착지 0 — 권고 ${stop}(멈춘다) · 그냥 둔 것과 같은 결과` };
84
+ }
85
+ return { verdict: 'route', rule: 'repeat-stop', to: 'CEO', reason: '반복 정지 카드인데 권고가 «멈춘다»가 아님 — 확신 없음' };
86
+ }
87
+ if (scope) {
88
+ const expand = optionKey(card, /^Expand scope$/i);
89
+ const files = scopeOutsideFiles(card);
90
+ const owner = runId ? runOwner(runId) : undefined;
91
+ const route = (rule: OpDecideRule, reason: string): OpDecideVerdict =>
92
+ ({ verdict: 'route', rule, to: owner && owner !== 'OP' ? owner : 'CEO', reason });
93
+ if (!expand) return route('scope-unknown', '범위 카드에 «Expand scope» 선택지가 없음');
94
+ if (!files) return route('scope-unknown', '바깥 파일 목록이 없거나 일부만 보임 — 경로를 확인 못 함');
95
+ const sensitive = files.map((file) => ({ file, kind: sensitivePathKind(file) })).filter((row) => row.kind);
96
+ if (sensitive.length) {
97
+ return { verdict: 'route', rule: 'scope-sensitive', to: 'CEO',
98
+ reason: `바깥 파일 중 ${sensitive[0]!.kind} 경로(${sensitive[0]!.file}${sensitive.length > 1 ? ` 외 ${sensitive.length - 1}` : ''}) — 유지 여부는 대표 판단` };
99
+ }
100
+ // Release/gate paths follow the release-path SSOT (src/self-dev/release-path-guard.ts) — never auto-widen; TC owns the gate.
101
+ // TODO(0.2.21 RELEASE-PATH-GUARD-GATE): src/task-orchestrator/surfaces/pod-command-job.ts and src/release-loop/gate-shards.ts
102
+ // are gate paths not yet in RELEASE_PATH_PREFIXES; they become covered here once that list grows.
103
+ const release = releasePathHold(files);
104
+ if (release) {
105
+ return { verdict: 'route', rule: 'scope-release-path', to: 'TC',
106
+ reason: `바깥 파일 중 발행·게이트 경로(${release}) — 게이트 주인 TC 판단` };
107
+ }
108
+ return { verdict: 'auto', rule: 'scope-expand', choice: expand,
109
+ reason: `범위 넓힘 b — 바깥 ${files.length}개 모두 돈·보안·비밀·공개 경로 아님 · 게이트·리뷰가 가린다` };
110
+ }
111
+ const owner = runOwner(runId!);
112
+ return { verdict: 'route', rule: 'run-blocking', to: owner && owner !== 'OP' ? owner : 'CEO',
113
+ reason: owner && owner !== 'OP' ? `런 ${runId} 을 막는 카드 — 런 주인 ${owner} 자리로` : `런 ${runId} 을 막는 카드 — 주인 자리 모름, 대표 카드로 남김` };
114
+ }
115
+
116
+ export type OpDecideDeps = {
117
+ mode: OpDecideMode;
118
+ ledger: Pick<DecisionLedger, 'list' | 'decide'>;
119
+ runOwner?: (runId: string) => SeatId | undefined;
120
+ /** Route a run-blocking card to its owner seat (live only); returns false when delivery failed. */
121
+ routeToSeat?: (to: SeatId, card: DecisionEntry, reason: string) => boolean;
122
+ /** Candidates already recorded for this card (dedup across ticks). */
123
+ recorded?: (id: string) => readonly OpDecideCandidate[];
124
+ record: (candidate: OpDecideCandidate) => void;
125
+ };
126
+
127
+ /** One filtering pass over open cards. Never throws for a single card; returns what it recorded. */
128
+ export function runOpDecide(deps: OpDecideDeps): OpDecideCandidate[] {
129
+ const out: OpDecideCandidate[] = [];
130
+ let cards: DecisionEntry[];
131
+ try { cards = deps.ledger.list({ status: 'open' }); }
132
+ catch (error) {
133
+ observeOpDecide({ event: 'ledger-unreadable', error: String(error).slice(0, 200) });
134
+ return out;
135
+ }
136
+ for (const card of cards) {
137
+ let judged: OpDecideVerdict | undefined;
138
+ try { judged = judgeOpDecision(card, deps.runOwner); }
139
+ catch (error) {
140
+ observeOpDecide({ event: 'judge-failed', id: card.id, error: String(error).slice(0, 200) });
141
+ continue;
142
+ }
143
+ if (!judged) continue;
144
+ const candidate: OpDecideCandidate = { kind: 'decision-filter', id: card.id, mode: deps.mode, ...judged };
145
+ const same = (row: OpDecideCandidate) => row.mode === candidate.mode && row.verdict === candidate.verdict && row.rule === candidate.rule
146
+ && ('to' in row ? row.to : row.choice) === ('to' in candidate ? candidate.to : candidate.choice);
147
+ if ((deps.recorded?.(card.id) ?? []).some(same)) continue;
148
+ if (deps.mode === 'live' && candidate.verdict === 'auto') {
149
+ try {
150
+ deps.ledger.decide(card.id, candidate.choice,
151
+ { kind: 'auto', agent: OP_DECIDE_AGENT, track: 'OP', delegation: OP_DECIDE_DELEGATION }, candidate.reason);
152
+ } catch (error) {
153
+ observeOpDecide({ event: 'decide-failed', id: card.id, rule: candidate.rule, error: String(error).slice(0, 200) });
154
+ continue;
155
+ }
156
+ }
157
+ if (deps.mode === 'live' && candidate.verdict === 'route' && candidate.to !== 'CEO' && deps.routeToSeat) {
158
+ let delivered = false;
159
+ try { delivered = deps.routeToSeat(candidate.to, card, candidate.reason); }
160
+ catch (error) { observeOpDecide({ event: 'route-failed', id: card.id, to: candidate.to, error: String(error).slice(0, 200) }); }
161
+ if (!delivered) continue;
162
+ }
163
+ deps.record(candidate);
164
+ out.push(candidate);
165
+ observeOpDecide({ event: 'op-decide', id: card.id, mode: candidate.mode, verdict: candidate.verdict, rule: candidate.rule,
166
+ ...(candidate.verdict === 'auto' ? { choice: candidate.choice } : { to: candidate.to }), category: card.category, reason: candidate.reason });
167
+ }
168
+ return out;
169
+ }
170
+
171
+ function observeOpDecide(data: Record<string, unknown>): void {
172
+ try { debug.log('seat.loop', 'op-decide', data); } catch { /* observation cannot change a decision */ }
173
+ }
@@ -26,6 +26,7 @@ import { answerCrossCheck, answerSeat, askCrossCheck, askSeat, crossCheckAnswer,
26
26
  import { queryRunningRuns } from '../self-implement/running-runs.js';
27
27
  import { checklistHistory, listChecklist, type Checklist } from '../release-loop/checklist.js';
28
28
  import { readSchedules, releasedVersion } from '../release-loop/feature-store.js';
29
+ import { runOpDecide, type OpDecideCandidate } from './op-decide.js';
29
30
 
30
31
  // `kind`/`createdAt` are the V3 shadow-compare keys (내부 문서 `METHOD-v3-shadow-compare-2026-10-02` · MK 10-02 18:54).
31
32
  export type SeatItem = { source: 'request' | 'checklist' | 'hook' | 'seat-question'; kind?: 'request' | 'cell' | 'hook-task' | 'seat-question'; id: string; title: string; text: string; evidence?: string; status?: string; version?: string; seat?: string; evidenceHash?: string; asOf?: string; queuedAt?: string; createdAt?: string; from?: SeatId };
@@ -43,7 +44,7 @@ export type TcCandidate =
43
44
  | { kind: 'publication-pr-approval-wait'; pr: number; title: string; readyAt: string; approvalWaitAt: string; paths: string[] }
44
45
  | { kind: 'other-seat-cell-defect'; version: string; id: string; title: string; to: SeatId };
45
46
  export type TcPullRequest = { number: number; title: string; body?: string; state: 'OPEN' | 'MERGED' | 'CLOSED'; isDraft: boolean; createdAt: string; updatedAt?: string; mergedAt?: string | null; readyAt?: string; approvalWaitAt?: string; paths?: string[]; reviewDecision?: string };
46
- export type SeatEntry = { seat: string; ts?: string; at: string; modeDowngradeReason?: string; status: 'shadow' | 'attempting' | 'outcome-unknown' | 'queued' | 'refused' | 'held' | 'launched' | 'hitl' | 'wait' | 'asked' | 'answered' | 'awaiting-answer' | 'awaiting-xcheck' | 'awaiting-resolution' | 'resolved-by-neighbor' | 'resolved' | 'rejected-no-evidence' | 'skipped-budget' | 'skipped-empty'; item?: SeatItem; candidate?: OpCandidate | TcCandidate; action?: SeatAction; reason?: string; runId?: string; queueId?: string; inquiry?: SeatInquiry; answer?: string; escalated?: boolean; xcheckRequestedAt?: string; xcheckQuestionId?: number; xcheckNeighbor?: SeatId; xcheckNote?: string; xcheckJudgmentEvidence?: string; xcheckWaitMinutes?: number };
47
+ export type SeatEntry = { seat: string; ts?: string; at: string; modeDowngradeReason?: string; status: 'shadow' | 'attempting' | 'outcome-unknown' | 'queued' | 'refused' | 'held' | 'launched' | 'hitl' | 'wait' | 'asked' | 'answered' | 'awaiting-answer' | 'awaiting-xcheck' | 'awaiting-resolution' | 'resolved-by-neighbor' | 'resolved' | 'rejected-no-evidence' | 'skipped-budget' | 'skipped-empty'; item?: SeatItem; candidate?: OpCandidate | TcCandidate | OpDecideCandidate; action?: SeatAction; reason?: string; runId?: string; queueId?: string; inquiry?: SeatInquiry; answer?: string; escalated?: boolean; xcheckRequestedAt?: string; xcheckQuestionId?: number; xcheckNeighbor?: SeatId; xcheckNote?: string; xcheckJudgmentEvidence?: string; xcheckWaitMinutes?: number };
47
48
  export type SeatLoopResult = SeatEntry | { seat: string; status: 'skipped-off'; modeDowngradeReason?: string };
48
49
 
49
50
  export function seatLoopTickLine(result: SeatLoopResult): string {
@@ -99,6 +100,8 @@ export type SeatDeps = {
99
100
  /** Judge a decision draft against the receiving seat's evidence; null leaves the request pending. */
100
101
  crossCheck?: (seat: SeatId, draft: string, from: SeatId) => Promise<CrossCheckJudgment | null> | CrossCheckJudgment | null;
101
102
  decisionsConfig?: UserConfig['decisions'];
103
+ /** OP-LOOP-DECIDE: who owns a run (for run-blocking cards). Default = today's seat ledgers' launched rows. */
104
+ runOwner?: (runId: string) => SeatId | undefined;
102
105
  };
103
106
 
104
107
  const repoRoot = resolve(import.meta.dir, '../..');
@@ -291,6 +294,8 @@ function personReopened(ledger: readonly SeatEntry[], seat: string, item: SeatIt
291
294
  const ref = decisionRef(seat, item);
292
295
  return new DecisionLedger({ stateDir: root }).list({ status: 'all' }).some((card) => {
293
296
  if (!card.refs?.includes(ref) || card.status !== 'decided' || !card.decidedAt) return false;
297
+ // «멈춘다» on a repeat-stop card keeps the cell held — only a reopen (or any other card's decision) frees it (OP-LOOP-DECIDE).
298
+ if (/ 반복 착지 0$/.test(card.title) && card.options.find((option) => option.key === card.choice)?.label === '멈춘다') return false;
294
299
  const decidedAt = Date.parse(card.decidedAt);
295
300
  return Number.isFinite(decidedAt) && decidedAt > heldAt;
296
301
  });
@@ -551,6 +556,40 @@ export async function gatherSeatInputs(seat: string, deps: SeatDeps = {}, ledger
551
556
  return { requests: pending, checklist, role: read(join(deps.repo ?? repoRoot, 'docs', 'roles', `${seat}.md`)).slice(0, 4_000) };
552
557
  }
553
558
 
559
+ /** OP-LOOP-DECIDE: filter open decision cards each OP turn. Shadow records; live decides/routes. A failure never blocks the turn. */
560
+ function opDecidePass(config: SeatLoopConfig, deps: SeatDeps, now: Date, path: string, stateRoot: string, ledger: readonly SeatEntry[]): void {
561
+ const mode = config.opDecide?.mode === 'live' ? 'live' : 'shadow';
562
+ let owners: Map<string, SeatId> | undefined;
563
+ try {
564
+ const append = deps.append ?? defaultAppend;
565
+ const recorded = new Map<string, OpDecideCandidate[]>();
566
+ for (const row of ledger) {
567
+ if (row.candidate?.kind === 'decision-filter') recorded.set(row.candidate.id, [...(recorded.get(row.candidate.id) ?? []), row.candidate]);
568
+ }
569
+ runOpDecide({
570
+ mode,
571
+ ledger: cardLedger(stateRoot, deps, now),
572
+ runOwner: deps.runOwner ?? ((runId) => {
573
+ owners ??= new Map((['OP', 'UX', 'MK', 'TC'] as const).flatMap((owner) =>
574
+ readSeatLedger(owner, deps, now).filter((row) => row.runId).map((row) => [row.runId!, owner] as const)));
575
+ return owners.get(runId);
576
+ }),
577
+ routeToSeat: (to, card, reason) => {
578
+ askSeat(stateRoot, 'OP', to, `결정 카드 ${card.id} «${card.title}» — ${reason}. 런 주인이 판단해 elanous decisions decide ${card.id} 로 닫아 주세요.`,
579
+ `op-decide:${card.id}:${to}`);
580
+ return true;
581
+ },
582
+ recorded: (id) => recorded.get(id) ?? [],
583
+ record: (candidate) => {
584
+ append(path, { seat: 'OP', ts: now.toISOString(), at: now.toISOString(),
585
+ status: mode === 'shadow' ? 'shadow' : candidate.verdict === 'auto' ? 'resolved' : 'hitl',
586
+ ...(candidate.verdict === 'route' && candidate.to === 'CEO' ? { escalated: true } : {}),
587
+ candidate, reason: candidate.reason });
588
+ },
589
+ });
590
+ } catch (error) { observe('op-decide', { event: 'pass-failed', mode, error: String(error).slice(0, 200) }); }
591
+ }
592
+
554
593
  const OP_CUTOFF_WINDOW_MS = 2 * 60 * 60_000;
555
594
  const RUN_REFERENCE = /\brun-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
556
595
 
@@ -870,10 +909,25 @@ const SEAT_ACTION_RULES: ReadonlyArray<{ kind: 'wait' | 'harness' | 'decision';
870
909
  { kind: 'wait', signal: /실측\s*대기|(?:사람|실제)\s*기기(?!\s*(?:(?:실측|측정|확인)\s*)?완료)(?:\s*(?:실측|측정|확인|대기))?|실물\s*측정(?!\s*완료)/iu, source: 'content', resolvedBy: /(?:실측|측정|(?:사람|실제)\s*기기|실물\s*측정)\s*완료/iu },
871
910
  { kind: 'wait', signal: /\u{1F451}\s*확인\s*대기/iu, source: 'content', resolvedBy: /\u{1F451}\s*확인\s*완료/iu },
872
911
  { kind: 'decision', signal: TRACK_AGENT_FORBIDDEN_ACTION_REGEX, source: 'task' },
912
+ { kind: 'decision', signal: /토큰\s*(?:을|를)?\s*(?:출력|노출|공개|첨부|붙여)/iu, source: 'task' },
873
913
  { kind: 'decision', signal: /(?:마켓|레지스트리)(?:에|로)?\s*(?:게시|등록|발행)|사이트\s*운영\s*반영|SNS(?:에|로)?\s*(?:게시|발행|업로드)|공개\s*발행/iu, source: 'task' },
874
914
  { kind: 'harness', signal: /(?:마켓|레지스트리|사이트|SNS|공개)?(?:에|로)?\s*(?:게시|발행|배포|등록|운영\s*반영)(?:를?\s*위한)?\s*(?:준비|초안|원고|자료|구현|점검|테스트)|(?:마켓|레지스트리|사이트|SNS|공개)?(?:에|로)?\s*(?:게시|발행|배포|등록)(?:용|를?\s*위한)\s*(?:초안|원고|자료|코드|기능)/iu, source: 'task' },
875
915
  ];
876
916
 
917
+ // SEAT-FORBID-NEGATION: «비밀 0» · «비밀 제외» · «no secret» name the word to exclude it, not to act on it.
918
+ // Only a negation right next to the hit (optionally after a short noun such as 키 · 증명 and a particle) clears it;
919
+ // «비밀 키를 붙여라» keeps its imperative and stays a decision.
920
+ const FORBID_NEGATION = '(?:0(?![\\dx.,])|제외|없이|빼고|금지|없음|none\\b|no\\b|without\\b|excluding\\b)';
921
+ const FORBID_NEGATION_AFTER = new RegExp(`^(?:\\s*(?:증명|정보|키|값|토큰|keys?|tokens?)(?![A-Za-z]))?\\s*(?:은|는|이|가|을|를|:)?\\s*${FORBID_NEGATION}`, 'iu');
922
+ const FORBID_NEGATION_BEFORE = /(?:^|[\s(\[«"'·,:])(?:no|without|excluding|none|제외|금지)\s*[:·-]?\s*$/iu;
923
+
924
+ export const FORBID_JUDGMENT_LINE = (word: string | undefined): string =>
925
+ `판정 근거: «${word ?? '?'}» 바로 앞뒤에 부정 문면(0·제외·없이·빼고·금지·없음·no·without·excluding)이 없어 실행 요청으로 봤다`;
926
+
927
+ export function forbiddenHitNegated(text: string, index: number, length: number): boolean {
928
+ return FORBID_NEGATION_AFTER.test(text.slice(index + length)) || FORBID_NEGATION_BEFORE.test(text.slice(0, index));
929
+ }
930
+
877
931
  export function planAction(item: SeatItem, seat?: string): { kind: 'decision' | 'harness' | 'wait'; text: string; reason?: string } {
878
932
  const task = `${item.id}\n${item.title}\n${item.text}`;
879
933
  const content = `${task}\n${item.evidence ?? ''}`;
@@ -884,7 +938,9 @@ export function planAction(item: SeatItem, seat?: string): { kind: 'decision' |
884
938
  if (resolvedBy?.test(item.evidence ?? '')) return null;
885
939
  const hits = [...text.matchAll(new RegExp(signal.source, `${signal.flags.replace('g', '')}g`))];
886
940
  const hit = kind === 'decision' ? hits.find((match) => !prepared.some((prep) =>
887
- match.index! >= prep.index! && match.index! + match[0].length <= prep.index! + prep[0].length)) : hits[0];
941
+ match.index! >= prep.index! && match.index! + match[0].length <= prep.index! + prep[0].length)
942
+ && !(forbiddenHitNegated(text, match.index!, match[0].length)
943
+ && (observe('forbid-negated', { item: item.id, word: match[0] }), true))) : hits[0];
888
944
  return hit ? { kind, reason: hit[0] } : null;
889
945
  }).find((hit) => hit !== null);
890
946
  const kind = rule?.kind ?? 'harness';
@@ -1004,6 +1060,7 @@ export async function runSeatLoopOnce(seat: string, deps: SeatDeps = {}): Promis
1004
1060
  } catch (error) { observe('heartbeat-write-failed', { seat, error: String(error).slice(0, 200) }); }
1005
1061
  const recorded = readSeatLedger(seat, deps, now);
1006
1062
  const ledger = config.mode === 'live-safe' ? reconciledQueueLedger(recorded, stateRoot, deps) : recorded;
1063
+ if (seat === 'OP') opDecidePass(config, deps, now, path, stateRoot, ledger);
1007
1064
  let turnError: unknown;
1008
1065
  try {
1009
1066
  if (config.mode === 'on' && config.questions === 'on') {
@@ -1494,7 +1551,7 @@ export async function runSeatLoopOnce(seat: string, deps: SeatDeps = {}): Promis
1494
1551
  : undefined;
1495
1552
  } catch (error) { observe('decision-source-unreadable', { seat, item: item.id, error: String(error).slice(0, 200) }); }
1496
1553
  const material = decisionCardMaterial({ what: `${seat} 배정 항목: ${item.title} 역할: ${inputs.role || '역할 근거 없음'}`, soFar: `요청 내용: ${item.text}`,
1497
- current: `밑바탕 재측: ${currentStatus ?? '상태 미확인'}; 요청에서 금지 문면 «${action.reason}» 발견 — 실행 전 사람 승인 필요`,
1554
+ current: `밑바탕 재측: ${currentStatus ?? '상태 미확인'}; 요청에서 금지 문면 «${action.reason}» 발견 — 실행 전 사람 승인 필요; ${FORBID_JUDGMENT_LINE(action.reason)}`,
1498
1555
  question: `금지 문면 «${action.reason}»이 걸린 요청을 승인할까?`, answer: '승인 전에는 집행하지 않고 보류한다',
1499
1556
  options, recommendation, confidence: '높음 — 요청에 금지 문면 직접 일치',
1500
1557
  ifUntouched: '자동 집행되지 않고 해당 칸은 보류 상태로 남는다',
@@ -6,6 +6,7 @@ import { promisify } from 'node:util';
6
6
  import { debug } from '../debug/log.js';
7
7
  import { effectiveInstanceRoot } from '../instance/resolve.js';
8
8
  import { getUserConfig, type SeatLoopConfig } from '../user-config.js';
9
+ import { collectDraftMetrics, collectOverlapMetrics, countSalvagedToday, type DraftMetrics, type OverlapMetrics } from '../self-dev/draft-sweep.js';
9
10
  import { seatDay, seatLedgerPath, type OpCandidate, type SeatEntry } from './seat-loop.js';
10
11
 
11
12
  export type SeatReportDeps = {
@@ -16,6 +17,10 @@ export type SeatReportDeps = {
16
17
  config?: SeatLoopConfig;
17
18
  post?: boolean;
18
19
  send?: (body: string, seat: string, pr: number) => Promise<void> | void;
20
+ draftMetrics?: (now: Date) => Promise<DraftMetrics>;
21
+ overlapMetrics?: (now: Date) => Promise<OverlapMetrics>;
22
+ /** DRAFT-NOT-ARCHIVE salvage branches since the KST day start; null = unreadable. */
23
+ salvagedToday?: (dayStart: Date, now: Date) => Promise<number | null>;
19
24
  };
20
25
  export type SeatReportResult = { seat: string; date: string; body: string; posted: boolean };
21
26
  const repoRoot = resolve(import.meta.dir, '../..');
@@ -36,6 +41,21 @@ function opJudgment(candidate: OpCandidate): { kind: 'card' | 'todo'; text: stri
36
41
  text: `${text} (${candidate.category ?? '범주 없음'})` };
37
42
  }
38
43
 
44
+ /** OVERLAP-METRIC line; ⛔ an unmeasured value says so instead of printing 0. */
45
+ function overlapLine(metrics: OverlapMetrics): string {
46
+ if (metrics.sourceIncomplete || metrics.launches24h === null) return ' · 겹침 발사 24h 못 잼(원천 불완전)';
47
+ const launched = metrics.launched === null ? '' : metrics.unmeasured
48
+ ? ` 이상 (발사 ${metrics.launched} 중 ${metrics.unmeasured} 못 잼)` : ` (발사 ${metrics.launched})`;
49
+ const rate = metrics.autoRate === null || metrics.linked === null || metrics.autoLanded === null
50
+ ? (metrics.linked === 0 ? '표본 없음' : '못 잼')
51
+ : `${(metrics.autoRate * 100).toFixed(1)}% (${metrics.autoLanded}/${metrics.linked})`;
52
+ const median = metrics.secondSiblingMedianHours === null ? (metrics.linked === null ? '못 잼' : '표본 없음')
53
+ : `${metrics.secondSiblingMedianHours.toFixed(1)}h`;
54
+ const salvage = (metrics.salvaged ? ` · 수확 가지 형제 ${metrics.salvaged}(미착지)` : '')
55
+ + (metrics.salvageUnmeasured ? ` · 수확 가지 ${metrics.salvageUnmeasured} 못 잼` : '');
56
+ return ` · 겹침 발사 24h ${metrics.launches24h}${launched} · 겹침 자동 착지 ${rate} · 둘째 형제 착지 중앙값 ${median}${salvage}`;
57
+ }
58
+
39
59
  async function defaultSend(body: string, seat: string, pr: number, repo: string): Promise<void> {
40
60
  const dir = mkdtempSync(join(tmpdir(), 'seat-report-'));
41
61
  try {
@@ -58,8 +78,13 @@ export async function seatReport(seat: string, deps: SeatReportDeps = {}): Promi
58
78
  // One line per item, its last state wins: an `attempting` row followed by `launched` is not «unconfirmed».
59
79
  const latest = new Map<string, SeatEntry>();
60
80
  const judgments = new Map<string, OpCandidate>();
81
+ const filtered = { auto: 0, route: 0 };
61
82
  for (const entry of entries) {
62
- if (seat === 'OP' && entry.candidate) {
83
+ if (entry.candidate?.kind === 'decision-filter') {
84
+ filtered[entry.candidate.verdict] += 1;
85
+ continue;
86
+ }
87
+ if (seat === 'OP' && entry.candidate && 'verdict' in entry.candidate) {
63
88
  if (entry.candidate.verdict === 'none') {
64
89
  if (entry.candidate.id) {
65
90
  const key = entry.candidate.kind === 'unassigned-cell'
@@ -89,8 +114,38 @@ export async function seatReport(seat: string, deps: SeatReportDeps = {}): Promi
89
114
  return `건너뜀 ${entry.status} ${label}`;
90
115
  });
91
116
  const classified = [...judgments.values()].map(opJudgment).filter((row): row is NonNullable<typeof row> => row !== null);
92
- const opDetail = classified.length ? ` · 결정 카드 후보: ${classified.filter((row) => row.kind === 'card').map((row) => row.text).join(' / ') || '없음'} · OP 가 할 일: ${classified.filter((row) => row.kind === 'todo').map((row) => row.text).join(' / ') || '없음'}` : '';
93
- const body = `**[${seat}]** {{TS}} → 보고 ${date}: ${detail.join(' · ') || (classified.length ? 'OP 그림자 판단' : '원장 기록 없음')}${opDetail}`;
117
+ const opDetail = (classified.length ? ` · 결정 카드 후보: ${classified.filter((row) => row.kind === 'card').map((row) => row.text).join(' / ') || '없음'} · OP 가 할 일: ${classified.filter((row) => row.kind === 'todo').map((row) => row.text).join(' / ') || '없음'}` : '')
118
+ + (filtered.auto + filtered.route ? ` · 카드 거르기: 자동 ${filtered.auto} · 넘김 ${filtered.route}` : '');
119
+ let draftDetail = '';
120
+ if (seat === 'OP') {
121
+ try {
122
+ const metrics = await (deps.draftMetrics ?? (async (clock: Date) => {
123
+ const [{ resolveRepositoryName }, { githubDraftSweepAdapters }] = await Promise.all([
124
+ import('../harness/repository-name.js'), import('../harness/harness-cli-command.js'),
125
+ ]);
126
+ return collectDraftMetrics(resolveRepositoryName({}), githubDraftSweepAdapters(), clock);
127
+ }))(now);
128
+ draftDetail = ` · draft 재고 ${metrics.inventory} · 최장 나이 ${metrics.oldestAgeHours === null ? '해당 없음' : `${metrics.oldestAgeHours.toFixed(1)}h`} · needs-owner ${metrics.needsOwner} · 48h 전환율 ${metrics.conversion48h === null ? '표본 없음' : `${(metrics.conversion48h * 100).toFixed(1)}% (${metrics.converted48h}/${metrics.cohort48h})`}`;
129
+ } catch { draftDetail = ' · draft 지표 못 읽음'; }
130
+ try {
131
+ const overlap = await (deps.overlapMetrics ?? (async (clock: Date) => {
132
+ const [{ resolveRepositoryName }, { githubDraftSweepAdapters }, { readAskPreflightRowsSince, readSalvagedRowsSince }] = await Promise.all([
133
+ import('../harness/repository-name.js'), import('../harness/harness-cli-command.js'), import('../self-dev/ask-launch-io.js'),
134
+ ]);
135
+ return collectOverlapMetrics(resolveRepositoryName({}), { ...githubDraftSweepAdapters(), listPreflightRows: readAskPreflightRowsSince, listSalvagedRows: readSalvagedRowsSince }, clock);
136
+ }))(now);
137
+ draftDetail += overlapLine(overlap);
138
+ } catch { draftDetail += ' · 겹침 지표 못 읽음'; }
139
+ let salvagedToday: number | null = null;
140
+ try {
141
+ salvagedToday = await (deps.salvagedToday ?? (async (dayStart: Date, clock: Date) => {
142
+ const { readSalvagedRowsSince } = await import('../self-dev/ask-launch-io.js');
143
+ return countSalvagedToday(await readSalvagedRowsSince(dayStart), dayStart, clock);
144
+ }))(new Date(`${date}T00:00:00+09:00`), now);
145
+ } catch { salvagedToday = null; }
146
+ draftDetail += ` · 수확 가지 오늘 ${salvagedToday === null ? '못 잼' : salvagedToday}`;
147
+ }
148
+ const body = `**[${seat}]** {{TS}} → 보고 ${date}: ${detail.join(' · ') || (classified.length ? 'OP 그림자 판단' : '원장 기록 없음')}${opDetail}${draftDetail}`;
94
149
  const pr = (deps.config ?? getUserConfig().loops?.seat)?.reportPr;
95
150
  const posted = deps.post === true && pr !== undefined;
96
151
  if (posted) await (deps.send ?? ((text, id, number) => defaultSend(text, id, number, deps.repo ?? repoRoot)))(body, seat, pr);
@@ -852,7 +852,7 @@ export async function runAskLaunchFlow(
852
852
  if (launchPreflight === false) return { kind: 'stopped-before-authoring' };
853
853
 
854
854
  await deps.beforeAuthoring?.();
855
- const authorAndPreflight = async (authorAskText: string = input.askText): Promise<{
855
+ const authorAndPreflight = async (authorAskText: string = input.askText, machineSuggestedTargetPaths: readonly string[] = []): Promise<{
856
856
  readonly goalFile: string;
857
857
  readonly decision: ReturnType<typeof decideAskPreflight>;
858
858
  }> => {
@@ -950,6 +950,8 @@ export async function runAskLaunchFlow(
950
950
  recentChangeWindowDays: input.recentChangeWindowDays,
951
951
  openPrsLimit: OPEN_PR_LIMIT,
952
952
  ...(askOutsidePathHints.length > 0 ? { askOutsidePathHints } : {}),
953
+ // AUTO-TARGET: paths injected by the candidate search (not written in the ask) — a NOT-GROUNDED goal stops on them.
954
+ ...(machineSuggestedTargetPaths.length > 0 ? { machineSuggestedTargetPaths } : {}),
953
955
  declaredPathsRoot: deps.cwd(),
954
956
  },
955
957
  preflightDeps,
@@ -1026,12 +1028,13 @@ export async function runAskLaunchFlow(
1026
1028
  ...(candidates.error === undefined ? {} : { error: candidates.error }),
1027
1029
  }, candidates.error === undefined ? 'info' : 'warn');
1028
1030
  }
1029
- if (candidates.paths.length > 0) {
1030
- deps.print(`[ask] ⑴ 코드에서 후보 경로 ${candidates.paths.length}개를 찾아 넣고 다시 저작한다: ${candidates.paths.join(' · ')}`);
1031
+ const selectedPaths = candidates.paths.slice(0, 1);
1032
+ if (selectedPaths.length > 0) {
1033
+ deps.print(`[ask] ⑴ 코드에서 후보 경로 ${selectedPaths.length}개를 찾아 넣고 다시 저작한다: ${selectedPaths.join(' · ')}`);
1031
1034
  }
1032
- authored = await authorAndPreflight(candidates.paths.length > 0
1033
- ? `대상 경로: ${candidates.paths.join(' · ')}\n${input.askText}`
1034
- : input.askText);
1035
+ authored = await authorAndPreflight(selectedPaths.length > 0
1036
+ ? `대상 경로: ${selectedPaths.join(' · ')}\n${input.askText}`
1037
+ : input.askText, selectedPaths);
1035
1038
  deps.log('ask-auto-reauthor', {
1036
1039
  candidatePathCount: candidates.paths.length,
1037
1040
  firstGoalFile: first.goalFile,
@@ -5,7 +5,7 @@
5
5
  // 72차 판이 복제를 금지했으므로 여기로 옮긴다. CLI 와 TUI 가 «같은 조회»를 쓴다.
6
6
  // ⛔ 판정은 여기 없다 — 여기는 「무엇을 조회하는가」뿐이고, 「그래서 막나」는 launch-preflight 가 정한다.
7
7
  import { execFileSync } from 'node:child_process';
8
- import { readFileSync } from 'node:fs';
8
+ import { readFileSync, realpathSync } from 'node:fs';
9
9
  import {
10
10
  parseAskTargetPathHints,
11
11
  parseAskTargetPathHintsResult,
@@ -97,7 +97,7 @@ function inspectLaunchingTree(cwd: string): LaunchingTreeProbe {
97
97
 
98
98
  /** 발사 전 검사가 쓰는 조회 구현 — ⛔ 이 «한 벌»을 모든 표면이 공유한다. */
99
99
  export async function buildAskPreflightDeps(options: BuildAskPreflightDepsOptions = {}): Promise<AskPreflightDeps & { inspectLaunchingTree(cwd: string): LaunchingTreeProbe }> {
100
- const [{ tracedPathReferences, verbatimOriginalAsk }, { loadRunLedger, queryFederatedCompletedRunLedgers, queryFederatedInterruptedRunLedgers, queryFederatedUnfinishedRunLedgers }] = await Promise.all([
100
+ const [{ tracedPathReferences, verbatimOriginalAsk, isNotGroundedWithoutPersistentEvidence }, { loadRunLedger, queryFederatedCompletedRunLedgers, queryFederatedInterruptedRunLedgers, queryFederatedUnfinishedRunLedgers }] = await Promise.all([
101
101
  import('../self-implement/goal-author.js'),
102
102
  import('../self-implement/run-ledger.js'),
103
103
  ]);
@@ -166,6 +166,8 @@ export async function buildAskPreflightDeps(options: BuildAskPreflightDepsOption
166
166
  // ⛔ ask 표지가 없으면 빈 배열 — 그때는 표시가 «안 붙는다»(지어내지 않는다).
167
167
  askTargetPaths: (document: string) => parseAskTargetPathHints(verbatimOriginalAsk(document) ?? ''),
168
168
  askTargetPathRejections: (document: string) => parseAskTargetPathHintsResult(verbatimOriginalAsk(document) ?? '').rejected,
169
+ // AUTO-TARGET: a NOT-GROUNDED goal (no persistent evidence) is a scope card — machine-suggested paths do not launch it.
170
+ notGroundedWithoutPersistentEvidence: isNotGroundedWithoutPersistentEvidence,
169
171
  // ⭐ 충돌 문면이 경로마다 「대상/근거」를 말하게 한다 — 판정은 «안» 바꾼다(문면만 는다).
170
172
  // ⛔ TRACED PATHS 는 「바꿀 파일」과 「근거로 읽은 파일」을 섞는다(실측: TRACED 8 · 변경 3).
171
173
  // ⇒ 사람이 막혔을 때 「그게 근거였네」를 «즉시» 알 수 있어야 한다.
@@ -300,6 +302,54 @@ export async function readAskPreflightLogRows(): Promise<AskLogRow[] | null> {
300
302
  } catch { return null; }
301
303
  }
302
304
 
305
+ /** Every `ask-preflight` row since `since`, all universes, paged past the 1000-row cap (OVERLAP-METRIC).
306
+ * ⛔ Unreadable ⇒ `null` — never an empty list that reads as «no overlap launches». */
307
+ export async function readAskPreflightRowsSince(since: Date): Promise<AskLogRow[] | null> {
308
+ return readLogRowsSince(since, 'dev-pipeline', 'ask-preflight');
309
+ }
310
+
311
+ /** Every DRAFT-NOT-ARCHIVE `salvaged` row since `since`, all universes (OVERLAP-METRIC salvage siblings).
312
+ * ⛔ Unreadable ⇒ `null` — a salvage branch we could not see is «unmeasured», not «none». */
313
+ export async function readSalvagedRowsSince(since: Date): Promise<AskLogRow[] | null> {
314
+ return readLogRowsSince(since, 'self-implement.draft-not-archive', 'salvaged');
315
+ }
316
+
317
+ async function readLogRowsSince(since: Date, category: string, event: string): Promise<AskLogRow[] | null> {
318
+ try {
319
+ const [{ resolveLogTargets }, { LogStore }] = await Promise.all([
320
+ import('../cli/logs-cli.js'),
321
+ import('../mss/logging/log-store.js'),
322
+ ]);
323
+ const { targets } = resolveLogTargets({ all: true, includeTest: true });
324
+ const rows: AskLogRow[] = [];
325
+ // ⛔ One store can be registered under two names (`~/.monad` → `~/.elanous` symlink) — read each real file once,
326
+ // or every prod row is counted twice (OVERLAP-METRIC 실측: 169 행 중 69 가 같은 prod 파일의 겹침).
327
+ const seen = new Set<string>();
328
+ for (const target of targets) {
329
+ let real = target.dbPath;
330
+ try { real = realpathSync(target.dbPath); } catch { /* missing store: LogStore below decides */ }
331
+ if (seen.has(real)) continue;
332
+ seen.add(real);
333
+ const store = new LogStore(target.dbPath, { readonly: true });
334
+ try {
335
+ let beforeId: number | undefined;
336
+ for (let page = 0; page < 100; page++) {
337
+ const batch = store.query({ exactCategories: [category], events: [event], sinceMs: since.getTime(),
338
+ limit: 1_000, ...(beforeId === undefined ? {} : { beforeId }) });
339
+ for (const row of batch) {
340
+ const parsed = typeof row.data === 'string' ? JSON.parse(row.data) : row.data;
341
+ rows.push({ ts: row.ts, data: (parsed ?? null) as Record<string, unknown> | null });
342
+ }
343
+ if (batch.length < 1_000) break;
344
+ if (page === 99) return null;
345
+ beforeId = batch.at(-1)!.id;
346
+ }
347
+ } finally { store.close?.(); }
348
+ }
349
+ return rows;
350
+ } catch { return null; }
351
+ }
352
+
303
353
  const stringList = (value: unknown): string[] =>
304
354
  Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];
305
355
 
@@ -14,6 +14,43 @@ export type AskPathCandidates =
14
14
  const STOP_WORDS = new Set(['the', 'and', 'test', 'src', 'scripts', 'file', 'path', 'paths', 'code', 'with', 'from', 'this', 'that', 'into', 'for', 'then', 'when', 'have', 'does', 'should', 'will', 'please', 'target', 'change']);
15
15
  const WORD = /[-/]?[A-Za-z][A-Za-z0-9_.-]*(?:\/[A-Za-z0-9_.-]+)*/g;
16
16
 
17
+ // ⛔ AUTO-TARGET (10-08 실측 · `ask-auto-target-candidates` Pod 로그): 한글 ask 에서 영문 낱말은 거의
18
+ // «포장»뿐이었다 — 디스패처 머리 `[UX · 0.2.20 칸 <ID> · TASK-AGENT(OP 디스패처)]` ⊕ Pod 샤드 꼬리
19
+ // `## Shard identity {"shardId","totalShards","position","summary","siblings"}` ⊕ `## Working-memory handoff`.
20
+ // 그 낱말들이 하니스 파일(orchestrate.ts · orchestrator.ts · self-implement-pod.ts · index.ts)을 끌어와
21
+ // 네 칸이 엉뚱한 골로 저작됐다. ⇒ 포장을 «증거»에서 걷고, 남는 것이 없으면 «후보 없음»(=근거 없음)을 낸다.
22
+ /** Machine-appended sections whose words describe the transport, not the request. */
23
+ const WRAPPER_SECTION_HEADINGS = new Set(['shard identity', 'working-memory handoff']);
24
+ /** Dispatcher wrapper lines that are identical for every card. */
25
+ const WRAPPER_LINE = /^\s*(?:보존 계약|판정)\s*:/;
26
+ /** Dispatcher header `[OWNER · <ver> 칸 <ID> · …]` — the title after it is kept. */
27
+ const WRAPPER_HEADER = /^\s*\[[^\]\n]*칸[^\]\n]*\]\s*/;
28
+ /** Dispatcher evidence label — the evidence itself is kept. */
29
+ const WRAPPER_LABEL = /^\s*칸 근거 끝\(남은 것\)\s*:\s*/;
30
+ /** Seat/role/surface words and similar labels that name the process, not the code. */
31
+ const GENERIC_TOKENS = new Set(['task-agent', 'op', 'mk', 'tc', 'ux', 'ceo', 'coo', 'cmo', 'cto', 'cxo', 'pr', 'prs', 'pod', 'tui', 'pwa', 'cli', 'hitl', 'p0', 'p1', 'p2']);
32
+
33
+ function isGenericToken(token: string): boolean {
34
+ const lower = token.toLowerCase().replace(/[.]+$/, '');
35
+ if (GENERIC_TOKENS.has(lower)) return true;
36
+ if (/^v?\d+(?:\.\d+)+(?:-[a-z0-9.]+)?$/i.test(lower)) return true; // version strings
37
+ if (/^[0-9a-f]{7,40}$/.test(lower) && /\d/.test(lower)) return true; // commit shas
38
+ return false;
39
+ }
40
+
41
+ /** Remove dispatcher/Pod wrapper text so only the request body counts as lexical evidence. */
42
+ export function stripAskWrapper(askText: string): string {
43
+ const kept: string[] = [];
44
+ let skipping = false;
45
+ for (const line of askText.split(/\r?\n/)) {
46
+ const heading = /^##\s+(.+?)\s*$/.exec(line);
47
+ if (heading) skipping = WRAPPER_SECTION_HEADINGS.has(heading[1]!.toLowerCase());
48
+ if (skipping || WRAPPER_LINE.test(line)) continue;
49
+ kept.push(line.replace(WRAPPER_HEADER, '').replace(WRAPPER_LABEL, ''));
50
+ }
51
+ return kept.join('\n');
52
+ }
53
+
17
54
  function existingFile(fragment: string, cwd: string): string | null {
18
55
  const path = fragment.replace(/^\.\//, '');
19
56
  if (!path.includes('/') && !/\.[A-Za-z][A-Za-z0-9]*$/.test(path)) return null;
@@ -29,7 +66,8 @@ export function findAskPathCandidates(askText: string, { cwd, run = execFileSync
29
66
  const scores = new Map<string, Set<string>>();
30
67
  const tokens: string[] = [];
31
68
  const seen = new Set<string>();
32
- const chunks = [...askText.matchAll(/`([^`]+)`/g)].map((match) => match[1]!).concat([askText]);
69
+ const body = stripAskWrapper(askText);
70
+ const chunks = [...body.matchAll(/`([^`]+)`/g)].map((match) => match[1]!).concat([body]);
33
71
  for (const chunk of chunks) {
34
72
  for (const match of chunk.matchAll(WORD)) {
35
73
  const raw = match[0];
@@ -40,7 +78,7 @@ export function findAskPathCandidates(askText: string, { cwd, run = execFileSync
40
78
  hits.add(token);
41
79
  scores.set(file, hits);
42
80
  }
43
- if (STOP_WORDS.has(token.toLowerCase()) || seen.has(token)) continue;
81
+ if (STOP_WORDS.has(token.toLowerCase()) || isGenericToken(token) || seen.has(token)) continue;
44
82
  if (!file && !token.includes('/') && !token.includes('.') && !token.includes('-') && !token.includes('_')
45
83
  && !/[a-z][A-Z]/.test(token) && token.length < 4) continue;
46
84
  seen.add(token);