elanous 0.2.36 → 0.2.37

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 (630) 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/{uC-N0emedeNOFuaBQFv-I → 8kITumG9GAZ1LwT9POrAR}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +62 -0
  8. package/apps/pwa/out/_next/static/chunks/{4286.b70c4520306817e8.js → 1262.a89bb27a5b2f844e.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{3410.7f9af5ab77cbe65f.js → 1746.3563617ea64023a3.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{9250-072df22eaadaa6b5.js → 2002-a43a3f380df873ec.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +32 -0
  19. package/apps/pwa/out/_next/static/chunks/{3727.7949ccaacaa71242.js → 2283.edd9627b7bdfb546.js} +2 -2
  20. package/apps/pwa/out/_next/static/chunks/2318-450e75d07605b8fe.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{4615.8525eb0add35eba6.js → 2375.bf364c85dbb6f085.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +148 -0
  25. package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +27 -0
  29. package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{5711.957b095705c12560.js → 3199.6a1a9b0e6cd01dc6.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{2986.45d7652e4f13557e.js → 3578.4e9f9948a9a6f2f4.js} +2 -2
  35. package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +36 -0
  37. package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +90 -0
  39. package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +226 -0
  40. package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +287 -0
  41. package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{7481.39f7a4654907bf6e.js → 4313.76f232c304a15bde.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4337e36d.f42c3b391b3d8f20.js +122 -0
  45. package/apps/pwa/out/_next/static/chunks/{6943.c6b24124853a47b2.js → 4383.18e5c54db3a22c88.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{3757-180308bc61021b05.js → 4725-34bed25720cc326b.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +24 -0
  52. package/apps/pwa/out/_next/static/chunks/{771.c3cdb6c1f7f47c02.js → 4931.95cc6dbd230774ca.js} +3 -3
  53. package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{552.b7d061ad91eeac51.js → 5046.7fd5cbd859299448.js} +2 -2
  56. package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +104 -0
  57. package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/{9f31e478.fefcbcd3c388ebc5.js → 58edce7d.f1b0c72acf13b123.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +93 -0
  65. package/apps/pwa/out/_next/static/chunks/{3136.30aaaa5fa03662a3.js → 5952.294fc574a8625184.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/{da5ecc5c-b005ad8cac737d57.js → 5f6af561-f90b7a67f4f75d13.js} +1 -1
  67. package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +74 -0
  68. package/apps/pwa/out/_next/static/chunks/{3324.a09703033abcbd2f.js → 6252.240578f10952e091.js} +1 -1
  69. package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{8904.7d51af2dc033965c.js → 6680.6a693c28aae4cd19.js} +2 -2
  71. package/apps/pwa/out/_next/static/chunks/{275-02ea4c2a33980422.js → 6745-5a63492933959dd9.js} +3 -3
  72. package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +149 -0
  74. package/apps/pwa/out/_next/static/chunks/{528.38ce20ef8aa251ff.js → 6819.be5c9c4d67f22922.js} +3 -3
  75. package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{3a3d9966.cc4d4585a2708e7c.js → 709a918c.4fd3b4e2a32cb4e3.js} +1 -1
  78. package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +41 -0
  80. package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +24 -0
  83. package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/{4304.e9b2512834a9e23e.js → 7424.c0fe2a595d4232b5.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{2683.c9773a0c589b031b.js → 7867.e8725745ddd1d940.js} +4 -4
  93. package/apps/pwa/out/_next/static/chunks/{6466-92e65a48490b68a9.js → 7893-e444a1b0809cd1e4.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{ccae1c4b-0cf414f5eff1b10d.js → 7c5ed21f-f286708e57cf88f7.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +8 -0
  98. package/apps/pwa/out/_next/static/chunks/{3840-5825d56d46976a92.js → 8080-40d781e7704d3671.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +77 -0
  100. package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +286 -0
  103. package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +79 -0
  107. package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{873d6c12.09bd499f57171543.js → 8c58d09b.e8724a299658d86f.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/{575.d929793a53f27c4b.js → 9151.a2c51e93f9156dae.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +94 -0
  117. package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{190.285c832bd9626f8c.js → 958.53a8dcf4729e6997.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/{page-e2de2e59111c9aad.js → page-3337c6a1328c2674.js} +1 -1
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/{page-f2b2e4bf6e981450.js → page-89acd5d68c0bc560.js} +1 -1
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-2af16e62c12f22df.js → page-fe986fe79b107546.js} +1 -1
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-1e5da297557d2354.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-88a1edbff62eaf1d.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-ac2c1e6169cfce57.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c1c80e345fa9d6f5.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/{053a429e.9a63436527cc751c.js → d9815f84.4918f682a45a8502.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/{ceba0382.650712b56b85b582.js → de8446d3.31b73eb239fecd7b.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +1 -0
  184. package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
  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 +23 -23
  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 +22 -22
  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 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  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/drafts/recipes.yaml +27 -7
  279. package/graphs/work/draft-close.yaml +54 -0
  280. package/graphs/work/green-close.yaml +37 -0
  281. package/graphs/work/recipes.yaml +46 -1
  282. package/graphs/work/run-research.yaml +35 -0
  283. package/package.json +1 -1
  284. package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
  285. package/scripts/boundary-proof-mapping-audit.ts +88 -0
  286. package/scripts/codex-fallback-live-probe.ts +17 -15
  287. package/scripts/fleet/node-setup.sh +32 -2
  288. package/scripts/fleet/run-light-worker.sh +9 -0
  289. package/scripts/gate-0226-failure-census.ts +507 -0
  290. package/scripts/goals/authoring-metrics.ts +258 -0
  291. package/scripts/graph-units/draft-close-node.ts +222 -0
  292. package/scripts/hook-order-sweep.ts +7 -4
  293. package/scripts/land-global-checks.ts +69 -1
  294. package/scripts/measure-nl-routing-corpus.ts +207 -2
  295. package/scripts/release-loop/docs-node.ts +140 -0
  296. package/scripts/release-loop/gate-closure.ts +48 -0
  297. package/scripts/release-loop/gate-diff.ts +2 -1
  298. package/scripts/release-loop/known-issues-node.ts +6 -4
  299. package/scripts/release-loop/notes-repair.ts +216 -0
  300. package/scripts/release-loop/prepare-node.ts +61 -5
  301. package/scripts/release-loop/resume-release.ts +114 -4
  302. package/scripts/release-loop/resume-test-traffic.ts +10 -0
  303. package/scripts/release-loop/version-node.ts +81 -12
  304. package/scripts/train/green-leg.ts +176 -0
  305. package/scripts/tui-continue-real-evidence.ts +47 -0
  306. package/scripts/ux-sim.ts +1 -1
  307. package/src/acp/client.ts +31 -5
  308. package/src/acp/core-turn-bridge.ts +6 -0
  309. package/src/acp/stderr-summary.ts +49 -0
  310. package/src/agent/monad-agent-turn.ts +1 -0
  311. package/src/agent/terminal-surface.ts +217 -0
  312. package/src/agent-substrate/pr-reviewer.ts +11 -3
  313. package/src/agent-substrate/self-review-cli.ts +343 -31
  314. package/src/autopilot/lineage/sources.ts +1 -1
  315. package/src/autopilot/pr-manager.ts +64 -13
  316. package/src/boot/daemon-runtime.ts +35 -3
  317. package/src/boot/daemon-tools/pty-shell.ts +2 -1
  318. package/src/budget/run-usage-rollup.ts +12 -7
  319. package/src/budget/unified-usage.ts +20 -0
  320. package/src/capture/tui-self-report.ts +32 -3
  321. package/src/cli/autopilot-cli.ts +24 -9
  322. package/src/cli/decisions-cli.ts +7 -4
  323. package/src/cli/doctor-cli.ts +116 -7
  324. package/src/cli/logs-cli.ts +357 -2
  325. package/src/cli/memory-cli.ts +30 -1
  326. package/src/cli/msg-cli.ts +15 -11
  327. package/src/cli/pr-granularity.ts +5 -3
  328. package/src/cli/release-checklist-read-cli.ts +109 -4
  329. package/src/cli/release-cli.ts +43 -10
  330. package/src/cli/self-update.ts +23 -5
  331. package/src/cli/self-utterances-cli.ts +13 -16
  332. package/src/cli/tasks-cli.ts +309 -11
  333. package/src/cli/usage-cli.ts +12 -10
  334. package/src/context-bus/claude-memory-import.ts +99 -0
  335. package/src/context-bus/long-term-memory.ts +125 -0
  336. package/src/core-turn/run-goal-loop.ts +5 -2
  337. package/src/core-turn/types.ts +2 -0
  338. package/src/dashboard/chat/acp-chat.ts +9 -0
  339. package/src/dashboard/index.ts +97 -13
  340. package/src/dashboard/input/agent-wake.ts +43 -0
  341. package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
  342. package/src/dashboard/replay-preview.ts +25 -0
  343. package/src/dashboard/slash-runtime/dashboard-handlers.ts +17 -8
  344. package/src/dashboard/synchronized-frame-output.ts +74 -0
  345. package/src/display/coordinator.ts +45 -12
  346. package/src/display/resize-listener.ts +41 -20
  347. package/src/display/synchronized-output-region.ts +60 -0
  348. package/src/domains/surface-events.ts +80 -1
  349. package/src/exec-requests/planner.ts +37 -2
  350. package/src/execution-loop/launch-gate.ts +4 -3
  351. package/src/git-fs/cli-stderr.ts +45 -0
  352. package/src/git-fs/gh-cli.ts +6 -3
  353. package/src/git-fs/git-cli.ts +11 -5
  354. package/src/graph-runner/graph-cli.ts +26 -2
  355. package/src/graph-runner/graph-run-api.ts +3 -2
  356. package/src/graph-runner/runner.ts +17 -5
  357. package/src/graph-wizard/generate.ts +29 -6
  358. package/src/harness/harness-cli-command.ts +179 -33
  359. package/src/harness/review-adapter.ts +26 -6
  360. package/src/index.ts +116 -13
  361. package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
  362. package/src/llm/route-decision.ts +13 -0
  363. package/src/llm-tool-name.ts +37 -0
  364. package/src/llm-tool-schema.ts +35 -0
  365. package/src/llm.ts +123 -11
  366. package/src/loops/checker.ts +100 -0
  367. package/src/loops/consensus.ts +26 -2
  368. package/src/loops/loop-cli.ts +9 -4
  369. package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
  370. package/src/loops/orchestrator/tick.ts +49 -4
  371. package/src/model-tier/llm-tier-map.ts +12 -17
  372. package/src/msg/msg-store.ts +17 -0
  373. package/src/native-tool-catalog.ts +1 -1
  374. package/src/nexus/api/graph-wizard-api.ts +27 -2
  375. package/src/nexus/api/grid.ts +24 -4
  376. package/src/nexus/api/http-server.ts +1 -1
  377. package/src/nexus/api/ops-api.ts +14 -6
  378. package/src/nexus/state/state.ts +7 -1
  379. package/src/oauth/codex-account-store.ts +34 -1
  380. package/src/ops/loops-map.ts +46 -0
  381. package/src/ops/overview-cache.ts +22 -4
  382. package/src/ops/overview.ts +41 -5
  383. package/src/policy/llm-policy.ts +3 -1
  384. package/src/prompt-enhance/enhance.ts +4 -4
  385. package/src/pty-shell/availability.ts +7 -0
  386. package/src/pty-shell/herdr-agent-report.ts +40 -31
  387. package/src/pty-shell/herdr-prune-stale.ts +17 -0
  388. package/src/pty-shell/herdr-sequence-lease.ts +60 -0
  389. package/src/pty-shell/pty-control-ipc.ts +187 -18
  390. package/src/pty-shell/registry.ts +25 -15
  391. package/src/pty-shell/tui-run-state.ts +235 -1
  392. package/src/release-loop/checklist.ts +50 -5
  393. package/src/release-loop/feature-store.ts +9 -9
  394. package/src/release-loop/landed-but-yellow.ts +93 -12
  395. package/src/repl/index.ts +8 -0
  396. package/src/seat-loop/seat-report.ts +1 -0
  397. package/src/self-dev/ask-launch-flow.ts +86 -10
  398. package/src/self-dev/decompose-proposal.ts +29 -18
  399. package/src/self-dev/dev-pipeline.ts +29 -7
  400. package/src/self-dev/draft-sweep.ts +241 -16
  401. package/src/self-dev/draft-triage-rules.ts +19 -5
  402. package/src/self-dev/review-provider-fallback.ts +45 -7
  403. package/src/self-dev/shard-plan.ts +48 -0
  404. package/src/self-dev/shard-run.ts +50 -3
  405. package/src/self-implement/doctor-visit.ts +83 -0
  406. package/src/self-implement/gate-artifacts.ts +6 -2
  407. package/src/self-implement/gate-baseline.ts +64 -1
  408. package/src/self-implement/gate-cli.ts +93 -9
  409. package/src/self-implement/gate-remote.ts +28 -4
  410. package/src/self-implement/gate-scope.ts +13 -1
  411. package/src/self-implement/goal-author.ts +333 -18
  412. package/src/self-implement/goal-supervisor-fill.ts +75 -26
  413. package/src/self-implement/importer-test-index.ts +215 -2
  414. package/src/self-implement/knowhow-pack.ts +5 -5
  415. package/src/self-implement/orchestrator.ts +318 -25
  416. package/src/self-implement/review-round-brief.ts +300 -0
  417. package/src/self-implement/rework-policy.ts +14 -0
  418. package/src/self-implement/run-ledger.ts +170 -6
  419. package/src/self-implement/run-stop.ts +1 -1
  420. package/src/self-implement/running-runs.ts +17 -3
  421. package/src/self-implement/seams.ts +12 -6
  422. package/src/self-implement/stop-autoheal.ts +1 -0
  423. package/src/self-implement/test-seams.ts +13 -1
  424. package/src/self-implement/train-reach-grouping.ts +8 -2
  425. package/src/session/chat.ts +7 -1
  426. package/src/session/id-prefix.ts +60 -0
  427. package/src/session/index.ts +4 -0
  428. package/src/session-runtime/index.ts +9 -1
  429. package/src/skills/tools/pty.ts +5 -0
  430. package/src/status/metrics.ts +12 -1
  431. package/src/steward/rejudge-tick.ts +12 -5
  432. package/src/steward/resync-tick.ts +31 -4
  433. package/src/task-agent/actions.ts +199 -4
  434. package/src/task-agent/boundary-proof-mapping.ts +12 -0
  435. package/src/task-agent/boundary-proof-producer.ts +147 -0
  436. package/src/task-agent/completion-evidence.ts +2 -1
  437. package/src/task-agent/green-close-recipe.ts +239 -0
  438. package/src/task-agent/green-sweep.ts +64 -10
  439. package/src/task-agent/live-moves.ts +48 -3
  440. package/src/task-agent/map-host-adapter.ts +134 -0
  441. package/src/task-agent/map-reduce.ts +158 -0
  442. package/src/task-agent/map-run-ledger.ts +226 -0
  443. package/src/task-agent/parent-host.ts +21 -11
  444. package/src/task-agent/rejudge-on-head.ts +72 -5
  445. package/src/task-agent/repair-cycle.ts +41 -0
  446. package/src/task-agent/repair-next-move.ts +12 -2
  447. package/src/task-agent/review-prior-fix.ts +12 -2
  448. package/src/task-agent/shadow.ts +188 -5
  449. package/src/task-agent/task-hand.ts +158 -13
  450. package/src/task-agent/task-parent-role-llm.ts +9 -0
  451. package/src/task-agent/tier-split.ts +4 -3
  452. package/src/task-agent/work-order.ts +53 -2
  453. package/src/task-orchestrator/dispatcher.ts +46 -1
  454. package/src/task-orchestrator/generator-prompt.ts +6 -0
  455. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
  456. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
  457. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
  458. package/src/task-orchestrator/surfaces/pod-pool.ts +50 -4
  459. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +15 -9
  460. package/src/task-orchestrator/surfaces/self-implement-pod.ts +217 -36
  461. package/src/task-orchestrator/surfaces/self-implement.ts +4 -0
  462. package/src/testing/linux-env.ts +177 -0
  463. package/src/tui/chat/goal-interim.ts +5 -1
  464. package/src/tui/entry.ts +258 -4
  465. package/src/tui/input/at-picker.ts +55 -0
  466. package/src/tui/slash/resume.ts +35 -12
  467. package/src/tui/slash/signals.ts +114 -0
  468. package/src/tui/slash/term-next.ts +71 -0
  469. package/src/tui-client/local-chat-turn.ts +4 -3
  470. package/src/user-config.ts +19 -1
  471. package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
  472. package/src/ux-sim/classic-tui-seat-scenarios.ts +158 -4
  473. package/src/ux-sim/fake-gh.ts +174 -0
  474. package/src/ux-sim/fake-kubectl.ts +142 -0
  475. package/src/ux-sim/fake-llm.ts +6 -1
  476. package/src/ux-sim/next-tui-seat-scenarios.ts +124 -6
  477. package/src/ux-sim/resume-picker-device.ts +173 -0
  478. package/src/ux-sim/session-id-seed.ts +60 -0
  479. package/src/ux-sim/skills-tools-shell-device.ts +156 -0
  480. package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
  481. package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
  482. package/src/version/packed-revision.json +1 -1
  483. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +0 -287
  484. package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +0 -36
  490. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +0 -149
  493. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +0 -24
  498. package/apps/pwa/out/_next/static/chunks/2812ca6a.3b9f4a7a08885744.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +0 -24
  502. package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/3148-98efd4869d660a87.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +0 -226
  505. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +0 -8
  509. package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +0 -32
  510. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +0 -286
  512. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +0 -74
  515. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +0 -104
  519. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +0 -148
  522. package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +0 -93
  524. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +0 -122
  526. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/599.c39c571b6733f2a2.js +0 -41
  531. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +0 -79
  532. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +0 -27
  544. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/6925.562d532110879886.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/7891.03f910124a737985.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +0 -62
  557. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +0 -90
  559. package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +0 -94
  560. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +0 -77
  565. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/9514.131c52cc75fe6439.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +0 -1
  630. /package/apps/pwa/out/_next/static/{uC-N0emedeNOFuaBQFv-I → 8kITumG9GAZ1LwT9POrAR}/_ssgManifest.js +0 -0
@@ -33,6 +33,9 @@ export interface CheckEntry {
33
33
  expectedVersion?: string;
34
34
  /** Registry graph path, supplied only by graph inventory. */
35
35
  file?: string;
36
+ /** LOOP-PRUNE-1021-FU 판정 재료 — cron-shell·미등록 행이 실은 crontab 명세(그래프 루프에는 없다). */
37
+ cron?: string;
38
+ command?: string;
36
39
  enabled: boolean;
37
40
  registered: boolean;
38
41
  }
@@ -317,3 +320,100 @@ export function observeLoopCheck(results: CheckResult[], scope: LoopScope, deps:
317
320
  catch (error) { if (existsSync(tmp)) unlinkSync(tmp); throw error; }
318
321
  return counts;
319
322
  }
323
+
324
+ // ── LOOP-PRUNE-1021-FU 정리 판정 (내부 문서 `loop-lineage-1021` · 0.2.36) ─────
325
+ /** 무실행 은퇴 한계 — off 상태가 원장으로 최근 14일 실행이 증명될 때만 은퇴 후보가 된다. */
326
+ export const PRUNE_IDLE_DAYS = 14;
327
+ /** 활성 루프 상한 — alive 가 25 를 넘으면 접기·은퇴 판정을 먼저 치른다. */
328
+ export const PRUNE_ALIVE_LIMIT = 25;
329
+
330
+ export interface PruneFoldGroup { family: string; ids: string[]; }
331
+ export interface PruneUnregisteredRow { id: string; cron?: string; command?: string; }
332
+ export interface PruneJudgment {
333
+ /** 14일 무실행이 원장으로 증명된 은퇴 후보(off). */
334
+ idleRetire: string[];
335
+ /** 실행 기록이 없어 무실행을 증명할 수 없는 항목 — 은퇴 후보에서 제외한다. */
336
+ idleUnproven: string[];
337
+ /** 등록되지 않은 elanous 크론 행 — 등록/제거 판정에 넘긴다. */
338
+ unregistered: PruneUnregisteredRow[];
339
+ /** 같은 일을 하는 elanous:* 형제 슬롯 가족 — 그래프 루프·원장 해시는 접지 않는다. */
340
+ foldGroups: PruneFoldGroup[];
341
+ /** 활성 루프 수와 25 한도 판정. */
342
+ alive: { count: number; limit: number; within: boolean };
343
+ /** 운영 이름이 없는 원장 해시 id — 명명 대상. */
344
+ unnamed: string[];
345
+ }
346
+
347
+ /** elanous:* 슬롯의 가족 이름 — namedCronIds 의 -N 접미와 자리 슬롯(:SEAT)을 원래 가족으로 되돌린다. */
348
+ function pruneFoldFamily(id: string): string | undefined {
349
+ if (!id.startsWith('elanous:')) return undefined;
350
+ const seat = /^elanous:([^:]+):[^:]+$/.exec(id);
351
+ if (seat) return `elanous:${seat[1]}`;
352
+ const sibling = /^elanous:(.+)-\d+$/.exec(id);
353
+ return `elanous:${sibling ? sibling[1] : id.slice('elanous:'.length)}`;
354
+ }
355
+
356
+ /** LOOP-PRUNE-1021-FU — CheckResult 원장 위에서 무실행 은퇴·미등록 정리·형제 접기·alive ≤ 25·이름 없는 해시를 판정한다. */
357
+ export function pruneJudgment(results: readonly CheckResult[], opts: { now?: Date } = {}): PruneJudgment {
358
+ const now = opts.now ?? new Date();
359
+ const idleMs = PRUNE_IDLE_DAYS * 24 * 60 * 60_000;
360
+ const idleRetire: string[] = [];
361
+ const idleUnproven: string[] = [];
362
+ const unregistered: PruneUnregisteredRow[] = [];
363
+ const unnamed: string[] = [];
364
+ const families = new Map<string, string[]>();
365
+ let aliveCount = 0;
366
+ for (const result of results) {
367
+ if (result.state === 'alive') aliveCount++;
368
+ if (result.state === 'unregistered') {
369
+ unregistered.push({
370
+ id: result.id,
371
+ ...(result.cron ? { cron: result.cron } : {}),
372
+ ...(result.command ? { command: result.command } : {}),
373
+ });
374
+ }
375
+ if (result.state === 'off') {
376
+ const ran = result.lastRunAt && Number.isFinite(Date.parse(result.lastRunAt)) ? Date.parse(result.lastRunAt) : undefined;
377
+ if (ran === undefined) idleUnproven.push(result.id);
378
+ else if (now.getTime() - ran > idleMs) idleRetire.push(result.id);
379
+ }
380
+ if (/^[0-9a-f]{8,}$/.test(result.id)) unnamed.push(result.id);
381
+ const family = pruneFoldFamily(result.id);
382
+ if (family) {
383
+ const group = families.get(family) ?? [];
384
+ group.push(result.id);
385
+ families.set(family, group);
386
+ }
387
+ }
388
+ const foldGroups: PruneFoldGroup[] = [];
389
+ for (const [family, ids] of families) {
390
+ if (ids.length < 2) continue;
391
+ foldGroups.push({ family, ids: [...ids].sort() });
392
+ }
393
+ const judgment: PruneJudgment = {
394
+ idleRetire,
395
+ idleUnproven,
396
+ unregistered,
397
+ foldGroups,
398
+ alive: { count: aliveCount, limit: PRUNE_ALIVE_LIMIT, within: aliveCount <= PRUNE_ALIVE_LIMIT },
399
+ unnamed,
400
+ };
401
+ debug.log('loop.checker', 'prune', {
402
+ idleRetire: idleRetire.length, idleUnproven: idleUnproven.length, unregistered: unregistered.length,
403
+ folds: foldGroups.length, alive: aliveCount, unnamed: unnamed.length,
404
+ });
405
+ return judgment;
406
+ }
407
+
408
+ /** LOOP-PRUNE-1021-FU — PruneJudgment 을 사람용 정리 판정 줄로 렌더한다(loop status --all 인간 출력 꼬리). */
409
+ export function pruneText(judgment: PruneJudgment): string {
410
+ const lines = [
411
+ `무실행 은퇴 ${judgment.idleRetire.length}: ${judgment.idleRetire.join(', ') || '없음'}`,
412
+ `무실행 미증명 ${judgment.idleUnproven.length}: ${judgment.idleUnproven.join(', ') || '없음'}`,
413
+ `미등록 ${judgment.unregistered.length}: ${judgment.unregistered.map(row => row.command ? `${row.id} (${row.command})` : row.id).join(', ') || '없음'}`,
414
+ `형제 접기 ${judgment.foldGroups.length}: ${judgment.foldGroups.map(group => `${group.family}[${group.ids.join('+')}]`).join(', ') || '없음'}`,
415
+ `alive ${judgment.alive.count}/${judgment.alive.limit} ${judgment.alive.within ? '한도 이내' : '한도 초과'}`,
416
+ `이름 없는 해시 ${judgment.unnamed.length}: ${judgment.unnamed.join(', ') || '없음'}`,
417
+ ];
418
+ return lines.join('\n');
419
+ }
@@ -45,6 +45,8 @@ export const CROWN_MARK = String.fromCodePoint(0x1F451);
45
45
  export interface ProposalCard {
46
46
  id: string;
47
47
  category: ConsensusCategory;
48
+ /** Stable orchestrator work key (orch:<card>:<cell>) for a cross-branch split cell. */
49
+ workKey?: string;
48
50
  title: string;
49
51
  /** 사실 id — 제안의 근거 관측. */
50
52
  factId: string;
@@ -152,8 +154,14 @@ export class ConsensusEngine {
152
154
 
153
155
  propose(input: {
154
156
  by: ConsensusRepresentative; category: ConsensusCategory; title: string; factId: string; cost: string; undo: string;
155
- thresholds?: DecisionCategory[]; provider?: string;
157
+ thresholds?: DecisionCategory[]; provider?: string; workKey?: string;
156
158
  }): ProposalCard {
159
+ if (input.workKey !== undefined) {
160
+ if (input.category !== 'cross-branch-change' || !/^orch:[a-zA-Z0-9_-]+:[a-zA-Z0-9_-]+$/.test(input.workKey))
161
+ throw new Error('invalid cross-branch work key');
162
+ const existing = this.list().find(proposal => proposal.workKey === input.workKey);
163
+ if (existing) throw new Error(`cross-branch work already proposed: ${existing.id}`);
164
+ }
157
165
  if (!CONSENSUS_REPRESENTATIVES.includes(input.by)) throw new Error(`invalid representative: ${input.by} (coordinator|guardian)`);
158
166
  if (!CONSENSUS_CATEGORIES.includes(input.category)) throw new Error(`invalid consensus category: ${input.category} (${CONSENSUS_CATEGORIES.join('|')})`);
159
167
  const thresholds = [...new Set(input.thresholds ?? [])];
@@ -164,6 +172,7 @@ export class ConsensusEngine {
164
172
  const proposal: ProposalCard = {
165
173
  id: this.nextId('C', at),
166
174
  category: input.category,
175
+ ...(input.workKey ? { workKey: input.workKey } : {}),
167
176
  title: oneLine(input.title, 'title'),
168
177
  factId: oneLine(input.factId, 'fact id'),
169
178
  cost: oneLine(input.cost, 'cost'),
@@ -210,11 +219,24 @@ export class ConsensusEngine {
210
219
  return proposal;
211
220
  }
212
221
 
222
+ proposalForWork(workKey: string): ProposalCard | undefined {
223
+ return this.list().find(entry => entry.workKey === workKey);
224
+ }
225
+
213
226
  crownCards(): CrownCard[] {
214
227
  return [...this.state().cards]
215
228
  .sort((a, b) => b.raisedAt.localeCompare(a.raisedAt) || a.id.localeCompare(b.id));
216
229
  }
217
230
 
231
+ /** The same durable execution gate is used by CLI replies, hooks and loop consumers. */
232
+ canExecute(id: string): boolean {
233
+ const proposal = this.show(id);
234
+ return proposal.status === 'agreed' && proposal.thresholds.length === 0
235
+ && proposal.roundTrips >= 1 && proposal.roundTrips <= MAX_REVIEW_ROUND_TRIPS
236
+ && proposal.reviews.at(-1)?.verdict === 'agree'
237
+ && proposal.reviews.at(-1)?.by !== proposal.proposedBy;
238
+ }
239
+
218
240
  /** 판정선 — 합의 원장의 agreed 이벤트를 ISO 주 단위로 센다 (한 주 N건의 기전). */
219
241
  weeklyAgreementCounts(): Array<{ week: string; count: number }> {
220
242
  const counts = new Map<string, number>();
@@ -230,7 +252,9 @@ export class ConsensusEngine {
230
252
  private conclude(id: string, verdict: ReviewRecord['verdict'], input: { by: ConsensusRepresentative; claim?: string; provider?: string }): { proposal: ProposalCard; crownCard?: CrownCard } {
231
253
  const proposal = this.show(id);
232
254
  if (proposal.status !== 'open') throw new Error(`합의가 이미 결론났다: ${id} (${proposal.status === 'agreed' ? '합의' : '불합의'})`);
255
+ if (!CONSENSUS_REPRESENTATIVES.includes(input.by)) throw new Error(`invalid representative: ${input.by}`);
233
256
  if (input.by === proposal.proposedBy) throw new Error('메아리 방지 — 제안한 대표는 자기 제안을 검토하지 않는다');
257
+ if (proposal.roundTrips >= MAX_REVIEW_ROUND_TRIPS) throw new Error(`상대 검토는 최대 ${MAX_REVIEW_ROUND_TRIPS}왕복이다`);
234
258
  if (verdict === 'revise' && proposal.roundTrips + 1 >= MAX_REVIEW_ROUND_TRIPS)
235
259
  throw new Error(`상대 검토는 최대 ${MAX_REVIEW_ROUND_TRIPS}왕복이다 — 마지막 왕복에는 합의 또는 불합의로 끝낸다`);
236
260
  const claim = oneLine(input.claim ?? (verdict === 'agree' ? '동의 — 제안대로 실행한다' : ''), 'claim');
@@ -249,7 +273,7 @@ export class ConsensusEngine {
249
273
  this.appendLens(input.by, { action: 'reviewed', proposalId: proposal.id, at, verdict, ...(provider ? { provider } : {}) });
250
274
  debug.log('loops.consensus', 'reviewed', { proposalId: proposal.id, verdict, roundTrip: review.roundTrip, by: input.by });
251
275
  const updated = this.show(proposal.id);
252
- if (verdict === 'agree') this.executeHook(updated);
276
+ if (this.canExecute(updated.id)) this.executeHook(updated);
253
277
  return { proposal: updated, ...(crownCard ? { crownCard } : {}) };
254
278
  }
255
279
 
@@ -1,7 +1,7 @@
1
1
  import type { Command } from 'commander';
2
2
  import { writeStdoutJson } from '../cli/stdout-json.js';
3
3
  import { listAllLoops, listLoops, loopStatus, runLoop, setLoopEnabled, unregisteredCronLoops, type AllLoopEntry, type LoopRegistryOptions } from './registry.js';
4
- import { checkLoops, countLoopStates, entriesFromRegistry, LOOP_STATES, notifyOwners, observeLoopCheck, type RegistryAdapterDeps } from './checker.js';
4
+ import { checkLoops, countLoopStates, entriesFromRegistry, LOOP_STATES, notifyOwners, observeLoopCheck, pruneJudgment, pruneText, type RegistryAdapterDeps } from './checker.js';
5
5
  import { effectiveInstanceRoot } from '../instance/resolve.js';
6
6
  import { verifyLoopPackage } from './package/verify.js';
7
7
  import { loopActivity } from './activity.js';
@@ -56,7 +56,8 @@ export function registerLoopCommands(program: Command, checkerDeps: RegistryAdap
56
56
  }));
57
57
  loop.command('status [id]').option('--all', 'Check all registered loops')
58
58
  .option('--json', 'Print JSON').option('--notify', 'Queue late/failing loops for their owners')
59
- .action((id: string | undefined, opts: { all?: boolean; json?: boolean; notify?: boolean }) => handle(async () => {
59
+ .option('--prune', 'Judge idle retire · unregistered cleanup · sibling folding · alive ≤ 25')
60
+ .action((id: string | undefined, opts: { all?: boolean; json?: boolean; notify?: boolean; prune?: boolean }) => handle(async () => {
60
61
  if (!opts.all) {
61
62
  if (!id) throw new Error('loop status requires an id or --all');
62
63
  await output(loopStatus(id), !!opts.json);
@@ -65,15 +66,19 @@ export function registerLoopCommands(program: Command, checkerDeps: RegistryAdap
65
66
  if (id) throw new Error('loop status --all does not take an id');
66
67
  const now = checkerDeps.now ?? new Date();
67
68
  const root = checkerDeps.root ?? effectiveInstanceRoot();
68
- const { entries, scope } = entriesFromRegistry({ ...checkerDeps, now });
69
+ const registryOpts = checkerDeps.registryOptions;
70
+ const { entries, scope } = entriesFromRegistry({ ...checkerDeps, now,
71
+ listAllLoops: checkerDeps.listAllLoops ?? (registryOpts ? () => listAllLoops(registryOpts) : undefined) });
69
72
  const results = checkLoops(entries, now);
70
73
  const counts = countLoopStates(results);
74
+ const prune = pruneJudgment(results, { now });
71
75
  observeLoopCheck(results, scope, { root, now });
72
76
  if (opts.notify) notifyOwners(results, { root, now });
73
- if (opts.json) { await output({ results, counts, scope }, true); return; }
77
+ if (opts.json) { await output({ results, counts, scope, prune }, true); return; }
74
78
  console.log('id\tstate\tlast run\texpected interval\towner\treason');
75
79
  for (const result of results) console.log(`${result.id}\t${result.state}\t${result.lastRunAt ?? '—'}\t${result.expectEveryMinutes === undefined ? '—' : `${result.expectEveryMinutes}m`}\t${result.owner ?? '—'}\t${result.reason}`);
76
80
  console.log(`${LOOP_STATES.map(state => `${state} ${counts[state]}`).join(' · ')} · scope ${scope}`);
81
+ if (opts.prune) console.log(pruneText(prune));
77
82
  }));
78
83
  for (const [name, enabled] of [['start', true], ['stop', false]] as const) {
79
84
  loop.command(`${name} <id>`).option('--yes', 'Apply the crontab change (otherwise preview only)')
@@ -0,0 +1,243 @@
1
+ /**
2
+ * ANOMALY-CLUSTER-PRODUCT — repeated failure signatures hold relaunches.
3
+ *
4
+ * Reference contract (read-only, unchanged): `seat-state/OP/tools/anomaly-cluster.{sh,py}` groups the same
5
+ * failures for an OP seat by eye and never holds anything automatically. This module is the product
6
+ * transfer of that reading contract: it computes a signature and turns it into a hold/release decision.
7
+ *
8
+ * Boundary: when the SAME signature shows up in 3+ DIFFERENT runs, relaunches of that goal·host are held
9
+ * automatically until a cause verdict (`release`) clears them. The host is a hold key, never part of the
10
+ * signature. When there is nothing measured for a goal·host, the hold reason says so ("원천 미측정").
11
+ *
12
+ * Pure module: no fs, no network, no clock reads unless a `now` seam is injected.
13
+ */
14
+
15
+ /** Runs of the same signature required before relaunches are held. */
16
+ export const ANOMALY_HOLD_THRESHOLD = 3;
17
+
18
+ /** Signature components: failure kind · container exit · stage · tail of `lastLines` reason. */
19
+ export interface FailureObservation {
20
+ /** Goal identifier — a hold key, not part of the signature. */
21
+ goal: string;
22
+ /** Host (seat / surface / launch host) — a hold key, not part of the signature. */
23
+ host: string;
24
+ /** Run identifier — the unit counted as "a different run". */
25
+ runId: string;
26
+ /** Failure kind (`preflight` · `exit` · `timeout` · adapter name …). */
27
+ kind: string;
28
+ /** Container exit code when observed; `null`/absent when the failure never reached a container. */
29
+ containerExit?: number | null;
30
+ /** Stage the failure was observed at (`launch` · `delegate` · `monitor` …). */
31
+ stage: string;
32
+ /** Tail lines of the failure; the last non-empty line is the "reason tail" that splits signatures. */
33
+ lastLines?: readonly string[];
34
+ at?: string;
35
+ }
36
+
37
+ export interface HoldDecision {
38
+ /** `true` when relaunches of this goal·host are held. */
39
+ hold: boolean;
40
+ /** Korean explanation — includes "원천 미측정" when nothing was measured. */
41
+ reason: string;
42
+ signature?: string;
43
+ /** Distinct runs counted for the holding signature. */
44
+ runs?: number;
45
+ }
46
+
47
+ export interface ReleaseDecision {
48
+ released: boolean;
49
+ reason: string;
50
+ }
51
+
52
+ const REASON_TAIL_LIMIT = 160;
53
+
54
+ /** Collapse whitespace and cap length — the reason tail is a signature component, not a payload. */
55
+ function reasonTail(lines: readonly string[] | undefined): string {
56
+ if (!lines || lines.length === 0) return 'none';
57
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
58
+ const line = (lines[i] ?? '').replace(/\s+/g, ' ').trim().replace(/^reason\s*[:=]\s*/i, '');
59
+ if (line) return line.slice(0, REASON_TAIL_LIMIT);
60
+ }
61
+ return 'none';
62
+ }
63
+
64
+ /** Pull a container exit code out of free text (`exited with code 137`, `exit status 1`, `exit=137`). */
65
+ export function extractContainerExit(text: string): number | null {
66
+ const match = /(?:exit(?:ed)?(?: with)?(?: code| status)?|exit=)\s*[:=]?\s*(\d+)/i.exec(text ?? '');
67
+ if (!match) return null;
68
+ const value = Number.parseInt(match[1]!, 10);
69
+ return Number.isFinite(value) ? value : null;
70
+ }
71
+
72
+ /**
73
+ * Signature = kind · exit · stage · reason tail. Host and run are deliberately excluded: the host is a
74
+ * hold key and the run is the counter.
75
+ */
76
+ export function failureSignature(obs: FailureObservation): string {
77
+ const exit = obs.containerExit === undefined || obs.containerExit === null ? 'none' : String(obs.containerExit);
78
+ return `kind=${obs.kind}|exit=${exit}|stage=${obs.stage}|reason=${reasonTail(obs.lastLines)}`;
79
+ }
80
+
81
+ interface ClusterState {
82
+ goal: string;
83
+ host: string;
84
+ signature: string;
85
+ runs: Set<string>;
86
+ held: boolean;
87
+ /** First `FailureObservation.at` read into this cluster — the observation window shown in the reason. */
88
+ firstAt?: string;
89
+ /** Latest `FailureObservation.at` read into this cluster. */
90
+ lastAt?: string;
91
+ }
92
+
93
+ function keyOf(goal: string, host: string): string {
94
+ return `${goal}\u0000${host}`;
95
+ }
96
+
97
+ /** In-memory grouping state — written by the failure observation point, read by the relaunch point. */
98
+ export class AnomalyCluster {
99
+ private readonly threshold: number;
100
+ private readonly now: () => Date;
101
+ private readonly clusters = new Map<string, ClusterState>();
102
+ /**
103
+ * Observations of a DIFFERENT signature that arrived while its goal·host was held. They are kept
104
+ * counting in a side bucket so a late-arriving observation can never drop a hold before a cause
105
+ * verdict — the hold is only ever cleared by `release`.
106
+ */
107
+ private readonly parked = new Map<string, ClusterState>();
108
+
109
+ constructor(opts: { threshold?: number; now?: () => Date } = {}) {
110
+ this.threshold = Math.max(1, Math.trunc(opts.threshold ?? ANOMALY_HOLD_THRESHOLD));
111
+ this.now = opts.now ?? (() => new Date());
112
+ }
113
+
114
+ /** Record one failure observation and return the resulting hold decision for its goal·host. */
115
+ record(obs: FailureObservation): { signature: string; runs: number; hold: HoldDecision } {
116
+ const signature = failureSignature(obs);
117
+ const key = keyOf(obs.goal, obs.host);
118
+ const at = typeof obs.at === 'string' && obs.at.trim() ? obs.at.trim() : undefined;
119
+ let cluster = this.clusters.get(key);
120
+ if (cluster && cluster.signature !== signature && cluster.held) {
121
+ // Held: the signature is frozen until a cause verdict. A late observation of another signature is
122
+ // counted in the parked bucket — replacing the cluster here would silently drop the hold.
123
+ const parkedKey = keyOf(key, signature);
124
+ let parked = this.parked.get(parkedKey);
125
+ if (!parked) {
126
+ parked = { goal: obs.goal, host: obs.host, signature, runs: new Set(), held: false };
127
+ this.parked.set(parkedKey, parked);
128
+ }
129
+ this.touch(parked, obs.runId, at);
130
+ const held = this.describe(cluster);
131
+ return {
132
+ signature: cluster.signature,
133
+ runs: cluster.runs.size,
134
+ hold: {
135
+ ...held,
136
+ reason: `${held.reason} · 보류 중 도착한 다른 서명 ${parked.runs.size}건은 해제 없이 별도 보관(판정 뒤 재판정)`,
137
+ },
138
+ };
139
+ }
140
+ if (!cluster || cluster.signature !== signature) {
141
+ // Not held: a different signature takes over. A parked bucket of that same signature keeps its runs.
142
+ const parkedKey = keyOf(key, signature);
143
+ const resumed = this.parked.get(parkedKey);
144
+ for (const stale of [...this.parked.keys()]) {
145
+ if (stale !== parkedKey && stale.startsWith(`${key}\u0000`)) this.parked.delete(stale);
146
+ }
147
+ if (resumed) this.parked.delete(parkedKey);
148
+ cluster = resumed ?? { goal: obs.goal, host: obs.host, signature, runs: new Set(), held: false };
149
+ this.clusters.set(key, cluster);
150
+ }
151
+ this.touch(cluster, obs.runId, at);
152
+ return { signature, runs: cluster.runs.size, hold: this.describe(cluster) };
153
+ }
154
+
155
+ /** Relaunch gate. A hold is decided before any cause verdict; the reason names an unmeasured source. */
156
+ hold(goal: string, host: string): HoldDecision {
157
+ const cluster = this.clusters.get(keyOf(goal, host));
158
+ if (!cluster) {
159
+ return { hold: false, reason: `원천 미측정: ${goal}·${host} 의 실패 관측이 없다 — 보류 판정 근거 없음` };
160
+ }
161
+ return this.describe(cluster);
162
+ }
163
+
164
+ isHeld(goal: string, host: string): boolean {
165
+ return this.clusters.get(keyOf(goal, host))?.held ?? false;
166
+ }
167
+
168
+ /** Cause verdict — clears the hold. Returns `released: false` when nothing was held. */
169
+ release(goal: string, host: string, cause: string): ReleaseDecision {
170
+ const key = keyOf(goal, host);
171
+ const cluster = this.clusters.get(key);
172
+ if (!cluster || !cluster.held) {
173
+ return { released: false, reason: `${goal}·${host} 는 보류 상태가 아니다` };
174
+ }
175
+ const judged = cluster.signature;
176
+ const judgedRuns = cluster.runs.size;
177
+ cluster.held = false;
178
+ cluster.runs.clear();
179
+ cluster.firstAt = undefined;
180
+ cluster.lastAt = undefined;
181
+ const promoted = this.takeStrongestParked(key);
182
+ if (promoted) this.clusters.set(key, promoted);
183
+ const head = `보류 해제: ${cause} (${this.now().toISOString()}) — 판정한 서명 ${judged} ${judgedRuns}건`;
184
+ return {
185
+ released: true,
186
+ reason: promoted
187
+ ? `${head} · 보류 중 보관한 다른 서명 ${promoted.signature} ${promoted.runs.size}건을 재판정 대상으로 승격${promoted.held ? ' (임계 도달 — 새 서명 기준 재보류)' : ''}`
188
+ : head,
189
+ };
190
+ }
191
+
192
+ private touch(cluster: ClusterState, runId: string, at: string | undefined): void {
193
+ cluster.runs.add(runId);
194
+ if (at) {
195
+ cluster.firstAt ??= at;
196
+ cluster.lastAt = at;
197
+ }
198
+ if (cluster.runs.size >= this.threshold) cluster.held = true;
199
+ }
200
+
201
+ /** The parked bucket of this goal·host with the most runs — the next signature to judge. */
202
+ private takeStrongestParked(key: string): ClusterState | undefined {
203
+ let best: ClusterState | undefined;
204
+ let bestKey: string | undefined;
205
+ for (const [parkedKey, state] of this.parked) {
206
+ if (!parkedKey.startsWith(`${key}\u0000`)) continue;
207
+ if (!best || state.runs.size > best.runs.size) {
208
+ best = state;
209
+ bestKey = parkedKey;
210
+ }
211
+ }
212
+ if (best && bestKey) this.parked.delete(bestKey);
213
+ return best;
214
+ }
215
+
216
+ private describe(cluster: ClusterState): HoldDecision {
217
+ const runs = cluster.runs.size;
218
+ const window = cluster.firstAt ? ` · 관측 ${cluster.firstAt}${cluster.lastAt && cluster.lastAt !== cluster.firstAt ? `..${cluster.lastAt}` : ''}` : '';
219
+ if (cluster.held) {
220
+ return {
221
+ hold: true,
222
+ reason: `같은 서명 ${runs}건(임계 ${this.threshold}) — 원인 판정 전 ${cluster.goal}·${cluster.host} 재발사 보류${window}`,
223
+ signature: cluster.signature,
224
+ runs,
225
+ };
226
+ }
227
+ return {
228
+ hold: false,
229
+ reason: `같은 서명 ${runs}건 < 임계 ${this.threshold} — 보류하지 않는다${window}`,
230
+ signature: cluster.signature,
231
+ runs,
232
+ };
233
+ }
234
+ }
235
+
236
+ /** Process-wide cluster shared by the tick failure record point and the dispatcher relaunch gate. */
237
+ let shared: AnomalyCluster | undefined;
238
+
239
+ /** Lazily created shared instance — no fs side effects, process-wide by design. */
240
+ export function defaultAnomalyCluster(): AnomalyCluster {
241
+ shared ??= new AnomalyCluster();
242
+ return shared;
243
+ }
@@ -11,12 +11,14 @@ import { getUserConfig, ORCHESTRATOR_DEFAULTS, resolveConfiguredAgentRoleLlm, ty
11
11
  import { rubricPriority } from '../../release-loop/rubric.js';
12
12
  import { debug } from '../../debug/log.js';
13
13
  import { emitLoopHeartbeat } from '../neighbor-runtime.js';
14
+ import { ConsensusEngine } from '../consensus.js';
14
15
  import { listSelfDevRuns, runSummaryLine, selfDevRunsDir } from '../../self-dev/run-store.js';
15
16
  import { planAction, runSeatLoopOnce, type SeatDeps, type SeatItem } from '../../seat-loop/seat-loop.js';
16
17
  import { addHarnessQueue, harnessQueueOutcome, setQueuedPoolHint } from '../../harness/harness-queue.js';
17
18
  import { placeOnGrid, type GridHost } from './grid-place.js';
18
19
  import { checkPodPool, parsePodPool, resolvePodPoolSpec } from '../../task-orchestrator/surfaces/pod-pool.js';
19
20
  import { leaseKubectl } from '../../task-orchestrator/surfaces/pod-lease.js';
21
+ import { defaultAnomalyCluster, extractContainerExit, type AnomalyCluster } from './anomaly-cluster.js';
20
22
  import { isLaunchEligible, isTrafficLaunch, recordDispatchCycle, seatOfTree, type TrafficProcess } from './traffic.js';
21
23
  import { defaultListHarnessProcesses } from '../../harness/harness-cli-command.js';
22
24
  import * as testGuard from '../../instance/test-write-guard.js';
@@ -32,7 +34,7 @@ export type Window = '08' | '12' | '18';
32
34
  export type Node = 'intake' | 'split' | 'place' | 'delegate' | 'launch' | 'reconcile' | 'report';
33
35
  export type Mode = 'off' | 'shadow' | 'live';
34
36
  const SEAT_LOOP_IDS: Readonly<Record<string, string>> = { OP: 'op-seat', MK: 'cmo-seat', TC: 'tc-seat', UX: 'ux-seat' };
35
- export interface Cell { id: string; title: string; kind?: string; seat?: string; host?: string; gridHost?: boolean; version?: string; cardId: string; origin: 'candidate' | 'flow1a'; priority?: 'P0' | 'P1' | 'P2' | 'P3' | 'P4'; predecessors?: string[] }
37
+ export interface Cell { id: string; title: string; kind?: string; seat?: string; host?: string; gridHost?: boolean; version?: string; cardId: string; origin: 'candidate' | 'flow1a'; priority?: 'P0' | 'P1' | 'P2' | 'P3' | 'P4'; predecessors?: string[]; consensusProposalId?: string }
36
38
  export interface TickState {
37
39
  runId: string; window: Window; mode: Mode; day: string;
38
40
  cards: TaskCard[]; skippedCards: Array<{ id: string; reason: string }>; cells: Cell[]; placed: number; unplaced?: number; delegated: number; wouldDelegate: number; rebalanced?: number; rebalanceBlocked?: Array<{ id: string; reason: string }>;
@@ -58,7 +60,7 @@ export interface TickState {
58
60
  missing: string[];
59
61
  }
60
62
  /** FLOW1a contract: with `{ shadow: true }` the splitter only proposes cells and writes nothing (cards, ledgers, LLM side effects excepted). */
61
- export type SplitAdapter = (card: TaskCard, opts?: { shadow?: boolean }) => Promise<Array<{ id: string; title: string; kind?: string; seat?: string; host?: string }>> | Array<{ id: string; title: string; kind?: string; seat?: string; host?: string }>;
63
+ export type SplitAdapter = (card: TaskCard, opts?: { shadow?: boolean }) => Promise<Array<{ id: string; title: string; kind?: string; seat?: string; host?: string; consensusProposalId?: string }>> | Array<{ id: string; title: string; kind?: string; seat?: string; host?: string; consensusProposalId?: string }>;
62
64
  /** RELPLAN1 `placeCell(input: PlacementCell)` — owner·priority·predecessors are required; the result carries no seat. */
63
65
  export type PlacementInput = { id: string; title: string; owner: string; priority: 'P0' | 'P1' | 'P2'; predecessors: string[] };
64
66
  export type PlaceAdapter = (cell: PlacementInput, deps?: { dryRun?: boolean; now?: Date }) => Promise<{ version?: string } | null> | { version?: string } | null;
@@ -73,6 +75,8 @@ export interface TickDeps {
73
75
  gridHosts?: readonly GridHost[];
74
76
  seatTurn?: (seat: string, root: string, host?: string, options?: Pick<SeatDeps, 'enqueue'>) => Promise<{ status: string; queueId?: string; runId?: string; item?: { source: string; id: string } }>;
75
77
  queueOutcome?: (queueId: string, root: string) => 'pending' | 'unknown' | 'retryable' | 'succeeded';
78
+ /** ANOMALY-CLUSTER — grouping state shared with the dispatcher relaunch gate; defaults to the process-wide instance. */
79
+ anomalyCluster?: AnomalyCluster;
76
80
  /** Snapshot of running harness processes for launch-cap decisions; an unreadable snapshot blocks launches. */
77
81
  launchProcesses?: () => { status: 'ok'; records: readonly TrafficProcess[] } | { status: 'incomplete' };
78
82
  /** 발사 전 대기열 항목의 풀 힌트 갱신(주입 안 하면 harness-queue `setQueuedPoolHint`). */
@@ -453,6 +457,22 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
453
457
  const root = deps.root ?? effectiveInstanceRoot();
454
458
  const runId = deps.runId ?? graphRunId() ?? `${kstDay(now)}-${window}`;
455
459
  const path = stateFile(root, runId);
460
+ const consensus = new ConsensusEngine({ stateDir: root });
461
+ const consensusAllows = (cell: Cell): boolean => {
462
+ if (cell.kind !== 'cross-branch-change' && !cell.consensusProposalId) return true;
463
+ const workKey = `orch:${cell.cardId}:${cell.id}`;
464
+ try {
465
+ if (cell.kind === 'cross-branch-change') {
466
+ const proposal = consensus.proposalForWork(workKey);
467
+ if (!proposal || (cell.consensusProposalId && cell.consensusProposalId !== proposal.id)) return false;
468
+ cell.consensusProposalId = proposal.id;
469
+ }
470
+ return !!cell.consensusProposalId && consensus.canExecute(cell.consensusProposalId);
471
+ } catch (error) {
472
+ debug.log('loop.orchestrator', 'consensus-gate-failed', { id: cell.consensusProposalId, workKey, error: String(error) }, { level: 'warn' });
473
+ return false;
474
+ }
475
+ };
456
476
  const orchestratorConfig = getUserConfig().loops?.orchestrator;
457
477
  const configured = deps.mode ?? orchestratorConfig?.mode;
458
478
  const mode: Mode = configured === 'off' || configured === 'live' ? configured : 'shadow';
@@ -529,9 +549,12 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
529
549
  const cells = ruleOnly ? [{ id: card.id, title: card.title }] : split ? await split(card, { shadow: mode === 'shadow' }) : [{ id: card.id, title: card.title }];
530
550
  for (const cell of cells) {
531
551
  if (!cell.id?.trim() || !cell.title?.trim()) throw new Error('invalid split cell');
552
+ const workKey = `orch:${card.id}:${cell.id}`;
553
+ const proposalId = cell.consensusProposalId ?? (cell.kind === 'cross-branch-change' ? consensus.proposalForWork(workKey)?.id : undefined);
532
554
  state.cells.push({ cardId: card.id, id: cell.id, title: cell.title, origin: split ? 'flow1a' : 'candidate',
533
555
  ...(ruleOnly ? { priority: rubricPriority(card.sections.map(section => section.content).join('\n')) } : {}),
534
- ...(cell.kind !== undefined ? { kind: cell.kind } : {}), ...(cell.seat ? { seat: cell.seat } : {}), ...(cell.host !== undefined ? { host: cell.host } : {}) });
556
+ ...(cell.kind !== undefined ? { kind: cell.kind } : {}), ...(cell.seat ? { seat: cell.seat } : {}), ...(cell.host !== undefined ? { host: cell.host } : {}),
557
+ ...(proposalId ? { consensusProposalId: proposalId } : {}) });
535
558
  }
536
559
  observe('exchange', `split:${card.id}`, cells.length);
537
560
  if (split && cells.length && mode === 'live') {
@@ -567,6 +590,7 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
567
590
  }
568
591
  if (available && (mode === 'live' || !deps.placeCell)) for (const cell of state.cells) {
569
592
  if (cell.origin !== 'flow1a' || !cell.seat || !SEAT_LOOP_IDS[cell.seat]) continue;
593
+ if (!consensusAllows(cell)) { observe('consensus-blocked', cell.consensusProposalId, 1); continue; }
570
594
  // RELPLAN's dryRun calculates the same release without writing a checklist in shadow.
571
595
  try {
572
596
  const priority = cell.priority === 'P3' || cell.priority === 'P4' ? 'P2' : cell.priority ?? 'P2';
@@ -645,6 +669,7 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
645
669
  };
646
670
  for (const cell of state.cells) {
647
671
  if (cell.origin !== 'flow1a' || !cell.seat) continue;
672
+ if (!consensusAllows(cell)) { observe('consensus-blocked', cell.consensusProposalId, 1); continue; }
648
673
  const targetLoopId = SEAT_LOOP_IDS[cell.seat];
649
674
  if (!targetLoopId) continue;
650
675
  const key = `orch:${cell.cardId}:${cell.id}`;
@@ -674,6 +699,17 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
674
699
  // shadow 표본은 따로 센다 — 자리 경로로 아직 안 간 칸(shadow 틱·배치 전)이 나중에 live 로 바뀌면 그때 뜬다.
675
700
  // ⚠️ 이미 자리 저널에 들어간 칸은 live 로 바꿔도 다시 안 넘긴다(keys.has 에서 끝) — 한 칸의 발사 주체는 하나다(의도).
676
701
  const handKey = handLive ? key : `shadow:${key}`;
702
+ // ANOMALY-CLUSTER: the goal·host pair is the hold key (never part of the failure signature). While a
703
+ // signature with 3+ runs is un-judged, its relaunch is held and the cell is carried to the next tick.
704
+ const anomalyGoal = cell.cardId;
705
+ const anomalyHost = cell.seat;
706
+ const anomaly = deps.anomalyCluster ?? defaultAnomalyCluster();
707
+ const hold = anomaly.hold(anomalyGoal, anomalyHost);
708
+ if (hold.hold) {
709
+ (state.deferredCells ??= []).push(cell);
710
+ observe('anomaly-cluster-hold', `${key}:${hold.reason}`, 1, 'task-agent');
711
+ continue;
712
+ }
677
713
  mkdirSync(dirname(ledger), { recursive: true });
678
714
  mkdirSync(dirname(path), { recursive: true });
679
715
  // Claim under the seat-journal lock — the same lock the seat append takes, so a live claim and a seat row never both land.
@@ -693,9 +729,18 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
693
729
  withFileLockSync(`${path}.lock`, () => appendFileSync(ledger, `${JSON.stringify({ key: handKey, cell: cell.id, cardId: result.card.id, mode: result.mode, launched: result.launched, status: 'handed', runId, at: now.toISOString() })}\n`));
694
730
  (state.handed ??= []).push({ key, cell: cell.id, cardId: result.card.id, mode: result.mode, launched: result.launched });
695
731
  observe('hand-to-task-agent', `${key}:${result.card.id}:${result.mode}${result.launched ? ':launched' : ''}`, 1, 'task-agent');
732
+ // A hand that went through is the cause verdict for this goal·host — clear a pending hold.
733
+ if (anomaly.isHeld(anomalyGoal, anomalyHost)) anomaly.release(anomalyGoal, anomalyHost, '원인 판정: hand-to-task-agent 성공');
696
734
  // A live hand is an assignment: it counts toward maxDelegatePerTick like a seat row (COORD-HA ②).
697
735
  if (handLive) { keys.add(key); state.delegatedKeys?.push(key); continue; }
698
736
  } catch (error) {
737
+ // ANOMALY-CLUSTER record point: signature from kind·container exit·stage·reason tail of lastLines.
738
+ const failureLines = [String(error)];
739
+ anomaly.record({
740
+ goal: anomalyGoal, host: anomalyHost, runId,
741
+ kind: 'hand-to-task-agent-failed', containerExit: extractContainerExit(failureLines[0]!),
742
+ stage: 'delegate', lastLines: failureLines, at: now.toISOString(),
743
+ });
699
744
  observe('hand-to-task-agent-failed', `${key}:${String(error).slice(0, 160)}`, 1, 'task-agent');
700
745
  // A failed live hand stays claimed (no relaunch loop) and does not fall back to the seat path — one launcher per cell.
701
746
  if (handLive) { keys.add(key); continue; }
@@ -754,7 +799,7 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
754
799
  // shadow 는 저널을 읽지 않는다 — 깨진 live 저널이 관측 전용 틱을 넘어뜨리지 않게.
755
800
  const latestRequests = new Map(mode === 'live' && state.degradation?.level !== 2 ? readRequests(root).map(row => [row.key, row]) : []);
756
801
  const eligible = state.cells.filter(cell => state.degradation?.level !== 2 && cell.origin === 'flow1a' && cell.seat && SEAT_LOOP_IDS[cell.seat]
757
- && validVersion(cell.version) && (mode === 'shadow' || latestRequests.get(`orch:${cell.cardId}:${cell.id}`)?.status === 'queued')
802
+ && consensusAllows(cell) && validVersion(cell.version) && (mode === 'shadow' || latestRequests.get(`orch:${cell.cardId}:${cell.id}`)?.status === 'queued')
758
803
  && (orchestratorConfig?.maxDelegatePerTick === undefined || state.delegatedKeys?.includes(`orch:${cell.cardId}:${cell.id}`)
759
804
  || (mode === 'live' && latestRequests.has(`orch:${cell.cardId}:${cell.id}`))));
760
805
  const seats = [...new Set(eligible.map(cell => cell.seat!))];