elanous 0.2.37 → 0.2.40

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 (727) 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/{8kITumG9GAZ1LwT9POrAR → HjeK7zONHfR7op1hKXp4k}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{1746.3563617ea64023a3.js → 1060.014f1f01a17aec26.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{9151.a2c51e93f9156dae.js → 1281.d81877e35b9068f4.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/1350.59f40e39e02d91b1.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1415.79821ec7ae99acdb.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1452.162bb2d9d699e82a.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/147.f92f63bbc5e85fa5.js +286 -0
  10. package/apps/pwa/out/_next/static/chunks/1537-6bb97b5214928ea9.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1661.fb425a1d8a065b72.js +149 -0
  12. package/apps/pwa/out/_next/static/chunks/1671-1c22b40b50b208f2.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1758.0204d3f48783c49d.js +90 -0
  14. package/apps/pwa/out/_next/static/chunks/1806.027bf78b6a94d340.js +104 -0
  15. package/apps/pwa/out/_next/static/chunks/{3578.4e9f9948a9a6f2f4.js → 2047.8f23e210995d4548.js} +2 -2
  16. package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{7424.c0fe2a595d4232b5.js → 2066.a77257c8c350770a.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/2096-a938496bc996dcbd.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{4931.95cc6dbd230774ca.js → 2177.df8547f9d7215c4e.js} +16 -16
  20. package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{6680.6a693c28aae4cd19.js → 2226.2cf61ec781827219.js} +2 -2
  22. package/apps/pwa/out/_next/static/chunks/2281-b8cede695c6c650e.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2499.02fbfd18126c10c0.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{6252.240578f10952e091.js → 2522.f2766b76d22c8bdf.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/{1262.a89bb27a5b2f844e.js → 2566.beaffc3a5e1fcd2e.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/261.0d471e8aded799f3.js +226 -0
  27. package/apps/pwa/out/_next/static/chunks/2615.3c9738153de3ef3f.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2727.e703d99ac414916d.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2752.7904b8df0254d0ae.js +27 -0
  30. package/apps/pwa/out/_next/static/chunks/2762-5051a862dfa40e99.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/2767-31784bfedf8e245d.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{2318-450e75d07605b8fe.js → 2774-719820e3f5b2a3eb.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{4725-34bed25720cc326b.js → 2829-734fe8bf2eee7347.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/311-32dcac79970985e8.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3175-f93f7495cd28253c.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3184.8da993f5502d2140.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3231-d7c981db0ff8bdcc.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3250.151309c5176d6b4b.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3330.7443183b7e6fdbdf.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3517.a5aa1797a9dbf2ee.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3567-45f676877ed9e8a5.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3746-f80a78f220bf37b5.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3819.8a1de79b2e8c7298.js +24 -0
  45. package/apps/pwa/out/_next/static/chunks/39.9b37b0be4c128a83.js +77 -0
  46. package/apps/pwa/out/_next/static/chunks/{4337e36d.f42c3b391b3d8f20.js → 3b355b3d.6f73c98bf6f9c749.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/4023.a19045970a9ce16a.js +36 -0
  48. package/apps/pwa/out/_next/static/chunks/{58edce7d.f1b0c72acf13b123.js → 409c787b.e48c5bec8ec10456.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/413-24c8284bda08241d.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4135.e45d6ebc29e20647.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4283.65502f5d0e6ff6c0.js +287 -0
  52. package/apps/pwa/out/_next/static/chunks/4305-4e28fa92a7b34a5b.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4335-50efa61fd7613142.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4351.0f37a6db2b34d50b.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{5046.7fd5cbd859299448.js → 470.51a72a2348306455.js} +2 -2
  56. package/apps/pwa/out/_next/static/chunks/4720.ecbd1693fa151068.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/{2375.bf364c85dbb6f085.js → 4769.9fd582071301f382.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/483.725e4a61be922788.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{de8446d3.31b73eb239fecd7b.js → 4864a2ca.1c1c280a7772c5e5.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/4969-4b209d7307410c00.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5068-c7f53862f83c0917.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5315.bc96711c24dfefe2.js +74 -0
  63. package/apps/pwa/out/_next/static/chunks/{4383.18e5c54db3a22c88.js → 5383.bdfa5d886e39a826.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/5436.fdf6fa8ae3e9588d.js +64 -0
  65. package/apps/pwa/out/_next/static/chunks/5542.efbf14f16baed4dd.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5622.94893f5aea7185d0.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5644.8f401a25601d05fc.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5658.35f70eb9871a54bf.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5721.7bdc0e904c76ab51.js +8 -0
  70. package/apps/pwa/out/_next/static/chunks/5790-eef0ca20884a6bdf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5802.ef0d8598ca68fe84.js +62 -0
  72. package/apps/pwa/out/_next/static/chunks/5890.fb974729788dcb71.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/5924.5ef25cddd36d5dbf.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/5979-e59c099ebf8d1f35.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/6020.714cfeada2315e2e.js +94 -0
  76. package/apps/pwa/out/_next/static/chunks/6027-dfe0349d8c50f698.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{6745-5a63492933959dd9.js → 6051-0ae955eedb10adb9.js} +3 -3
  78. package/apps/pwa/out/_next/static/chunks/6178.bc4730c86cf74536.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/{2283.edd9627b7bdfb546.js → 6257.c0037b8949239f5e.js} +2 -2
  80. package/apps/pwa/out/_next/static/chunks/6273.d808b0dcb3c2b155.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6292.6ef1df64fa6a4c8a.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/647-af8dd920ba46533c.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6541-170dc5c59e135c0c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6624.981ef7caeb680560.js +32 -0
  85. package/apps/pwa/out/_next/static/chunks/6742-a1ad4a94ba7bc37a.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/{6819.be5c9c4d67f22922.js → 6749.0744ce6eb08d40e9.js} +16 -16
  87. package/apps/pwa/out/_next/static/chunks/6836-493dc55c39187949.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/6856-53ac421c06039a18.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/6908.06008c67f6380ea9.js +148 -0
  90. package/apps/pwa/out/_next/static/chunks/6915.096931864206f522.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/6925.5e181fb7dcf90193.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/6cc1d1d6.9a98dd4622f1afc6.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7203-800e11037adc41eb.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7219-15bdd9a80661af8e.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7279.6170f591105936bb.js +93 -0
  96. package/apps/pwa/out/_next/static/chunks/7349-373165c7fbdcc3df.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7514-a533ba0ca1cae4f4.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7515.1ad6efe157fa4448.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/7521.d919cc1fab80c1d9.js +24 -0
  100. package/apps/pwa/out/_next/static/chunks/7538.90e97bbdf9178cff.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/7611.85f045bf232053ac.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/7825-39203196a12579b2.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/7869.5e1a9a12fd70d6c7.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8086.1ab9103c41be884f.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8099.1cccf31c1baa7e1c.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8179-e61fffbdb70f1152.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8265.bdeb991b34db6a06.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{2002-a43a3f380df873ec.js → 8272-025653884f9645d2.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/{7867.e8725745ddd1d940.js → 8357.1aaa713b052a78b1.js} +4 -4
  110. package/apps/pwa/out/_next/static/chunks/8638-e42615f2166165b5.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/8639-92c11d069792429e.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/8691.54e22831d5e8ccf8.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/8d173e38.18a2f7b4e1848bdb.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9069.657590a84afb8fac.js +41 -0
  115. package/apps/pwa/out/_next/static/chunks/9125-ae588d88a0293b93.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{4313.76f232c304a15bde.js → 9175.2de5209a5ce6f68a.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9184.45afbf44fec87574.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{8c58d09b.e8724a299658d86f.js → 9189505a.980427ac048c8c60.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9311.f9f641a46a508611.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9371-a6fee8378ebfa3ee.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9421-3aa9ff4fa7f63d8a.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9992.07ce73c10bd5e6a1.js +79 -0
  123. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76394dc618d322c8.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/approvals/page-1b948637c37b3abd.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-c63400f1bcf3e47c.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/board/page-95d0957267819586.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ba957ff875a026a0.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/bots/page-bb6fd0714879cb87.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8f9038520d2acbef.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/chat/page-d4b48397e05fce2c.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/consult/page-72d5744245dc0c27.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/control/page-37625dc8300fa43a.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/decisions/page-fbef9d160272dbc1.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/design-check/page-58424168df84928e.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/editor/page-72c12ba430ac57c0.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/exec/page-d53f3e9ed806d7e0.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/field/page-4d2fbd45feee0829.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76394dc618d322c8.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/inside/page-8783dc0ed7590a2c.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/intake/page-3706cb390606e930.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/layout-9b0a86598e0111fd.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live/{page-3337c6a1328c2674.js → page-4edb8df90f4537ce.js} +1 -1
  143. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83d27757e2b8060a.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/loops/page-47398b9ba1cc5e1b.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/market/page-fb86f55cfe2e681d.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e22345fc8fd47b1b.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/morning/{page-1e5da297557d2354.js → page-fca2e59a81744d9e.js} +1 -1
  148. package/apps/pwa/out/_next/static/chunks/app/not-found-6e96bda63100b31e.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/observatory/page-4d17ad8e0db8cea4.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-121f92766c33beaa.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-43f14212c545f92d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ccec2023e7a974ec.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/outputs/page-b04f33f548b89a94.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/page-c8792823c0917021.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/reflection/page-8c0e32782ceef4cb.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-94bd3922eb230ce8.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bca565887bafa03c.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ac1dffafe649fc6c.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/page-52374edb5e23e455.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ad4ebca120d43ca7.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76394dc618d322c8.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/page-718b89ce4b4ae4e4.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/share/page-204eca33eeeaddec.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/showroom/page-e58ba9bcdb9ac0f9.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/tasks/page-98f6dd50bafd7734.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/term/{page-ac2c1e6169cfce57.js → page-139d722de1dcd6c1.js} +1 -1
  167. package/apps/pwa/out/_next/static/chunks/app/today/page-5a4bdd72bff27057.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/trace/page-6f6ab17d44f984ce.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/vault/page-aabb7bd15fb72da9.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e4322319164a4436.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/page-e9efc0c8f32e2371.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-c1c80e345fa9d6f5.js → page-ccde99f07aaf71f7.js} +1 -1
  173. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{d9815f84.4918f682a45a8502.js → b84cad00.594027ebe0531fe2.js} +3 -3
  175. package/apps/pwa/out/_next/static/chunks/c696986b.5dc8bb1143af16d1.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/{709a918c.4fd3b4e2a32cb4e3.js → ca3702f8.2913182e73889fa2.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/d5d3cefc-373c4eb722ed848b.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/{5f6af561-f90b7a67f4f75d13.js → d8de0de2-dd0f4ac8e5ab1832.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/framework-002b472a66935d31.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-49b88d47292c0476.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/main-app-fff2549cb10a133f.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_app-32abbbba3f3b76b7.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/pages/_error-9d9cfef60c60dd7a.js +1 -0
  184. package/apps/pwa/out/_next/static/chunks/webpack-cc7f483fa294034a.js +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +22 -22
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +22 -22
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +22 -22
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +21 -21
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +21 -21
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +22 -22
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +21 -21
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +22 -22
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +22 -22
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +21 -21
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +22 -22
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +22 -22
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +22 -22
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +22 -22
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +21 -21
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +21 -21
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +22 -22
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +22 -22
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +22 -22
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +21 -21
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +21 -21
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +22 -22
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +22 -22
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +21 -21
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +21 -21
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +21 -21
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +22 -22
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +22 -22
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +21 -21
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +22 -22
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +22 -22
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +22 -22
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +22 -22
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +22 -22
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +21 -21
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +22 -22
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +22 -22
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +22 -22
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +22 -22
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +22 -22
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +22 -22
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +22 -22
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +22 -22
  278. package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
  279. package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
  280. package/graphs/demo/persona-marketer/recipes.yaml +19 -0
  281. package/graphs/release/recipes.yaml +9 -0
  282. package/graphs/release/release-loop.yaml +26 -18
  283. package/graphs/video/explainer-line.yaml +4 -1
  284. package/package.json +1 -1
  285. package/scripts/ask-op-inbox-once.ts +17 -0
  286. package/scripts/brand/check.ts +13 -4
  287. package/scripts/dead-code/report.ts +169 -0
  288. package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
  289. package/scripts/gate-0226-failure-census.ts +39 -0
  290. package/scripts/intake-collect-telegram-saved-stage.ts +48 -0
  291. package/scripts/lib/morning-report-options.ts +3 -4
  292. package/scripts/lib/tui-regress-evidence.ts +56 -0
  293. package/scripts/morning-report.ts +5 -1
  294. package/scripts/provision-export-redactions.ts +15 -0
  295. package/scripts/public-copy-lint.ts +122 -0
  296. package/scripts/public-export.ts +77 -2
  297. package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
  298. package/scripts/ratchets/train-side-invariants.sh +7 -1
  299. package/scripts/release-loop/cut-branch.ts +61 -12
  300. package/scripts/release-loop/export-check-node.ts +21 -3
  301. package/scripts/release-loop/gate-node.ts +527 -60
  302. package/scripts/release-loop/gate-partial.ts +82 -3
  303. package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
  304. package/scripts/release-loop/gate-radius-live.ts +4 -2
  305. package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
  306. package/scripts/release-loop/gate-shard-receipts.ts +89 -0
  307. package/scripts/release-loop/gate-wall.ts +5 -5
  308. package/scripts/release-loop/preflight.ts +6 -2
  309. package/scripts/release-loop/resume-cap.ts +2 -1
  310. package/scripts/release-loop/resume-release.ts +317 -13
  311. package/scripts/release-loop/resume.ts +61 -5
  312. package/scripts/release-loop/traffic-node.ts +12 -4
  313. package/scripts/release-loop/traffic-transition.ts +53 -13
  314. package/scripts/release-loop/version-node.ts +35 -5
  315. package/scripts/release-story/draft.ts +1 -1
  316. package/scripts/research-bench/README.md +53 -0
  317. package/scripts/research-bench/questions.json +66 -0
  318. package/scripts/research-bench/rubric.md +33 -0
  319. package/scripts/research-bench/run.ts +523 -0
  320. package/scripts/tui-regress.ts +85 -10
  321. package/scripts/ux-sim.ts +1 -1
  322. package/scripts/video-pipeline.ts +2 -2
  323. package/src/acp/core-turn-bridge.ts +14 -1
  324. package/src/agent/autonomous-tools.ts +10 -3
  325. package/src/agent/monad-agent-turn.ts +4 -1
  326. package/src/agent/registry.ts +26 -2
  327. package/src/agent/run-context.ts +1 -1
  328. package/src/agent/shared-app-tools.ts +1 -1
  329. package/src/agent/surface-ux/build.ts +12 -3
  330. package/src/agent/surface-ux/types.ts +1 -1
  331. package/src/agent/task-notification.ts +78 -7
  332. package/src/agent/types.ts +3 -0
  333. package/src/agent-mission/driver.ts +29 -3
  334. package/src/agent-mission/mission-cli.ts +2 -1
  335. package/src/agent-substrate/review-context-pack.ts +365 -0
  336. package/src/agent-substrate/review-observation.ts +10 -0
  337. package/src/agent-substrate/self-review-cli.ts +419 -42
  338. package/src/ask-user-question/index.ts +6 -0
  339. package/src/ask-user-question/inline-resolver.ts +49 -0
  340. package/src/auto-research/question-ladder-contract.ts +156 -0
  341. package/src/auto-research/research-turn.ts +467 -0
  342. package/src/autopilot/agent-loop.ts +1 -1
  343. package/src/autopilot/discovery/doc-lint.ts +1 -1
  344. package/src/autopilot/pty-control-loop.ts +8 -1
  345. package/src/boot/daemon-tools/index.ts +4 -3
  346. package/src/boot/daemon-tools/self-implement.ts +270 -2
  347. package/src/boot/daemon-tools/types.ts +2 -0
  348. package/src/bots/screen-probe.ts +1 -1
  349. package/src/budget/llm-cost.ts +44 -5
  350. package/src/budget/unified-usage.ts +17 -1
  351. package/src/capture/tui-self-report.ts +24 -2
  352. package/src/chat/index.ts +34 -7
  353. package/src/chat/tool-render/dispatch.ts +8 -1
  354. package/src/cli/agent-cli.ts +43 -8
  355. package/src/cli/guardian-cli.ts +3 -1
  356. package/src/cli/intake-cli.ts +70 -13
  357. package/src/cli/lesson-cli.ts +86 -10
  358. package/src/cli/log-event-names.ts +1 -0
  359. package/src/cli/pod-cli.ts +17 -2
  360. package/src/cli/pr-land-overlap-evidence.ts +38 -5
  361. package/src/cli/pr-land-refusal.ts +1 -1
  362. package/src/cli/pty-takeover-cli.ts +125 -12
  363. package/src/cli/release-checklist-read-cli.ts +5 -2
  364. package/src/cli/release-cli.ts +99 -15
  365. package/src/cli/repo-cli.ts +2 -1
  366. package/src/cli/review-carry.ts +77 -0
  367. package/src/cli/self-update.ts +1 -1
  368. package/src/cli/tasks-card-show.ts +31 -1
  369. package/src/cli/tasks-cli.ts +98 -32
  370. package/src/cli/tasks-read-cli.ts +13 -5
  371. package/src/context-bus/context-now.ts +86 -2
  372. package/src/control-plane/ledger.ts +21 -4
  373. package/src/core-turn/run-core-turn.ts +51 -3
  374. package/src/core-turn/run-goal-loop.ts +152 -8
  375. package/src/core-turn/types.ts +12 -0
  376. package/src/dashboard/chat/acp-chat.ts +2 -2
  377. package/src/dashboard/classic-sigquit.ts +16 -0
  378. package/src/dashboard/index.ts +339 -44
  379. package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
  380. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
  381. package/src/dashboard/input/chat-main-slash-command.ts +7 -0
  382. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  383. package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
  384. package/src/dashboard/input/external-input-host.ts +2 -0
  385. package/src/dashboard/input/terminal-modal-router.ts +8 -159
  386. package/src/dashboard/side-basic-runtime.ts +61 -0
  387. package/src/dashboard/sidetab-runtime.ts +228 -0
  388. package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
  389. package/src/dashboard/slash-runtime/dashboard-handlers.ts +22 -8
  390. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
  391. package/src/dashboard/term-slash-runtime.ts +18 -18
  392. package/src/dashboard/turn-preamble.ts +30 -4
  393. package/src/domains/guardian-tick.ts +9 -0
  394. package/src/domains/knowledge.ts +1 -1
  395. package/src/esc-abort-gate.ts +33 -1
  396. package/src/execution-loop/launch-gate.ts +206 -1
  397. package/src/git-fs/watcher.ts +27 -22
  398. package/src/git-fs/worktree.ts +19 -3
  399. package/src/graph-runner/graph-cli.ts +6 -4
  400. package/src/graph-runner/graph-grow.ts +37 -9
  401. package/src/graph-runner/runner.ts +48 -11
  402. package/src/graph-wizard/generate.ts +16 -7
  403. package/src/graph-wizard/mission-compose.ts +201 -0
  404. package/src/grok/agent-search.ts +8 -2
  405. package/src/grok/credential.ts +112 -36
  406. package/src/grounding/ref-index.ts +11 -0
  407. package/src/grounding/ref-vector.ts +61 -0
  408. package/src/grounding/sources-cli.ts +2 -2
  409. package/src/grounding/sources.ts +15 -1
  410. package/src/harness/harness-cli-command.ts +38 -9
  411. package/src/harness/harness-pod-dispatch.ts +7 -1
  412. package/src/hq/fence-wrapper.ts +1 -1
  413. package/src/hq/transfer.ts +1 -1
  414. package/src/index.ts +60 -16
  415. package/src/input/external-input-queue.ts +10 -0
  416. package/src/intake-plane/collect-telegram-saved.ts +90 -6
  417. package/src/intake-plane/intake-to-tasks.ts +246 -3
  418. package/src/interactive-terminal-modal.ts +3 -0
  419. package/src/keybindings.ts +17 -22
  420. package/src/lessons/friction-ledger.ts +154 -0
  421. package/src/live-supply/collector.ts +149 -0
  422. package/src/live-supply/probes.ts +52 -0
  423. package/src/live-supply/snapshot.ts +40 -0
  424. package/src/llm/provider-credentials.ts +1 -1
  425. package/src/llm-tool-schema.ts +20 -0
  426. package/src/llm.ts +486 -61
  427. package/src/loops/orchestrator/inbox-once.ts +28 -0
  428. package/src/loops/orchestrator/inbox.ts +130 -1
  429. package/src/loops/orchestrator/tick.ts +14 -3
  430. package/src/maturity/feature-maturity.ts +1 -0
  431. package/src/nexus/api/channel-ask-op.ts +96 -0
  432. package/src/nexus/api/discord-trigger-bot.ts +28 -1
  433. package/src/nexus/api/harness-api.ts +2 -1
  434. package/src/nexus/api/telegram-trigger-bot.ts +24 -0
  435. package/src/nexus/api/terminals.ts +28 -6
  436. package/src/patents/ledger.ts +18 -1
  437. package/src/preview/terminal.ts +4 -2
  438. package/src/prompt-cache/anthropic.ts +2 -0
  439. package/src/prompt-enhance/enhance.ts +5 -0
  440. package/src/pty/snapshot.py +132 -0
  441. package/src/pty-shell/pty-control-ipc.ts +29 -2
  442. package/src/pty-shell/pty-manifest.ts +75 -5
  443. package/src/pty-shell/registry.ts +2 -0
  444. package/src/pty-shell/tui-run-state.ts +80 -3
  445. package/src/release-loop/gate-host-reservation.ts +13 -4
  446. package/src/release-loop/gate-shard-ledger.ts +68 -0
  447. package/src/release-loop/gate-shards.ts +61 -0
  448. package/src/release-loop/light-rc.ts +7 -4
  449. package/src/release-loop/merged-pr-checklist.ts +25 -2
  450. package/src/release-loop/rehearsal-shard-plan.ts +6 -1
  451. package/src/release-loop/rehearsal.ts +28 -1
  452. package/src/repl/index.ts +10 -0
  453. package/src/research/axis-fanout.ts +133 -0
  454. package/src/research/edge-decision.ts +197 -0
  455. package/src/research/gap-followup.ts +249 -0
  456. package/src/research/lenses/counter-evidence.ts +100 -0
  457. package/src/research/lenses/working-backwards.ts +89 -0
  458. package/src/research/output-router.ts +127 -0
  459. package/src/research/plugin-discovery.ts +242 -0
  460. package/src/research-bridge/format.ts +16 -1
  461. package/src/research-bridge/index.ts +1 -0
  462. package/src/research-bridge/invoke.ts +45 -7
  463. package/src/research-bridge/types.ts +2 -0
  464. package/src/self-dev/ask-launch-flow.ts +34 -106
  465. package/src/self-dev/decompose.ts +45 -9
  466. package/src/self-dev/dev-cli.ts +2 -0
  467. package/src/self-dev/dev-pipeline.ts +8 -4
  468. package/src/self-dev/draft-residue.ts +221 -2
  469. package/src/self-dev/draft-sweep.ts +29 -16
  470. package/src/self-dev/graph-journey-route.ts +10 -2
  471. package/src/self-dev/launch-preflight-text.ts +2 -2
  472. package/src/self-dev/launch-preflight.ts +38 -7
  473. package/src/self-dev/orchestrate-cli.ts +1 -0
  474. package/src/self-dev/orchestrate.ts +1 -0
  475. package/src/self-dev/run-supervisor.ts +41 -7
  476. package/src/self-dev/shard-run.ts +260 -3
  477. package/src/self-implement/comment-only-source.ts +54 -0
  478. package/src/self-implement/device-first.ts +8 -2
  479. package/src/self-implement/doctor-visit.ts +100 -57
  480. package/src/self-implement/gate-artifacts.ts +5 -2
  481. package/src/self-implement/gate-baseline.ts +119 -13
  482. package/src/self-implement/gate-cli.ts +466 -93
  483. package/src/self-implement/gate-failure-signature.ts +44 -0
  484. package/src/self-implement/gate-receipt-registry.ts +180 -0
  485. package/src/self-implement/gate-remote.ts +147 -22
  486. package/src/self-implement/goal-author-clarification.ts +178 -24
  487. package/src/self-implement/goal-author-decompose.ts +24 -15
  488. package/src/self-implement/goal-author.ts +82 -7
  489. package/src/self-implement/goal-doc/section.ts +22 -0
  490. package/src/self-implement/goal-supervisor-fill.ts +38 -4
  491. package/src/self-implement/host-regate.ts +120 -45
  492. package/src/self-implement/impl-findings-feedback.ts +188 -0
  493. package/src/self-implement/knowhow-pack.ts +301 -9
  494. package/src/self-implement/l8-merge-queue.ts +198 -32
  495. package/src/self-implement/off-diff-evidence.ts +147 -0
  496. package/src/self-implement/orchestrator.ts +137 -16
  497. package/src/self-implement/pod-inplace-worktree.ts +82 -0
  498. package/src/self-implement/pod-warm-pool-profile.ts +2 -2
  499. package/src/self-implement/premise-review.ts +7 -5
  500. package/src/self-implement/run-ledger.ts +304 -8
  501. package/src/self-implement/run-stop.ts +12 -0
  502. package/src/self-implement/seams.ts +39 -13
  503. package/src/self-implement/self-implement-cli.ts +30 -4
  504. package/src/session/channel-ask-op-envelope.ts +36 -0
  505. package/src/session/channel-op-reply-route.ts +200 -0
  506. package/src/session/chat.ts +92 -15
  507. package/src/session/index.ts +2 -0
  508. package/src/session-runtime/index.ts +9 -22
  509. package/src/session-runtime/provider-circuit.ts +140 -0
  510. package/src/shell-runner/file-engine.ts +1 -0
  511. package/src/shell-runner/types.ts +4 -0
  512. package/src/sidetab-core/model.ts +176 -0
  513. package/src/skills/runner.ts +7 -3
  514. package/src/skills/tools/dev-harness.ts +2 -2
  515. package/src/skills/tools/schedule-wakeup.ts +24 -7
  516. package/src/skills/tools/shell.ts +51 -5
  517. package/src/status/bar.ts +3 -3
  518. package/src/steward/directive-audit.ts +354 -0
  519. package/src/storage/file-lock.ts +17 -4
  520. package/src/surface/child-process.ts +31 -0
  521. package/src/surface/tui-stderr-owner.ts +48 -0
  522. package/src/task-agent/adopt-pr.ts +63 -2
  523. package/src/task-agent/cover.ts +30 -12
  524. package/src/task-agent/evidence-command-normalize.ts +42 -0
  525. package/src/task-agent/export-redactions-provision.ts +43 -0
  526. package/src/task-agent/judge.ts +56 -0
  527. package/src/task-agent/parent-host.ts +59 -12
  528. package/src/task-agent/postland-card.ts +35 -2
  529. package/src/task-agent/rejudge-on-head.ts +46 -2
  530. package/src/task-agent/repair-cycle.ts +68 -9
  531. package/src/task-agent/repair-worker.ts +37 -1
  532. package/src/task-agent/task-hand.ts +226 -33
  533. package/src/task-agent/tier-split.ts +142 -24
  534. package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
  535. package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
  536. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +57 -5
  537. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
  538. package/src/task-orchestrator/surfaces/pod-pool.ts +27 -4
  539. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
  540. package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
  541. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
  542. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
  543. package/src/task-orchestrator/surfaces/self-implement-pod.ts +310 -79
  544. package/src/task-orchestrator/surfaces/self-implement.ts +33 -2
  545. package/src/terminal/session-registry.ts +1 -0
  546. package/src/terminal/terminal-modal-router.ts +156 -0
  547. package/src/tool-hints/gate.ts +6 -4
  548. package/src/tool-hints/signals.ts +33 -1
  549. package/src/tool-runtime/skill-exec-runtime.ts +95 -5
  550. package/src/tui/chat/background-job-status.ts +8 -2
  551. package/src/tui/entry.ts +483 -32
  552. package/src/tui/inline-choice.ts +188 -0
  553. package/src/tui/sidetab/attach.ts +304 -0
  554. package/src/tui/sidetab/list.ts +2 -0
  555. package/src/tui/sidetab/nl-tool.ts +136 -0
  556. package/src/tui/slash/resume-command.ts +23 -0
  557. package/src/tui/slash/resume.ts +3 -23
  558. package/src/tui/slash/term-next.ts +2 -1
  559. package/src/tui/slash/term.ts +12 -1
  560. package/src/tui-client/dashboard-session.ts +7 -1
  561. package/src/tui-client/local-chat-turn.ts +29 -8
  562. package/src/user-config.ts +42 -3
  563. package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
  564. package/src/ux-sim/fake-land-queue.ts +88 -0
  565. package/src/ux-sim/fake-llm.ts +11 -5
  566. package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
  567. package/src/ux-sim/goal-interim-trace.ts +24 -0
  568. package/src/ux-sim/next-tui-seat-scenarios.ts +61 -14
  569. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
  570. package/src/version/packed-revision.json +1 -1
  571. package/src/video-pipeline/recipes/explainer.ts +54 -2
  572. package/src/web-search/grok.ts +32 -6
  573. package/src/web-search/index.ts +8 -7
  574. package/src/workflow-runtime/node-catalog.ts +53 -4
  575. package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +0 -62
  579. package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +0 -32
  587. package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +0 -148
  590. package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +0 -27
  594. package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/3199.6a1a9b0e6cd01dc6.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +0 -36
  601. package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +0 -90
  603. package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +0 -226
  604. package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +0 -287
  605. package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +0 -24
  612. package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +0 -104
  615. package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +0 -93
  622. package/apps/pwa/out/_next/static/chunks/5952.294fc574a8625184.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +0 -74
  624. package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +0 -149
  627. package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +0 -41
  631. package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +0 -24
  634. package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/7c5ed21f-f286708e57cf88f7.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +0 -8
  647. package/apps/pwa/out/_next/static/chunks/8080-40d781e7704d3671.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +0 -77
  649. package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +0 -286
  652. package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +0 -79
  656. package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +0 -94
  664. package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +0 -64
  666. package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-88a1edbff62eaf1d.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +0 -1
  725. package/scripts/migrate-monad-to-elanous.ts +0 -195
  726. package/scripts/rebrand-elanous.ts +0 -242
  727. /package/apps/pwa/out/_next/static/{8kITumG9GAZ1LwT9POrAR → HjeK7zONHfR7op1hKXp4k}/_ssgManifest.js +0 -0
@@ -30,9 +30,39 @@ export const TIER_SPLIT_DECOMPOSE_TIMEOUT_MS = 300_000;
30
30
 
31
31
  /** 조각이 부모 칸에서 물려받는 줄 머리 — hand 의 골 검사(완료 경계 셋)와 계약·경계 문맥. */
32
32
  const INHERITED_PARENT_LABELS = /^\s*(?:[-*]\s*)?(현재 계약|완료 경계 코드|완료 경계 실물|완료 경계 증거 명령|경계|증거 보충)\s*:/;
33
+ const PARENT_ACCEPTANCE_LABEL = /^\s*(?:[-*]\s*)?(수용선|판정|완료 조건|완료 경계 코드|완료 경계 실물|완료 경계 증거 명령)\s*:/;
34
+ const VERIFICATION_PLAN_HEADING = '### 검증 계획(TDD)';
35
+
36
+ /** Read a real Markdown section, ignoring headings inside fenced verbatim asks. */
37
+ function parentVerificationPlan(text: string): string[] {
38
+ const lines = text.split(/\r?\n/u);
39
+ let fence: { char: string; length: number } | null = null;
40
+ let start = -1;
41
+ const section: string[] = [];
42
+ for (const [index, line] of lines.entries()) {
43
+ const marker = /^ {0,3}(`{3,}|~{3,})/u.exec(line)?.[1];
44
+ if (marker) {
45
+ if (!fence) fence = { char: marker[0]!, length: marker.length };
46
+ else if (marker[0] === fence.char && marker.length >= fence.length) fence = null;
47
+ if (start >= 0 && fence) break;
48
+ continue;
49
+ }
50
+ if (fence) continue;
51
+ if (start < 0) {
52
+ if (line.trim() === VERIFICATION_PLAN_HEADING) {
53
+ start = index;
54
+ section.push(line);
55
+ }
56
+ continue;
57
+ }
58
+ if (/^ {0,3}#{1,6}\s/u.test(line)) break;
59
+ section.push(line);
60
+ }
61
+ return section;
62
+ }
33
63
 
34
64
  /**
35
- * 조각 hand 문면 = 조각 골(대상 경로·동작 — 첫 줄 유지) ⊕ 조각 표지 ⊕ 부모 칸의 계약·완료 경계·경계 줄.
65
+ * 조각 hand 문면 = 조각 골(대상 경로·동작 — 첫 줄 유지) ⊕ 조각 표지 ⊕ 부모 칸의 계약·완료 경계·경계 줄·TDD 계획.
36
66
  * 분해기의 조각 골은 짧은 제목뿐이라 그대로 넘기면 hand 의 골 검사(완료 경계 누락)가 막는다(10-21 DEVICE-FIRST-AUTHORING 발사 0).
37
67
  * 부모에 그 줄이 없으면 아무것도 더하지 않는다 — 검사가 지금처럼 거부한다(보수 쪽).
38
68
  */
@@ -43,10 +73,15 @@ export function composeSliceHandText(sliceGoal: string, parentText: string, mark
43
73
  const label = INHERITED_PARENT_LABELS.exec(line)?.[1];
44
74
  return label !== undefined && !sliceHas.has(label);
45
75
  });
76
+ const sliceHasVerificationPlan = sliceLines.some((line) => line.trim() === VERIFICATION_PLAN_HEADING);
77
+ const verificationPlan = sliceHasVerificationPlan ? [] : parentVerificationPlan(parentText);
78
+ inherited.push(...verificationPlan);
46
79
  // 표지는 리뷰 범위를 나르므로 장치 우선 조각(총 2 이상)은 상속 줄이 없어도 남는다 —
47
80
  // 다만 «물려받았다» 는 물려받은 줄에 대한 주장이므로 그 줄이 있을 때만 붙인다.
48
- if (inherited.length === 0 && (marker.total < 2 || !sliceGoal.includes(`동작: ${DEVICE_FIRST_STEP}`))) return sliceGoal;
49
- const inheritanceClaim = inherited.length > 0 ? ' 아래 계약·완료 경계는 부모 칸에서 물려받았다 — 이 조각 범위만 채운다.' : '';
81
+ const isAcceptanceIntegration = sliceGoal.includes('부모 수용선 몫(자동 통합 조각):');
82
+ if (inherited.length === 0 && (marker.total < 2 || (!isAcceptanceIntegration && !sliceGoal.includes(`동작: ${DEVICE_FIRST_STEP}`)))) return sliceGoal;
83
+ const inheritedTopics = `계약·완료 경계${verificationPlan.length > 0 ? '·검증 계획' : ''}`;
84
+ const inheritanceClaim = inherited.length > 0 ? ` 아래 ${inheritedTopics}는 부모 칸에서 물려받았다 — 이 조각 범위만 채운다.` : '';
50
85
  const tag = `조각 ${marker.index}/${marker.total} — 부모 ${marker.cid ?? '(칸 없음)'}(${marker.fromTier}) 를 중 이하로 나눈 몫.${inheritanceClaim}`;
51
86
  return [...sliceLines, tag, ...inherited].join('\n');
52
87
  }
@@ -55,22 +90,58 @@ export type TierSplitPlan =
55
90
  | { kind: 'split'; slices: SizedSlice[] }
56
91
  | { kind: 'blocked'; reason: string };
57
92
 
58
- /** 순수 판정 — 분해 결과 → 발사 계획. 이유 없는 상 조각이 하나라도 있으면 결과 전체를 실패로 본다(이유 없는 상 0). */
93
+ function parentAcceptanceLines(parentText: string): string[] {
94
+ return parentText.split(/\r?\n/u).map((line) => line.trim()).filter((line) => PARENT_ACCEPTANCE_LABEL.test(line));
95
+ }
96
+
97
+ function coveredAcceptanceLines(slices: readonly SizedSlice[], acceptance: readonly string[], parentText: string,
98
+ fromTier: '상' | '특', cid: string | null): string[] {
99
+ const effectiveGoals = slices.map((slice, index) => composeSliceHandText(slice.goal, parentText,
100
+ { index: index + 1, total: slices.length, fromTier, cid }));
101
+ return acceptance.filter((line) => effectiveGoals.some((goal) => goal.includes(line)));
102
+ }
103
+
104
+ function annotateAcceptanceShares(slices: readonly SizedSlice[], acceptance: readonly string[], integratedAdded = false): SizedSlice[] {
105
+ return slices.map((slice) => {
106
+ const share = acceptance.filter((line) => slice.goal.includes(line));
107
+ if (slice.goal.includes('부모 수용선 몫')) {
108
+ if (!integratedAdded || share.length >= acceptance.length || slice.goal.includes('누락 수용선은 자동 통합 조각이 담당한다.')) return slice;
109
+ return { ...slice, goal: `${slice.goal}\n- 누락 수용선은 자동 통합 조각이 담당한다.` };
110
+ }
111
+ if (share.length > 0) return { ...slice, goal: `${slice.goal}\n부모 수용선 몫:\n${share.map((line) => `- ${line}`).join('\n')}` };
112
+ if (acceptance.length > 0 && integratedAdded) return { ...slice, goal: `${slice.goal}\n부모 수용선 몫: 없음 — 누락 수용선은 자동 통합 조각이 담당한다.` };
113
+ return slice;
114
+ });
115
+ }
116
+
117
+ function recordAcceptanceCoverage(data: Record<string, unknown>): void {
118
+ try { debug.log('tier-split', 'slice-acceptance-coverage', data); } catch { /* fail-soft */ }
119
+ }
120
+
121
+ function integratedAcceptanceSlice(parentText: string, missing: readonly string[], slices: readonly SizedSlice[]): SizedSlice {
122
+ const paths = [...new Set(slices.flatMap((slice) => slice.goal.match(/[\w./-]+\.[A-Za-z][\w-]*/gu) ?? []))];
123
+ const goal = `${parentText}\n\n부모 수용선 몫(자동 통합 조각):\n${missing.map((line) => `- ${line}`).join('\n')}`;
124
+ return { goal, files: Math.max(1, paths.length), behaviours: Math.max(1, slices.reduce((sum, slice) => sum + slice.behaviours, 0)),
125
+ newFiles: slices.reduce((sum, slice) => sum + slice.newFiles, 0), tier: '상', unavoidable: 'acceptance-coverage-integration' };
126
+ }
127
+
128
+ /** 순수 판정 — 분해 결과에 남은 상 조각은 불가피 사유가 없어도 unavoidable=auto로 발사한다. */
59
129
  export function planTierSplit(result: TierSizedDecomposeResult): TierSplitPlan {
60
130
  if (!result.ok) return { kind: 'blocked', reason: `decompose-failed: ${result.reason}` };
61
131
  if (result.slices.length === 0) return { kind: 'blocked', reason: 'no-slices' };
62
132
  for (const [index, slice] of result.slices.entries()) {
63
133
  if (!['하', '중', '상'].includes(slice.tier)) return { kind: 'blocked', reason: `invalid-slice-tier: #${index + 1} ${String(slice.tier)}` };
64
134
  if (!slice.goal?.trim()) return { kind: 'blocked', reason: `empty-slice-goal: #${index + 1}` };
65
- if (slice.tier === '상' && !slice.unavoidable?.trim()) return { kind: 'blocked', reason: `unjustified-상-slice: #${index + 1}` };
66
135
  }
67
- const deviceSlices = result.slices.filter((slice) => slice.deviceFirst === 'device-test');
68
- if (deviceSlices.length === 0 && result.slices.some((slice) => slice.deviceFirst === 'feature'))
136
+ const slices = result.slices.map((slice) => slice.tier === '상'
137
+ ? { ...slice, unavoidable: slice.unavoidable?.trim() || 'auto' } : slice);
138
+ const deviceSlices = slices.filter((slice) => slice.deviceFirst === 'device-test');
139
+ if (deviceSlices.length === 0 && slices.some((slice) => slice.deviceFirst === 'feature'))
69
140
  return { kind: 'blocked', reason: 'device-first-stage-missing' };
70
- if (deviceSlices.length > 0 && (deviceSlices.length !== 1 || result.slices[0]?.deviceFirst !== 'device-test'
71
- || result.slices.slice(1).some((slice) => slice.deviceFirst !== 'feature')))
141
+ if (deviceSlices.length > 0 && (deviceSlices.length !== 1 || slices[0]?.deviceFirst !== 'device-test'
142
+ || slices.slice(1).some((slice) => slice.deviceFirst !== 'feature')))
72
143
  return { kind: 'blocked', reason: 'device-first-order-invalid' };
73
- return { kind: 'split', slices: result.slices };
144
+ return { kind: 'split', slices };
74
145
  }
75
146
 
76
147
  export interface TierSplitSliceOutcome { slice: SizedSlice; result?: HandTaskResult; error?: string }
@@ -111,19 +182,63 @@ export async function handTaskWithTierSplit(opts: TierSplitHandOptions): Promise
111
182
  record({ cid, fromTier, outcome: 'whole', reason: TIER_SPLIT_UNAVAILABLE, slices: [], unavoidable: [], ...acceptedSliceCounts([]) });
112
183
  return { kind: 'whole', result: await handTask(hand), reason: TIER_SPLIT_UNAVAILABLE };
113
184
  }
114
- let plan: TierSplitPlan;
115
- const controller = new AbortController();
116
- let timer: ReturnType<typeof setTimeout> | undefined;
117
- const timedOut = new Promise<'timeout'>((resolve) => { timer = setTimeout(() => { controller.abort(); resolve('timeout'); }, decomposeTimeoutMs); });
118
- try {
119
- const raced = await Promise.race([decompose(hand.text.trim(), { signal: controller.signal,
120
- ...(hand.project ? { repositoryRoot: resolve(hand.project.target) } : {}) }), timedOut]);
121
- plan = raced === 'timeout' ? { kind: 'blocked', reason: `decompose-timeout: ${decomposeTimeoutMs}ms` } : planTierSplit(raced);
122
- } catch (error) {
123
- plan = { kind: 'blocked', reason: `decompose-threw: ${String((error as Error)?.message ?? error).slice(0, 200)}` };
124
- } finally { clearTimeout(timer); }
185
+ const runDecompose = async (goal: string): Promise<{ plan: TierSplitPlan; result?: TierSizedDecomposeResult }> => {
186
+ const controller = new AbortController();
187
+ let timer: ReturnType<typeof setTimeout> | undefined;
188
+ const timedOut = new Promise<'timeout'>((resolve) => { timer = setTimeout(() => { controller.abort(); resolve('timeout'); }, decomposeTimeoutMs); });
189
+ try {
190
+ const raced = await Promise.race([decompose(goal, { signal: controller.signal,
191
+ ...(hand.project ? { repositoryRoot: resolve(hand.project.target) } : {}) }), timedOut]);
192
+ if (raced === 'timeout') return { plan: { kind: 'blocked', reason: `decompose-timeout: ${decomposeTimeoutMs}ms` } };
193
+ return { plan: planTierSplit(raced), result: raced };
194
+ } catch (error) {
195
+ return { plan: { kind: 'blocked', reason: `decompose-threw: ${String((error as Error)?.message ?? error).slice(0, 200)}` } };
196
+ } finally { clearTimeout(timer); }
197
+ };
198
+ const first = await runDecompose(hand.text.trim());
199
+ let plan = first.plan;
200
+ let decomposed = first.result;
201
+ const acceptance = parentAcceptanceLines(hand.text);
202
+ if (plan.kind === 'split') {
203
+ let candidateSlices = plan.slices;
204
+ let covered = coveredAcceptanceLines(candidateSlices, acceptance, hand.text, fromTier, cid);
205
+ let missing = acceptance.filter((line) => !covered.includes(line));
206
+ const inheritedByComposition = acceptance.filter((line) => INHERITED_PARENT_LABELS.test(line));
207
+ recordAcceptanceCoverage({ cid, fromTier, attempt: 1, coverageMode: 'exact-parent-line', inheritedByComposition, covered, missing });
208
+ if (missing.length > 0) {
209
+ const retryPrompt = `${hand.text.trim()}\n\n### 분해 필수 수용선\n각 조각의 "부모 수용선 몫"에 담당하는 원문 수용선 전체를 그대로 싣고, 조각들의 합집합으로 아래 모든 줄을 덮으세요.\n${missing.map((line) => `- ${line}`).join('\n')}`;
210
+ const retry = await runDecompose(retryPrompt);
211
+ if (retry.plan.kind === 'split') {
212
+ plan = retry.plan;
213
+ decomposed = retry.result;
214
+ candidateSlices = annotateAcceptanceShares(retry.plan.slices, acceptance);
215
+ }
216
+ covered = coveredAcceptanceLines(candidateSlices, acceptance, hand.text, fromTier, cid);
217
+ missing = acceptance.filter((line) => !covered.includes(line));
218
+ recordAcceptanceCoverage({ cid, fromTier, attempt: 2, coverageMode: 'exact-parent-line', inheritedByComposition, covered, missing,
219
+ retryReason: retry.plan.kind === 'blocked' ? retry.plan.reason : undefined });
220
+ let integratedAdded = false;
221
+ if (missing.length > 0) {
222
+ candidateSlices = [...candidateSlices, integratedAcceptanceSlice(hand.text, missing, candidateSlices)];
223
+ integratedAdded = true;
224
+ covered = coveredAcceptanceLines(candidateSlices, acceptance, hand.text, fromTier, cid);
225
+ missing = acceptance.filter((line) => !covered.includes(line));
226
+ }
227
+ candidateSlices = annotateAcceptanceShares(candidateSlices, acceptance, integratedAdded);
228
+ recordAcceptanceCoverage({ cid, fromTier, attempt: 'final', coverageMode: 'exact-parent-line', inheritedByComposition,
229
+ covered, missing, integrated: integratedAdded });
230
+ plan = { kind: 'split', slices: candidateSlices };
231
+ } else {
232
+ plan = { kind: 'split', slices: candidateSlices };
233
+ }
234
+ }
125
235
  if (plan.kind === 'blocked') {
126
- record({ cid, fromTier, outcome: 'blocked', reason: plan.reason, slices: [], unavoidable: [], ...acceptedSliceCounts([]) });
236
+ const rejectedOversized = decomposed?.ok
237
+ ? decomposed.slices.flatMap((slice, index) => slice.tier === '상' ? [{ index: index + 1, files: slice.files, behaviours: slice.behaviours }] : [])
238
+ : [];
239
+ record({ cid, fromTier, outcome: 'blocked', reason: plan.reason, slices: [], unavoidable: [],
240
+ ...(decomposed?.ok ? { redecomposed: decomposed.redecomposed } : {}),
241
+ rejectedOversized, rejectedOversizedCount: rejectedOversized.length, ...acceptedSliceCounts([]) });
127
242
  return { kind: 'blocked', result: await handTask({ ...hand, tierSplitBlocked: plan.reason }), reason: plan.reason };
128
243
  }
129
244
  const group = `${TASK_CARD_PREFIX}split-${randomBytes(4).toString('hex')}`;
@@ -132,7 +247,9 @@ export async function handTaskWithTierSplit(opts: TierSplitHandOptions): Promise
132
247
  const unavoidable = counts.unavoidableReasons;
133
248
  // 조각은 새 카드다 — 호출자 id·pr·goalId 를 조각마다 복제하면 «PR: #N» 조회·수확이 엇갈린다. 버린 것은 기록에 남긴다.
134
249
  const dropped = { ...(hand.id ? { id: hand.id } : {}), ...(hand.cardFields?.pr !== undefined ? { pr: hand.cardFields.pr } : {}), ...(hand.cardFields?.goalId !== undefined ? { goalId: hand.cardFields.goalId } : {}) };
135
- record({ cid, fromTier, outcome: 'split', group, ...(Object.keys(dropped).length ? { dropped } : {}), slices: plan.slices.map((s) => ({ tier: s.tier, files: s.files, behaviours: s.behaviours })), unavoidable: [...unavoidable],
250
+ record({ cid, fromTier, outcome: 'split', group, ...(Object.keys(dropped).length ? { dropped } : {}),
251
+ ...(decomposed?.ok ? { redecomposed: decomposed.redecomposed } : {}),
252
+ slices: plan.slices.map((s) => ({ tier: s.tier, files: s.files, behaviours: s.behaviours })), unavoidable: [...unavoidable],
136
253
  ...counts });
137
254
  const { id: _wholeId, cardFields, ...rest } = hand;
138
255
  const base = { ...rest, ...(cardFields?.handed !== undefined ? { cardFields: { handed: cardFields.handed } } : {}) };
@@ -181,7 +298,8 @@ export async function handTaskWithTierSplit(opts: TierSplitHandOptions): Promise
181
298
  markFirstLaunchFailure(reason);
182
299
  }
183
300
  }
184
- record({ cid, fromTier, outcome: 'device-first-deferred', group, first: ids[0], blockedUntilLanded: ids.slice(1) });
301
+ record({ cid, fromTier, outcome: 'device-first-deferred', group, first: ids[0], blockedUntilLanded: ids.slice(1),
302
+ unavoidable: [...unavoidable], ...counts });
185
303
  return { kind: 'split', group, fromTier, slices };
186
304
  }
187
305
  for (const [index, slice] of plan.slices.entries()) {
@@ -17,7 +17,7 @@ import { getDefaultLogStore, type LogStore } from '../../mss/logging/log-store.j
17
17
  import { podBunCacheVolume } from './pod-bun-cache.js';
18
18
  import { POD_JOB_TTL_AFTER_FINISHED_SECONDS } from './pod-lease.js';
19
19
  import { podHostDirsCheckScript, podInstallSlotsVolume, prepareHostDirsOnce, type HostDirsPrepResult, podHostDirsScript } from './pod-install-slots.js';
20
- import { type PodPoolMember, PodPoolScheduler, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, registryImageRef, type PoolKubectl } from './pod-pool.js';
20
+ import { type PodPoolMember, PodPoolScheduler, defaultRemoteRun, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, registryImageRef, type PoolKubectl } from './pod-pool.js';
21
21
  import { podSkillsDigest, readSkillEnvFiles, resolvePodSkills } from './pod-skills.js';
22
22
  import { podSourceScript, type PodSource } from './pod-source-receive.js';
23
23
  import { podProvenanceMetadata, type PodProvenance } from './pod-provenance.js';
@@ -108,6 +108,287 @@ export function memoryRequestWithin(limit: string | undefined): string {
108
108
  return request !== null && max !== null && request > max ? limit! : POD_COMMAND_MEMORY_REQUEST_DEFAULT;
109
109
  }
110
110
 
111
+ // ═══════════ POD-CPU-REQUEST-RIGHTSIZE-2-FU ═══════════
112
+ // CPU 요청량(기본 request 1)을 바꾸려면 «gate16+harness40 이 같은 호스트에서 함께 도는» 측정값이 있어야 한다.
113
+ // 그 측정을 내는 발사는 두 관문을 지난다 — ①발사 선행 조건(풀 슬롯·SSH·Pod admission·allocatable/request 기준선)을
114
+ // 먼저 읽어 기록하고 하나라도 불가하면 발사 0 · 사유 · HITL(local substrate 대체 없음) ②측정이 없는 같은 조건의
115
+ // 재발사 금지(run-477b2ee2·run-7bc13989 는 CPU 측정 전에 no-launch(pod-error)로 끝났다). 측정이 모자라면 yellow —
116
+ // 기본 요청량 그대로다.
117
+
118
+ /** POD-CPU-REQUEST-RIGHTSIZE-2-FU — 이 요청량을 정당화하는 공존 조건(게이트 조각 16 ⊕ 하니스 40 동시 실행). */
119
+ export const POD_RIGHTSIZE_CONDITION = 'gate16+harness40';
120
+ /** 측정 사용량 위에 남기는 여유 — 조정 요청량은 100m 단위로 올린다. */
121
+ export const POD_RIGHTSIZE_HEADROOM = 1.25;
122
+ /** 스케줄 대기가 이보다 길면 그 요청은 그 호스트에 «너무 크다» — 조정 사유에 원문을 남긴다. */
123
+ export const POD_RIGHTSIZE_WAIT_LIMIT_MS = 120_000;
124
+
125
+ /** 한 발사의 결과 기록 — `no-launch` 는 CPU 측정 «전에» 끝난 발사다(pod-error). */
126
+ export interface PodRightsizeLaunchRecord {
127
+ run: string;
128
+ condition: string;
129
+ outcome: 'no-launch' | 'launched';
130
+ reason?: string;
131
+ /** 그 발사가 CPU 사용량을 쟀나 — no-launch 면 false. */
132
+ cpuMeasured?: boolean;
133
+ }
134
+
135
+ /** run-477b2ee2·run-7bc13989 — CPU 측정 전에 no-launch(pod-error)로 끝나 gate16+harness40 공존 증거가 0 인 두 발사. */
136
+ export const POD_RIGHTSIZE_VOID_LAUNCHES: readonly PodRightsizeLaunchRecord[] = [
137
+ { run: 'run-477b2ee2', condition: POD_RIGHTSIZE_CONDITION, outcome: 'no-launch', reason: 'pod-error', cpuMeasured: false },
138
+ { run: 'run-7bc13989', condition: POD_RIGHTSIZE_CONDITION, outcome: 'no-launch', reason: 'pod-error', cpuMeasured: false },
139
+ ];
140
+
141
+ /** 동일 호스트 동시 실행 한 표본 — 요청량·사용량·스케줄 대기·eviction 원문을 그대로 든다. */
142
+ export interface PodCpuSample {
143
+ /** 이 표본을 낸 실행(게이트 조각 16 · 하니스 40). */
144
+ label: string;
145
+ /** 매니페스트에 실려 실제로 발사된 CPU 요청(millis). */
146
+ requestMillis: number;
147
+ /** 실행 중 측정된 CPU 사용량(millis) — 못 쟀으면 null. */
148
+ usageMillis: number | null;
149
+ /** 스케줄 대기(ms) — 못 쟀으면 null. */
150
+ waitMs: number | null;
151
+ /** eviction 원문(있으면 그대로 · 없으면 null/빈 문자열). */
152
+ eviction?: string | null;
153
+ }
154
+
155
+ /** `runPodCommand` 에 붙는 재측정 요청 — 어떤 조건의 표본인지, 앞선 발사 기록, 이번 발사의 호스트 이름. */
156
+ export interface PodCpuRightsizeRequest {
157
+ /** 공존 조건 이름 — 기본 {@link POD_RIGHTSIZE_CONDITION}. */
158
+ condition?: string;
159
+ /** 같은 호스트 동시 실행 표본. 비었거나 사용량을 못 쟀으면 yellow(기본 요청량 유지). */
160
+ samples?: readonly PodCpuSample[];
161
+ /** 앞선 발사 기록 — 기본 {@link POD_RIGHTSIZE_VOID_LAUNCHES}(측정 전 no-launch 두 건). */
162
+ priorLaunches?: readonly PodRightsizeLaunchRecord[];
163
+ /** 기록·사유에 남길 대상 호스트(없으면 임차한 멤버의 ssh 호스트). */
164
+ host?: string;
165
+ }
166
+
167
+ /**
168
+ * CLI(`elanous pod run --cpu-rightsize`)가 받는 JSON → 재측정 요청. `{ condition?, samples?, priorLaunches?, host? }` 만 받고
169
+ * 모르는 키·잘못된 수량은 사유와 함께 거부한다(발사 전에 막는다). 비었으면 undefined = 종전 발사.
170
+ */
171
+ export function parseCpuRightsizeRequest(value: unknown, label = 'cpuRightsize'): PodCpuRightsizeRequest | undefined {
172
+ if (value === undefined || value === null) return undefined;
173
+ if (typeof value !== 'object' || Array.isArray(value)) throw new Error(`${label} must be { condition?, samples?, priorLaunches?, host? }`);
174
+ const raw = value as Record<string, unknown>;
175
+ const unknownKeys = Object.keys(raw).filter((key) => !['condition', 'samples', 'priorLaunches', 'host'].includes(key));
176
+ if (unknownKeys.length) throw new Error(`${label} has unknown keys: ${unknownKeys.join(', ')}`);
177
+ const text = (v: unknown, key: string): string | undefined => {
178
+ if (v === undefined || v === null || v === '') return undefined;
179
+ if (typeof v !== 'string') throw new Error(`${label}.${key} must be a string`);
180
+ return v.trim() || undefined;
181
+ };
182
+ const millis = (v: unknown, key: string, allowZero = false): number | null => {
183
+ if (v === undefined || v === null) return null;
184
+ if (typeof v !== 'number' || !Number.isSafeInteger(v) || (allowZero ? v < 0 : v <= 0)) {
185
+ throw new Error(`${label}.${key} must be ${allowZero ? 'non-negative' : 'positive'} whole millicores`);
186
+ }
187
+ return v;
188
+ };
189
+ const sampleList = raw.samples === undefined || raw.samples === null ? [] : raw.samples;
190
+ if (!Array.isArray(sampleList)) throw new Error(`${label}.samples must be an array`);
191
+ const samples = sampleList.map((entry, i) => {
192
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) throw new Error(`${label}.samples[${i}] must be an object`);
193
+ const row = entry as Record<string, unknown>;
194
+ const name = text(row.label, `samples[${i}].label`);
195
+ if (!name) throw new Error(`${label}.samples[${i}].label is required`);
196
+ const requestMillis = millis(row.requestMillis, `samples[${i}].requestMillis`);
197
+ if (requestMillis === null) throw new Error(`${label}.samples[${i}].requestMillis is required`);
198
+ return {
199
+ label: name, requestMillis,
200
+ usageMillis: millis(row.usageMillis, `samples[${i}].usageMillis`),
201
+ waitMs: millis(row.waitMs, `samples[${i}].waitMs`, true),
202
+ eviction: text(row.eviction, `samples[${i}].eviction`) ?? null,
203
+ };
204
+ });
205
+ const launchList = raw.priorLaunches === undefined || raw.priorLaunches === null ? [] : raw.priorLaunches;
206
+ if (!Array.isArray(launchList)) throw new Error(`${label}.priorLaunches must be an array`);
207
+ const priorLaunches = launchList.map((entry, i) => {
208
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) throw new Error(`${label}.priorLaunches[${i}] must be an object`);
209
+ const row = entry as Record<string, unknown>;
210
+ const run = text(row.run, `priorLaunches[${i}].run`);
211
+ if (!run) throw new Error(`${label}.priorLaunches[${i}].run is required`);
212
+ const rawOutcome = row.outcome;
213
+ if (rawOutcome !== 'no-launch' && rawOutcome !== 'launched') throw new Error(`${label}.priorLaunches[${i}].outcome must be no-launch or launched`);
214
+ const outcome: 'no-launch' | 'launched' = rawOutcome === 'launched' ? 'launched' : 'no-launch';
215
+ const condition = text(row.condition, `priorLaunches[${i}].condition`) ?? POD_RIGHTSIZE_CONDITION;
216
+ const reason = text(row.reason, `priorLaunches[${i}].reason`);
217
+ return { run, condition, outcome, ...(reason ? { reason } : {}) };
218
+ });
219
+ const condition = text(raw.condition, 'condition');
220
+ const host = text(raw.host, 'host');
221
+ return {
222
+ ...(condition ? { condition } : {}),
223
+ samples,
224
+ ...(priorLaunches.length ? { priorLaunches } : {}),
225
+ ...(host ? { host } : {}),
226
+ };
227
+ }
228
+
229
+ /** millis → 쿠버네티스 수량(`2000` → `2` · `2800` → `2800m`). */
230
+ export function podCpuQuantity(millis: number): string {
231
+ if (!Number.isSafeInteger(millis) || millis <= 0) throw new Error(`pod cpu quantity needs positive millicores: ${millis}`);
232
+ return millis % 1000 === 0 ? String(millis / 1000) : `${millis}m`;
233
+ }
234
+
235
+ export interface PodCpuRightsizeVerdict {
236
+ /** green = 측정값이 요청량을 정한다 · yellow = 재측정 불가(기본 요청량 유지). */
237
+ status: 'green' | 'yellow';
238
+ /** 이번 발사에 실을 요청량(yellow 면 기본값). */
239
+ request: string;
240
+ requestMillis: number;
241
+ reason: string;
242
+ /** 판정에 쓴 표본(사용량을 잰 것만). */
243
+ measured: Array<{ label: string; requestMillis: number; usageMillis: number; waitMs: number | null; eviction: string | null }>;
244
+ }
245
+
246
+ /**
247
+ * 측정값 → 요청량. 표본이 하나도 없거나, 사용량을 못 쟀거나, eviction 원문이 있으면 yellow 로 기본 요청량을 지킨다
248
+ * (재측정 불가 = 결함 없음이 아니다). 그 밖에는 표본들의 최대 사용량 ⊕ 여유(POD_RIGHTSIZE_HEADROOM)를 100m 로
249
+ * 올린 값이 요청량이고, 한도(POD_COMMAND_CPU_LIMIT_DEFAULT)를 넘지 않는다.
250
+ */
251
+ export function podCpuRightsize(samples: readonly PodCpuSample[]): PodCpuRightsizeVerdict {
252
+ const yellow = (reason: string): PodCpuRightsizeVerdict => ({
253
+ status: 'yellow', request: POD_COMMAND_CPU_REQUEST_DEFAULT,
254
+ requestMillis: podCpuMillis(POD_COMMAND_CPU_REQUEST_DEFAULT)!, reason, measured: [],
255
+ });
256
+ if (samples.length === 0) return yellow('no same-host co-residency samples');
257
+ const evicted = samples.find((s) => (s.eviction ?? '').trim().length > 0);
258
+ if (evicted) return yellow(`eviction on ${evicted.label}: ${evicted.eviction!.trim().replace(/\s+/g, ' ').slice(0, 200)}`);
259
+ const unmeasured = samples.find((s) => s.usageMillis === null);
260
+ if (unmeasured) return yellow(`usage unmeasured on ${unmeasured.label}`);
261
+ const measured = samples.map((s) => ({
262
+ label: s.label, requestMillis: s.requestMillis, usageMillis: s.usageMillis!, waitMs: s.waitMs, eviction: null,
263
+ }));
264
+ const peak = Math.max(...measured.map((s) => s.usageMillis));
265
+ const limitMillis = podCpuMillis(POD_COMMAND_CPU_LIMIT_DEFAULT)!;
266
+ const sized = Math.min(Math.ceil((peak * POD_RIGHTSIZE_HEADROOM) / 100) * 100, limitMillis);
267
+ const waits = measured.map((s) => s.waitMs).filter((ms): ms is number => ms !== null);
268
+ const slow = waits.filter((ms) => ms > POD_RIGHTSIZE_WAIT_LIMIT_MS);
269
+ const waitNote = waits.length === 0
270
+ ? 'wait unreadable'
271
+ : `waited ${Math.max(...waits)}ms${slow.length ? ` (over ${POD_RIGHTSIZE_WAIT_LIMIT_MS}ms on ${slow.length})` : ''}`;
272
+ return {
273
+ status: 'green', request: podCpuQuantity(sized), requestMillis: sized,
274
+ reason: `peak usage ${peak}m over ${measured.length} samples · ${waitNote} · no eviction → request ${podCpuQuantity(sized)}`,
275
+ measured,
276
+ };
277
+ }
278
+
279
+ /**
280
+ * 같은 조건의 «무효 재발사» 금지 — 그 조건의 발사가 CPU 측정 전에 no-launch(pod-error)로 끝났고 아직 사용량을 잰
281
+ * 표본이 없으면, 같은 조건을 다시 쏘는 것은 같은 무효를 한 번 더 사는 일이다.
282
+ */
283
+ export function podRightsizeRefusal(o: {
284
+ condition: string;
285
+ samples: readonly PodCpuSample[];
286
+ priorLaunches?: readonly PodRightsizeLaunchRecord[];
287
+ }): { refused: boolean; reason: string; priorVoid: PodRightsizeLaunchRecord[] } {
288
+ // Only a no-launch that measured nothing is a void — a launch that died after a reading is not «no evidence».
289
+ const priorVoid = (o.priorLaunches ?? POD_RIGHTSIZE_VOID_LAUNCHES)
290
+ .filter((r) => r.condition === o.condition && r.outcome === 'no-launch' && r.cpuMeasured !== true);
291
+ if (priorVoid.length === 0) return { refused: false, reason: 'no no-launch record for this condition', priorVoid };
292
+ if (o.samples.some((s) => s.usageMillis !== null)) return { refused: false, reason: 'a measured sample exists', priorVoid };
293
+ const seen = priorVoid.map((r) => `${r.run}:${r.reason ?? r.outcome}`).join('·');
294
+ return {
295
+ refused: true,
296
+ reason: `same condition ${o.condition} re-launch refused — ${seen} ended before any CPU measurement`,
297
+ priorVoid,
298
+ };
299
+ }
300
+
301
+ /** 발사 선행 조건 기록 — 풀 슬롯 · SSH · Pod admission · allocatable/request 기준선. 하나라도 ok=false 면 발사하지 않는다. */
302
+ export interface PodLaunchPreconditions {
303
+ slots: { ok: boolean; ready: number; capacity: number; detail?: string };
304
+ ssh: { ok: boolean; host: string | null; detail?: string };
305
+ admission: { ok: boolean; detail?: string };
306
+ baseline: {
307
+ ok: boolean; node: string | null;
308
+ allocatableCpuMillis: number | null; requestedCpuMillis: number | null;
309
+ requestCpuMillis: number | null; freeCpuMillis: number | null;
310
+ detail?: string;
311
+ };
312
+ }
313
+
314
+ export interface PodLaunchPreconditionsDeps {
315
+ kubectl: Kubectl;
316
+ namespace: string;
317
+ member?: PodPoolMember | null;
318
+ /** 발사할 풀의 자리 — 풀이 없으면 null(단일 컨텍스트 하나). */
319
+ pool?: { ready: number; capacity: number } | null;
320
+ /** 이번 발사가 요청할 CPU(millis) — 기준선 여유와 비교한다. */
321
+ requestCpuMillis: number;
322
+ /** 원격 멤버 SSH 도달 시험. null/생략 = 못 잼(원격이면 불가로 센다). */
323
+ sshProbe?: ((host: string) => { status: number | null; stdout: string; stderr: string }) | null;
324
+ }
325
+
326
+ /** 대상 호스트의 선행 조건을 실제 클러스터에서 읽어 기록한다 — 판정하지 않고 «읽은 그대로» 남긴다. */
327
+ export function podLaunchPreconditions(o: PodLaunchPreconditionsDeps): PodLaunchPreconditions {
328
+ const slots: PodLaunchPreconditions['slots'] = o.pool
329
+ ? { ok: o.pool.ready > 0, ready: o.pool.ready, capacity: o.pool.capacity, ...(o.pool.ready > 0 ? {} : { detail: 'no ready pool member' }) }
330
+ : { ok: true, ready: 1, capacity: 1, detail: 'single context (no pool)' };
331
+
332
+ const host = o.member?.sshHost ?? null;
333
+ let ssh: PodLaunchPreconditions['ssh'];
334
+ if (!host) ssh = { ok: true, host: null, detail: 'this machine (no ssh)' };
335
+ else if (!o.sshProbe) ssh = { ok: false, host, detail: 'ssh probe unavailable' };
336
+ else {
337
+ const probed = o.sshProbe(host);
338
+ ssh = probed.status === 0
339
+ ? { ok: true, host }
340
+ : { ok: false, host, detail: (probed.stderr.trim().split('\n').pop() ?? '').slice(0, 200) || `ssh exit ${probed.status}` };
341
+ }
342
+
343
+ const cani = o.kubectl(['-n', o.namespace, 'auth', 'can-i', 'create', 'jobs.batch']);
344
+ const admission: PodLaunchPreconditions['admission'] = cani.status === 0 && /^yes$/i.test(cani.stdout.trim())
345
+ ? { ok: true, detail: 'can-i create jobs.batch' }
346
+ : { ok: false, detail: (cani.stderr.trim().split('\n').pop() ?? '').slice(0, 200) || `can-i ${cani.stdout.trim() || `exit ${cani.status}`}` };
347
+
348
+ const nodes = o.kubectl(['get', 'nodes', '-o', 'json']);
349
+ const pods = o.kubectl(['get', 'pods', '--all-namespaces', '-o', 'json']);
350
+ let allocatable: Array<{ name: string; cpu: number }> = [];
351
+ let perNode: Record<string, number> = {};
352
+ let baselineError: string | null = null;
353
+ try {
354
+ const parsed = JSON.parse(nodes.stdout) as { items?: Array<{ metadata?: { name?: string }; status?: { allocatable?: { cpu?: string } } }> };
355
+ allocatable = (parsed.items ?? []).flatMap((item) => {
356
+ const name = item.metadata?.name;
357
+ const cpu = podCpuMillis(item.status?.allocatable?.cpu ?? '');
358
+ return name && cpu !== null ? [{ name, cpu }] : [];
359
+ });
360
+ } catch { baselineError = `node list unreadable: ${(nodes.stderr.trim() || 'invalid json').slice(0, 200)}`; }
361
+ if (!baselineError) {
362
+ try {
363
+ const parsed = JSON.parse(pods.stdout) as { items?: Array<{ spec?: { nodeName?: string; containers?: Array<{ resources?: { requests?: { cpu?: string } } }> } }> };
364
+ for (const pod of parsed.items ?? []) {
365
+ const node = pod.spec?.nodeName;
366
+ if (!node) continue;
367
+ for (const container of pod.spec?.containers ?? []) {
368
+ perNode[node] = (perNode[node] ?? 0) + (podCpuMillis(container.resources?.requests?.cpu ?? '') ?? 0);
369
+ }
370
+ }
371
+ } catch { baselineError = `pod list unreadable: ${(pods.stderr.trim() || 'invalid json').slice(0, 200)}`; }
372
+ }
373
+ const ranked = [...allocatable]
374
+ .map((node) => ({ ...node, requested: perNode[node.name] ?? 0 }))
375
+ .sort((a, b) => (b.cpu - b.requested) - (a.cpu - a.requested) || a.name.localeCompare(b.name));
376
+ const chosen = baselineError ? undefined : ranked[0];
377
+ const baseline: PodLaunchPreconditions['baseline'] = !chosen
378
+ ? {
379
+ ok: false, node: null, allocatableCpuMillis: null, requestedCpuMillis: null,
380
+ requestCpuMillis: o.requestCpuMillis, freeCpuMillis: null,
381
+ detail: baselineError ?? (nodes.status !== 0 ? `node list exit ${nodes.status}` : 'no node reports an allocatable cpu'),
382
+ }
383
+ : {
384
+ ok: chosen.cpu - chosen.requested >= o.requestCpuMillis,
385
+ node: chosen.name, allocatableCpuMillis: chosen.cpu, requestedCpuMillis: chosen.requested,
386
+ requestCpuMillis: o.requestCpuMillis, freeCpuMillis: chosen.cpu - chosen.requested,
387
+ ...(chosen.cpu - chosen.requested >= o.requestCpuMillis ? {} : { detail: `free ${chosen.cpu - chosen.requested}m < request ${o.requestCpuMillis}m` }),
388
+ };
389
+ return { slots, ssh, admission, baseline };
390
+ }
391
+
111
392
  /** POD7 must-fix: the skill list alone can't tell a network-only job from one that needs ffmpeg/browser — so lite is
112
393
  * only ever chosen when the caller says so (`lite`), and then only for network skills without a clone. Anything we
113
394
  * can't judge keeps the full image. A lite request that doesn't fit is refused with the reason, not silently widened. */
@@ -429,6 +710,11 @@ export interface RunPodCommandOptions {
429
710
  memoryLimit?: string;
430
711
  /** GATE-SPEED A3①: CPU request/limit override — only the release gate passes it. Omitted = request 1 / limit 4. */
431
712
  cpu?: PodCpu;
713
+ /**
714
+ * POD-CPU-REQUEST-RIGHTSIZE-2-FU — this launch is a co-residency CPU measurement (게이트 조각 16 ⊕ 하니스 40 on one host).
715
+ * Omitted callers keep today's behaviour byte for byte: no precondition read, no measurement-driven request.
716
+ */
717
+ cpuRightsize?: PodCpuRightsizeRequest;
432
718
  /** W5 — memory-backed TMPDIR sizeLimit mounted at {@link POD_TMPFS_MOUNT_PATH}; only the release gate passes it. Omitted = image `/tmp`. */
433
719
  tmpfsSizeLimit?: string;
434
720
  /** POD7: 호출부가 «네트워크 스킬만 쓰는 명령»이라고 말할 때만 lite 이미지 ⊕ 2Gi. */
@@ -465,6 +751,8 @@ export interface RunPodCommandOptions {
465
751
  mirrorSeedCwd?: string;
466
752
  /** GATE-WARM-BOOT-NO-INIT — hands the hostPath dirs to uid 1000 on the member's nodes (test seam · default {@link prepareHostDirsOnce}). */
467
753
  prepareHostDirs?: (o: { member: PodPoolMember; hostPaths: readonly string[] }) => Promise<HostDirsPrepResult | undefined>;
754
+ /** POD-CPU-REQUEST-RIGHTSIZE-2-FU — SSH 도달 시험(test seam · 기본 `ssh <host> true`; 주입된 kubectl 이면 기본 없음). */
755
+ sshProbe?: (host: string) => { status: number | null; stdout: string; stderr: string };
468
756
  checkPool?: typeof checkPodPool;
469
757
  syncImages?: typeof syncPoolImages;
470
758
  imageCommit?: string | null;
@@ -641,9 +929,48 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
641
929
  const artifactRoot = options.artifactsRoot ?? `${effectiveInstanceRoot()}/pod-artifacts`;
642
930
  const artifactsDir = `${artifactRoot}/${name}`;
643
931
  let jobApplied = false;
932
+ /** POD-CPU-REQUEST-RIGHTSIZE-2-FU — 측정값이 정한 요청량(yellow 면 undefined = 기본값 그대로). */
933
+ let rightsizeCpu: PodCpu | undefined;
644
934
  try {
645
935
  ensureLive();
646
936
  if (!context && !options.kubectl) throw new Error('pod command: kubectl context 를 확인할 수 없다');
937
+ if (options.cpuRightsize) {
938
+ const condition = options.cpuRightsize.condition?.trim() || POD_RIGHTSIZE_CONDITION;
939
+ const samples = [...(options.cpuRightsize.samples ?? [])];
940
+ const priorLaunches = [...(options.cpuRightsize.priorLaunches ?? POD_RIGHTSIZE_VOID_LAUNCHES)];
941
+ const targetHost = options.cpuRightsize.host?.trim() || member?.sshHost || null;
942
+ // A no-launch(pod-error) run never produced a reading — firing the same condition again would buy the same void.
943
+ const refusal = podRightsizeRefusal({ condition, samples, priorLaunches });
944
+ if (refusal.refused) {
945
+ log('pod.command-job', 'rightsize-relaunch-refused', {
946
+ condition, host: targetHost, reason: refusal.reason, substrate: 'pod', launched: false, fallback: 'none',
947
+ hitl: true, priorVoid: refusal.priorVoid,
948
+ });
949
+ throw new Error(`pod command: ${refusal.reason}`);
950
+ }
951
+ const requestCpuMillis = podCpuMillis(resolvePodCpu(options.cpu).request)!;
952
+ const members = (pool as { members?: readonly PodPoolMember[] } | undefined)?.members;
953
+ const preconditions = podLaunchPreconditions({
954
+ kubectl, namespace, member,
955
+ pool: members ? { ready: members.filter((m) => m.capacity > 0).length, capacity: members.reduce((sum, m) => sum + Math.max(0, m.capacity), 0) } : null,
956
+ requestCpuMillis,
957
+ sshProbe: options.sshProbe ?? (options.kubectl ? null : (host) => defaultRemoteRun(host, 'true')),
958
+ });
959
+ log('pod.command-job', 'rightsize-preconditions', { condition, host: targetHost, job: name, context, preconditions });
960
+ const blocked = (['slots', 'ssh', 'admission', 'baseline'] as const).filter((key) => !preconditions[key].ok);
961
+ if (blocked.length) {
962
+ log('pod.command-job', 'rightsize-launch-refused', {
963
+ condition, host: targetHost, job: name, context, blocked, preconditions,
964
+ substrate: 'pod', launched: false, fallback: 'none', hitl: true,
965
+ });
966
+ throw new Error(`pod command: 발사 선행 조건 미충족(${blocked.join(', ')}) — 발사 0 · HITL`);
967
+ }
968
+ const verdict = podCpuRightsize(samples);
969
+ log('pod.command-job', 'cpu-rightsize', {
970
+ condition, host: targetHost, job: name, status: verdict.status, request: verdict.request, reason: verdict.reason, samples: verdict.measured,
971
+ });
972
+ if (verdict.status === 'green') rightsizeCpu = { request: verdict.request };
973
+ }
647
974
  let grokAuth: string | undefined;
648
975
  if (llm === 'grok') {
649
976
  // POD-GROK-VALIDITY-FIT — this Job's deadline is not fitted to the token, so the copy must outlive the whole Job.
@@ -750,12 +1077,13 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
750
1077
  const applied = kubectl(['apply', '-f', '-'], JSON.stringify(secret));
751
1078
  if (applied.status !== 0) throw new Error(applied.stderr.trim() || 'pod command: Secret 적용 실패');
752
1079
  }
1080
+ const effectiveCpu = options.cpu ?? rightsizeCpu;
753
1081
  const manifest = podCommandJobManifest({
754
1082
  name, namespace, launch, image: imageRef ?? image,
755
1083
  provenance: options.provenance, provenanceGate: options.provenanceGate,
756
1084
  ...(imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
757
1085
  repoUrl, command, skills, ...(options.returnLogs ? { returnLogs: true } : {}), ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
758
- ...(options.source ? { source: options.source } : {}), ...(options.warmProducer ? { warmFiles: options.warmProducer.files } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(options.cpu ? { cpu: options.cpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
1086
+ ...(options.source ? { source: options.source } : {}), ...(options.warmProducer ? { warmFiles: options.warmProducer.files } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(installSlots ? { installSlots } : {}), ...(memoryLimit ? { memoryLimit } : {}), ...(effectiveCpu ? { cpu: effectiveCpu } : {}), ...(options.tmpfsSizeLimit ? { tmpfsSizeLimit: options.tmpfsSizeLimit } : {}), deadlineSeconds,
759
1087
  ...(options.runId ? { runId: options.runId } : {}),
760
1088
  ...(hostDirsInit ? { hostDirsInit: true } : {}),
761
1089
  });