elanous 0.2.19 → 0.2.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/MObU8ujkMciAKr6ljAV05/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/088d8e8a.8069543d082bec12.js +160 -0
  5. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +148 -0
  6. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/119fc678.6f591cdb84ca5791.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +309 -0
  9. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 1268.0840ff91e083fcbd.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1307-c97eba9fb72a9a5e.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +122 -0
  12. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +149 -0
  13. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +79 -0
  14. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +24 -0
  16. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +27 -0
  21. package/apps/pwa/out/_next/static/chunks/1948.5f35b39eef222a94.js +5 -0
  22. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{2977-e38442e86289f1d3.js → 211-9c9090c59e2c5907.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +36 -0
  31. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +286 -0
  32. package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +94 -0
  45. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/3522-1de1319d028ac89c.js +25 -0
  49. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +74 -0
  54. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +34 -0
  59. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +115 -0
  61. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/4588.ad3364cb7fb97ada.js +86 -0
  63. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +77 -0
  66. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +90 -0
  70. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5977-59fedea50d13c762.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +8 -0
  75. package/apps/pwa/out/_next/static/chunks/{4847.56f5bc454fbcc827.js → 6110.1297d4093fdfbb0d.js} +2 -2
  76. package/apps/pwa/out/_next/static/chunks/6158.566c890adc06a459.js +2 -0
  77. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +64 -0
  78. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +287 -0
  80. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +226 -0
  81. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6767.8e6c5f6e744fcd9f.js +38 -0
  83. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7175-350f4ce2873bc038.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +41 -0
  91. package/apps/pwa/out/_next/static/chunks/{1470.98a6ab61ccb4131c.js → 726.83532d69452ee24b.js} +1 -1
  92. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 7327-2d69fb321ba73389.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +24 -0
  95. package/apps/pwa/out/_next/static/chunks/7630.2b9a68659053ff4e.js +193 -0
  96. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/7899.597af4a9996c907f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/79b78388.663188133449d707.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8194.484f51e273d9abd2.js +217 -0
  105. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +104 -0
  109. package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/88729267.9c6c000157c83f2f.js +62 -0
  111. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +93 -0
  113. package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{7647.2fcd30d894d5ee30.js → 935.4ddaa99fc1d1126c.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +23 -0
  118. package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +62 -0
  120. package/apps/pwa/out/_next/static/chunks/9832.2ab2e818013574c7.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/a9f2b54d-40c16bd0efdb04b8.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-111cabe4d1fd69ae.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/{page-b70cd005d9169e25.js → page-be8b4615c919e36c.js} +1 -1
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-f23484de467c9ea3.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/d70879db.c66c56a95a91efc6.js +66 -0
  174. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → f6231284-45726550aba08fca.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/{2ea96958.e8c7e112de50b067.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/f8626309.a4e5d362b1d55e59.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +1 -0
  183. package/apps/pwa/out/_next/static/css/{d3427996da11e480.css → b9d8151e48998417.css} +1 -1
  184. package/apps/pwa/out/_next/static/css/e81df11490b4413b.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +24 -24
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +23 -23
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -0
  223. package/apps/pwa/out/live-run/index.txt +35 -0
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/graphs/demo/editor-recipes.yaml +22 -0
  279. package/graphs/drafts/recipes.yaml +4 -4
  280. package/graphs/implement-loop.yaml +277 -5
  281. package/graphs/retro/daily.yaml +25 -0
  282. package/graphs/retro/recipes.yaml +24 -0
  283. package/package.json +1 -1
  284. package/scripts/ask-marker-check.ts +3 -1
  285. package/scripts/coord-channel-watch.sh +31 -4
  286. package/scripts/docs-lint.ts +4 -1
  287. package/scripts/land-global-checks.ts +89 -0
  288. package/scripts/lib/pch-regress-map.ts +2 -1
  289. package/scripts/marketing/generate-ax-brief.ts +18 -1
  290. package/scripts/measure-nl-routing-corpus.ts +11 -3
  291. package/scripts/release-loop/gate-node.ts +296 -25
  292. package/scripts/release-loop/gate-timing.ts +116 -7
  293. package/scripts/release-loop/preflight.ts +6 -4
  294. package/scripts/release-loop/publish-window.ts +141 -0
  295. package/scripts/release-loop/release-docs.ts +1 -4
  296. package/scripts/release-loop/release-universe.ts +38 -0
  297. package/scripts/release-loop/resume-release.ts +4 -1
  298. package/scripts/release-loop/shard-plan.ts +50 -5
  299. package/scripts/release-loop/unattended-release.ts +10 -2
  300. package/scripts/release-story/draft.ts +5 -1
  301. package/scripts/retro/shadow-compare.ts +71 -0
  302. package/scripts/rhythm/daily.ts +8 -2
  303. package/src/agent-mission/driver.ts +34 -6
  304. package/src/autopilot/build/llm-conflict-merge.ts +132 -7
  305. package/src/autopilot/build/merge-intent.ts +135 -7
  306. package/src/away/release-watch.ts +20 -3
  307. package/src/browser-cdp/client.ts +10 -5
  308. package/src/cli/config-drift.ts +513 -0
  309. package/src/cli/log-event-names.ts +4 -0
  310. package/src/cli/ops-cli.ts +11 -0
  311. package/src/cli/ops-overview-cli.ts +50 -0
  312. package/src/cli/pod-cli.ts +1 -0
  313. package/src/cli/pr-cli.ts +20 -0
  314. package/src/cli/release-cli.ts +20 -5
  315. package/src/cli/retro-cli.ts +78 -0
  316. package/src/cli/tasks-cli.ts +200 -8
  317. package/src/dashboard/index.ts +40 -4
  318. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -4
  319. package/src/dashboard/slash-runtime/help-from-registry.ts +57 -31
  320. package/src/domains/outbound-log-probe.ts +6 -1
  321. package/src/esc-abort-gate.ts +3 -1
  322. package/src/graph-runner/graph-cli.ts +57 -0
  323. package/src/graph-runner/graph-run-api.ts +218 -0
  324. package/src/graph-runner/runner.ts +11 -1
  325. package/src/graph-wizard/archetypes.ts +88 -0
  326. package/src/graph-wizard/generate.ts +545 -0
  327. package/src/graph-wizard/saved-steps.ts +120 -0
  328. package/src/graph-wizard/steps.ts +193 -0
  329. package/src/harness/harness-cli-command.ts +482 -59
  330. package/src/harness/harness-queue.ts +315 -25
  331. package/src/harness/harness-salvage-cli.ts +62 -0
  332. package/src/hq/fence-outcomes.ts +63 -0
  333. package/src/hq/fence-wrapper.ts +33 -0
  334. package/src/hq/hq.ts +11 -1
  335. package/src/index.ts +76 -10
  336. package/src/intake-plane/digest.ts +18 -11
  337. package/src/maturity/feature-maturity.ts +4 -3
  338. package/src/nexus/api/draft-metrics.ts +114 -0
  339. package/src/nexus/api/graph-kinds.ts +10 -4
  340. package/src/nexus/api/graph-wizard-api.ts +53 -0
  341. package/src/nexus/api/graphs-api.ts +220 -10
  342. package/src/nexus/api/harness-traversal.ts +205 -0
  343. package/src/nexus/api/http-server.ts +69 -3
  344. package/src/nexus/api/loop-edges.ts +4 -2
  345. package/src/nexus/api/ops-api.ts +22 -7
  346. package/src/nexus/api/ops-board-route.ts +48 -0
  347. package/src/nexus/outbound/router.ts +28 -8
  348. package/src/onboarding/entry-hints.ts +5 -0
  349. package/src/onboarding/first-run.ts +3 -0
  350. package/src/onboarding.ts +24 -6
  351. package/src/ops/overview-collect.ts +345 -0
  352. package/src/ops/overview-seat-era.ts +90 -0
  353. package/src/ops/overview.ts +223 -0
  354. package/src/release-loop/feature-store.ts +14 -11
  355. package/src/release-loop/gate-shards.ts +163 -0
  356. package/src/release-loop/release-schedule.ts +6 -2
  357. package/src/retro/daily.ts +372 -0
  358. package/src/seat-loop/op-decide.ts +173 -0
  359. package/src/seat-loop/seat-loop.ts +60 -3
  360. package/src/seat-loop/seat-report.ts +58 -3
  361. package/src/self-dev/ask-launch-flow.ts +9 -6
  362. package/src/self-dev/ask-launch-io.ts +52 -2
  363. package/src/self-dev/ask-path-candidates.ts +40 -2
  364. package/src/self-dev/draft-sweep.ts +371 -16
  365. package/src/self-dev/draft-triage-rules.ts +19 -4
  366. package/src/self-dev/graph-journey-nodes.ts +157 -0
  367. package/src/self-dev/graph-journey-route.ts +105 -0
  368. package/src/self-dev/launch-preflight.ts +43 -3
  369. package/src/self-dev/pr-preview.ts +84 -16
  370. package/src/self-dev/release-path-guard.ts +7 -4
  371. package/src/self-implement/blocked-draft-policy.ts +101 -0
  372. package/src/self-implement/execution-clarification.ts +11 -0
  373. package/src/self-implement/frozen-merges.ts +23 -0
  374. package/src/self-implement/gate-env-retry.ts +83 -0
  375. package/src/self-implement/goal-author.ts +14 -0
  376. package/src/self-implement/heal-intake.ts +3 -0
  377. package/src/self-implement/orchestrator.ts +234 -6
  378. package/src/self-implement/run-stop.ts +123 -0
  379. package/src/self-implement/run-ttl.ts +258 -0
  380. package/src/self-implement/salvage-retention.ts +123 -0
  381. package/src/self-implement/seams.ts +7 -0
  382. package/src/self-implement/self-implement-cli.ts +2 -0
  383. package/src/self-implement/self-implement-runtime.ts +12 -0
  384. package/src/self-implement/sibling-resync.ts +223 -0
  385. package/src/self-implement/stop-autoheal.ts +204 -0
  386. package/src/session-runtime/index.ts +5 -3
  387. package/src/shell-env-bootstrap.ts +17 -3
  388. package/src/task-agent/board.ts +1 -1
  389. package/src/task-agent/card-evidence.ts +105 -10
  390. package/src/task-agent/judge.ts +7 -0
  391. package/src/task-agent/live-moves.ts +120 -20
  392. package/src/task-agent/mission.ts +1 -1
  393. package/src/task-agent/parent-host.ts +315 -0
  394. package/src/task-agent/shadow.ts +10 -1
  395. package/src/task-agent/task-hand.ts +16 -4
  396. package/src/task-orchestrator/surfaces/pod-command-job.ts +60 -11
  397. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +4 -0
  398. package/src/task-orchestrator/surfaces/pod-gate-deps.ts +123 -0
  399. package/src/task-orchestrator/surfaces/pod-install-slots.ts +89 -0
  400. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -10
  401. package/src/task-orchestrator/surfaces/pod-pool.ts +147 -34
  402. package/src/task-orchestrator/surfaces/self-implement-pod.ts +58 -9
  403. package/src/telegram-commands.ts +41 -0
  404. package/src/testing/real-cli-spawn.ts +106 -0
  405. package/src/tool-runtime/browser-runtime.ts +87 -3
  406. package/src/tool-runtime/index.ts +1 -0
  407. package/src/user-config.ts +76 -7
  408. package/src/version/packed-revision.json +1 -1
  409. package/apps/pwa/out/_next/static/J5H7BvqgSI8DUjtRRcA_S/_buildManifest.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/1157-cba0e8553d35a980.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/171-23a877ed11720de9.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/2336-e830c777eb6bce04.js +0 -1
  416. package/apps/pwa/out/_next/static/chunks/2375-e061bb24cd2b5cde.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/3094.67339318c7f72a3a.js +0 -2
  419. package/apps/pwa/out/_next/static/chunks/338-ceb956612dcfaa86.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/3395-835e4ceaa6335ba4.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  422. package/apps/pwa/out/_next/static/chunks/3441-be82e3595aef3a20.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/3689-89905039bf3e7257.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/3822-6f268bc26c6a84ac.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/4457-d7df81c90f9d0268.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/4551-77dadae76f6cbace.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/4978.6fd93b974441e87f.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/5012-f746f6549b869f91.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/62-5bfed1e23790b745.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/6320-9bc8561fde416e07.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/649-ca96d1c5d09e02b8.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/6726-85a7db59b288c53f.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/6735-33267c4630d0d963.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/7633-141682015873beb6.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/8067-143791231c99bd02.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/8430-a10cfba8ef282d4e.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/8870-9614a213b990b10b.js +0 -25
  447. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/9454-12c2f30dea62291c.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/976-4a9b4ebdca7c739a.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/9989-15cdf568bafa9fc8.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/ae787e4c-e5b1ef00b2dbceca.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/app/approvals/page-deef5ee191830f14.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-b193da485f9a14b2.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/app/board/page-b6e1a79df0e214f4.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/app/botlab/page-e84df4d907f703c7.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/app/bots/page-a5fb9a5db89ae4ea.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/app/ceo/page-1499f481d7fc52d6.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/app/chat/page-c7cf753aeb648790.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/app/consult/page-4118469e514e10fd.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/app/control/page-e968f7630654332a.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/app/decisions/page-505915052f947022.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c2f962fb4a3b06c6.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/app/editor/page-7b5ed0bd8a589ec4.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/app/exec/page-cf8193250dd42dd4.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/app/field/page-cf3f5dfa35dea8e9.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/app/inside/page-5b29d9b06ceadade.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/app/intake/page-a15e7fcc283e9ca7.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/app/layout-d2915e7b70ff3d0e.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/loops/page-2595f0eba29f57e1.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/app/market/page-c776322454156e36.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-77bbd17f4435aa10.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/app/morning/page-049689e611ecc936.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/app/not-found-85954a4fb09c44eb.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e773e552e1068ee6.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5633c4bfa7684b4a.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d829b92bd01b4994.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-061c317fc771becf.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a45ece8865ed4b6.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/app/page-0be990618c0d56bd.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/app/reflection/page-bfea4865dc244b73.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d6ba8e337741484.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/app/sessions/page-76a88b55d816482e.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-bba1542df59f61ce.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/app/settings/page-4185c95689bb372e.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b699e1a8d5d34b8b.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/app/setup/page-c225e338c31bf274.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/app/share/page-449353f70507ca1f.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/app/showroom/page-90b889714102476d.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f1ee7fbeb7f96ddc.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/app/term/page-d59a95e1434dfaa0.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/app/today/page-71491a23414d1a47.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/app/trace/page-de7112bdb65fa4fe.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/app/vault/page-feb4d0d88079660d.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f17d887b40dd6b1d.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/workflows/page-8da77be2192bcd5d.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72c3b9a5e9582b29.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3afe4c8d0c48c39.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/main-app-b9308f2d8a931531.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/webpack-6f35f9d892fa630b.js +0 -1
  507. package/apps/pwa/out/_next/static/css/85f53c6f35d11382.css +0 -1
  508. /package/apps/pwa/out/_next/static/{J5H7BvqgSI8DUjtRRcA_S → MObU8ujkMciAKr6ljAV05}/_ssgManifest.js +0 -0
  509. /package/skills/project-onboarding/{skill.md → SKILL.md} +0 -0
@@ -0,0 +1,157 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { debug } from '../debug/log.js';
3
+ import { GRAPH_SPECS, GRAPH_TEMPLATES, GRAPH_TEMPLATES_SOURCE, pipelineNodeEntryPayload, templateForGoalType, type GraphTemplate } from '../self-implement/graph-templates.js';
4
+ import type { GoalType } from '../self-implement/goal-author.js';
5
+
6
+ /** ⭐ HARNESS-FULL-GRAPH (0.2.21 · 대표 10-08) — 하니스 «여정» 전 단계를 그래프 노드로 선언·관측한다.
7
+ *
8
+ * 🩸 계기: `내부 문서 `TECH-harness-map-2026-10-06`` 차트의 단계 중 «입구·대기열·발사 관문·배치·Pod 입장·
9
+ * 이미지 동기화·자격 선갱신·동결 검사·보류·회수·실패 쪽(결과 해석·수확·heal·다음 한 수)»이
10
+ * 그래프 밖의 «맨 코드»였다. 공개 문서는 「그래프 선언이 모든 걸음을 대조한다」고 말한다 — 거짓이 되지 않게.
11
+ *
12
+ * ⛔ 이 모듈은 «관측»이다(1단계) — 흐름을 바꾸지 않는다. 진입은 기존 노드와 «같은 사건»
13
+ * (`self-implement` / `pipeline-node-entry` · 같은 `pipelineNodeEntryPayload`)으로 남겨
14
+ * 그래프 권위의 declared/undeclared 판정과 원장 질의가 이 노드들을 «같은 자»로 본다.
15
+ * 출구는 `pipeline-node-exit`(결과 `outcome` 포함)로 남긴다.
16
+ * ⛔ fail-soft — 관측이 발사·착지를 죽이지 않는다.
17
+ *
18
+ * 🔗 조인(런 id 가 없는 앞단): 입구에서 `ELANOUS_JOURNEY_KEY` 를 한 번 만들어 환경에 싣는다.
19
+ * 자식 프로세스는 그 값을 물려받고, 오케스트레이터의 모든 파이프라인 관측에도 `journeyKey` 가 실린다.
20
+ * ⇒ `journeyKey` 로 「runId 없이 남은 앞단 걸음」과 「runId 가 있는 후반 걸음」을 한 질의로 묶는다.
21
+ * 대기열을 거친 발사는 부모·자식 프로세스가 다르다 — 그 자리는 `queueLaunchId`(=`ELANOUS_HARNESS_QUEUE_LAUNCH`)가 잇는다.
22
+ * 설계 = 내부 문서 `RFC-harness-full-journey-as-graph-2026-10-08` §4. */
23
+
24
+ /** 여정 노드 — ⛔ id 는 원장의 조인 키이자 라이브 그래프 화면(HARNESS-RUN-LIVE-GRAPH)의 키다. 바꾸지 마라. */
25
+ export const JOURNEY_NODE_IDS = [
26
+ 'intake',
27
+ 'queue',
28
+ 'launch-gate',
29
+ 'dispatch',
30
+ 'pool-admit',
31
+ 'image-sync',
32
+ 'credential-refresh',
33
+ 'freeze-check',
34
+ 'hold',
35
+ 'cleanup',
36
+ 'result-parse',
37
+ 'salvage',
38
+ 'heal',
39
+ 'next-move',
40
+ 'stopped',
41
+ ] as const;
42
+ export type JourneyNodeId = typeof JOURNEY_NODE_IDS[number];
43
+
44
+ export const JOURNEY_KEY_ENV = 'ELANOUS_JOURNEY_KEY';
45
+ const QUEUE_LAUNCH_ENV = 'ELANOUS_HARNESS_QUEUE_LAUNCH';
46
+ const RUN_ID_ENV = 'ELANOUS_RUN_ID';
47
+
48
+ /** 이 여정의 조인 키 — 없으면 만들어 환경에 싣는다(자식이 물려받는다). */
49
+ export function ensureJourneyKey(env: NodeJS.ProcessEnv = process.env): string {
50
+ const existing = env[JOURNEY_KEY_ENV]?.trim();
51
+ if (existing) return existing;
52
+ const key = `jrn-${randomUUID()}`;
53
+ env[JOURNEY_KEY_ENV] = key;
54
+ return key;
55
+ }
56
+
57
+ /** 관측 자리마다 펼치는 조인 칸(있는 것만). */
58
+ export function journeyJoinFields(env: NodeJS.ProcessEnv = process.env): { journeyKey?: string; queueLaunchId?: string } {
59
+ const journeyKey = env[JOURNEY_KEY_ENV]?.trim();
60
+ const queueLaunchId = env[QUEUE_LAUNCH_ENV]?.trim();
61
+ return {
62
+ ...(journeyKey ? { journeyKey } : {}),
63
+ ...(queueLaunchId ? { queueLaunchId } : {}),
64
+ };
65
+ }
66
+
67
+ /** 여정 노드를 선언한 템플릿 — 골 종류의 템플릿이 그 노드를 선언하면 그것, 아니면 구현 루프. */
68
+ export function journeyTemplate(node: string, goalType?: GoalType | null): GraphTemplate {
69
+ const own = goalType ? templateForGoalType(goalType) : null;
70
+ if (own && own.nodes.some((n) => n.nodeId === node)) return own;
71
+ return GRAPH_TEMPLATES['self-implement'] as GraphTemplate;
72
+ }
73
+
74
+ export interface JourneyObservation {
75
+ readonly provenance: string;
76
+ readonly outcome?: string;
77
+ readonly runId?: string;
78
+ readonly goalType?: GoalType | null;
79
+ readonly data?: Readonly<Record<string, unknown>>;
80
+ }
81
+
82
+ function emit(entry: boolean, node: JourneyNodeId, o: JourneyObservation): void {
83
+ try {
84
+ const template = journeyTemplate(node, o.goalType);
85
+ const runId = o.runId ?? process.env[RUN_ID_ENV]?.trim();
86
+ const fields = {
87
+ node,
88
+ round: 0,
89
+ phase: 'journey',
90
+ provenance: o.provenance,
91
+ ...(o.outcome === undefined ? {} : { outcome: o.outcome }),
92
+ ...(runId ? { runId } : {}),
93
+ ...(o.goalType ? { goalType: o.goalType } : {}),
94
+ ...journeyJoinFields(),
95
+ ...o.data,
96
+ graphTemplatesSource: GRAPH_TEMPLATES_SOURCE,
97
+ };
98
+ // ⛔ 진입은 «공용 payload» 를 그 호출 안에서 펼친다 — 우회 가드(graph-templates.ts)가 행 단위로 문다.
99
+ if (entry) debug.log('self-implement', 'pipeline-node-entry', { ...pipelineNodeEntryPayload(template, node), ...fields });
100
+ else debug.log('self-implement', 'pipeline-node-exit', { ...pipelineNodeEntryPayload(template, node), ...fields });
101
+ } catch { /* 관측은 fail-soft */ }
102
+ }
103
+
104
+ /** 노드 진입. */
105
+ export function enterJourneyNode(node: JourneyNodeId, o: JourneyObservation): void {
106
+ emit(true, node, o);
107
+ }
108
+
109
+ /** 노드 출구 — `outcome` 이 그 노드에서 나간 간선의 라벨(YAML `map` 키)이다.
110
+ * ⭐ 그 라벨이 선언에서 종결 노드 `stopped` 로 가면 `stopped` 진입도 남긴다 — 거절·포기 런이 «선언된 종결점»에서 끝난다.
111
+ * `outcome: 'error'` = 노드 안 작업이 예외를 던졌다(예외는 호출자에게 그대로 간다). */
112
+ export function exitJourneyNode(node: JourneyNodeId, o: JourneyObservation & { readonly outcome: string }): void {
113
+ emit(false, node, o);
114
+ if (node !== 'stopped' && journeyEdgeTarget(node, o.outcome) === 'stopped') {
115
+ const { outcome: _outcome, ...rest } = o;
116
+ emit(true, 'stopped', { ...rest, provenance: `${node}:${o.outcome}` });
117
+ }
118
+ }
119
+
120
+ /** 선언(기준 YAML)에서 `from` 의 `label` 간선이 가는 노드. 없으면 undefined. */
121
+ export function journeyEdgeTarget(from: string, label: string): string | undefined {
122
+ try {
123
+ for (const edge of GRAPH_SPECS['self-implement']?.edges ?? []) {
124
+ if (edge.from === from && edge.map !== undefined && Object.hasOwn(edge.map, label)) return edge.map[label];
125
+ }
126
+ } catch { /* 관측 보조 — 실패해도 출구는 이미 남았다 */ }
127
+ return undefined;
128
+ }
129
+
130
+ /** 노드 안 작업을 감싼다 — 예외면 출구 `error` 를 남기고 다시 던진다(진입 뒤 출구가 빠지지 않게). */
131
+ export function withJourneyNode<T>(node: JourneyNodeId, o: JourneyObservation, work: () => Promise<T>): Promise<T> {
132
+ const onError = (error: unknown): void => {
133
+ exitJourneyNode(node, { ...o, outcome: 'error', data: { ...o.data, error: error instanceof Error ? error.message : String(error) } });
134
+ };
135
+ let pending: Promise<T>;
136
+ try { pending = work(); }
137
+ catch (error) { onError(error); throw error; }
138
+ // ⛔ 같은 약속을 «그대로» 돌려준다 — async/await 로 감싸면 마이크로태스크가 늘어 호출자의 순서가 밀린다
139
+ // (2판에서 self-implement-pod 시험이 그 차이를 잡았다). 관측은 곁가지(.then)로만 붙인다.
140
+ pending.then(undefined, onError);
141
+ return pending;
142
+ }
143
+
144
+ /** 동기 판. */
145
+ export function withJourneyNodeSync<T>(node: JourneyNodeId, o: JourneyObservation, work: () => T): T {
146
+ try { return work(); }
147
+ catch (error) {
148
+ exitJourneyNode(node, { ...o, outcome: 'error', data: { ...o.data, error: error instanceof Error ? error.message : String(error) } });
149
+ throw error;
150
+ }
151
+ }
152
+
153
+ /** 진입·출구를 한 번에 — 판정만 하는 노드(대기 없는 관문)용. */
154
+ export function passJourneyNode(node: JourneyNodeId, o: JourneyObservation & { readonly outcome: string }): void {
155
+ enterJourneyNode(node, o);
156
+ exitJourneyNode(node, o);
157
+ }
@@ -0,0 +1,105 @@
1
+ import { debug } from '../debug/log.js';
2
+ import { GRAPH_SPECS } from '../self-implement/graph-templates.js';
3
+ import { applyGraphOverlays, defaultOverlaysDir, loadGraphOverlays, selectOverlays, type GraphOverlaySpec } from '../self-implement/graph-overlay-yaml.js';
4
+ import type { GraphTemplateSpec } from '../self-implement/graph-yaml.js';
5
+ import { journeyJoinFields } from './graph-journey-nodes.js';
6
+
7
+ /** ⭐ HARNESS-FULL-GRAPH 2판 — 「다음 노드」를 코드가 아니라 «그래프»가 정한다.
8
+ *
9
+ * 대표 10-08: *«그래프에 따라 실제 경로가 바뀌어야 한다. 기본은 풀세트, 환경 셋업·운영 방법에 따라 일부만 걷거나 생략.»*
10
+ * ⇒ 코드는 «상태 값»(queue=queued|direct · substrate=local|pod · freeze=open|frozen …)만 낸다.
11
+ * 그 값으로 «어느 간선을 타나»는 YAML 의 `on:`/`map:`(⊕ `stage: launch` 오버레이)이 정한다.
12
+ * ⛔ 기본 YAML 은 오늘 코드와 «같은 길»을 낸다 — 시험이 그 동치를 문다(graph-journey-route.test.ts).
13
+ * ⛔ 그래프가 답을 못 내면(간선 없음·로드 실패) 코드 기본으로 간다 — 그 사실을 `source: 'code-default'` 로 남긴다.
14
+ * 🔎 관측: `self-implement` / `graph-edge-taken` { from, on, label, to, source, overlays } */
15
+
16
+ export interface JourneyRoute {
17
+ readonly from: string;
18
+ readonly on: string | null;
19
+ readonly label: string;
20
+ /** 그래프가 고른 다음 노드. 못 고르면 null. */
21
+ readonly to: string | null;
22
+ readonly source: 'graph' | 'code-default';
23
+ readonly overlays: readonly string[];
24
+ }
25
+
26
+ /** ⛔ 캐시하지 않는다 — 여러 런을 처리하는 프로세스(데몬·대기열 tick)가 다음 발사에서 오버레이 변경을 봐야 한다.
27
+ * 여정 판정은 발사당 몇 번뿐이라 디렉터리 한 번 읽기가 싸다. */
28
+ let overlaysForTesting: readonly GraphOverlaySpec[] | undefined;
29
+ function launchOverlays(): readonly GraphOverlaySpec[] {
30
+ if (overlaysForTesting !== undefined) return overlaysForTesting;
31
+ try { return loadGraphOverlays(defaultOverlaysDir()).overlays; }
32
+ catch { return []; }
33
+ }
34
+
35
+ /** 시험 전용 — 오버레이 묶음을 고정한다(undefined 면 디스크에서 읽는다). */
36
+ export function setJourneyOverlaysForTesting(overlays: readonly GraphOverlaySpec[] | undefined): void {
37
+ overlaysForTesting = overlays;
38
+ }
39
+
40
+ /** 상태 값으로 고른 «이 런의 여정 선언» — 기준 YAML ⊕ 조건이 맞는 launch 오버레이. */
41
+ export function journeySpec(
42
+ state: Readonly<Record<string, unknown>>,
43
+ base: GraphTemplateSpec | undefined = GRAPH_SPECS['self-implement'],
44
+ overlays: readonly GraphOverlaySpec[] = launchOverlays(),
45
+ ): { readonly spec: GraphTemplateSpec | undefined; readonly applied: readonly string[] } {
46
+ if (base === undefined) return { spec: undefined, applied: [] };
47
+ try {
48
+ const { applied } = selectOverlays(overlays, { graphId: base.graphId, stage: 'launch', state });
49
+ if (applied.length === 0) return { spec: base, applied: [] };
50
+ const result = applyGraphOverlays(base, applied);
51
+ // ⛔ 거절된 오버레이는 길을 바꾸지 않는다 — 기준 선언으로 간다.
52
+ return result.ok ? { spec: result.template, applied: result.overlayIds } : { spec: base, applied: [] };
53
+ } catch {
54
+ return { spec: base, applied: [] };
55
+ }
56
+ }
57
+
58
+ /** `from` 노드에서 `label` 로 나가는 다음 노드를 그래프에서 «읽는다»(기록하지 않는다).
59
+ * ⛔ 판독과 기록을 가른다 — 실제로 탄 간선은 전제 검사·실제 단계 경계 «뒤»에 `recordJourneyEdge` 로 남긴다. */
60
+ export function readJourneyEdge(
61
+ from: string,
62
+ label: string,
63
+ state: Readonly<Record<string, unknown>> = {},
64
+ deps: { readonly base?: GraphTemplateSpec; readonly overlays?: readonly GraphOverlaySpec[] } = {},
65
+ ): JourneyRoute {
66
+ const { spec, applied } = journeySpec(state, deps.base ?? GRAPH_SPECS['self-implement'], deps.overlays ?? launchOverlays());
67
+ let route: JourneyRoute = { from, on: null, label, to: null, source: 'code-default', overlays: applied };
68
+ for (const edge of spec?.edges ?? []) {
69
+ if (edge.from !== from) continue;
70
+ if (edge.map !== undefined && Object.hasOwn(edge.map, label)) {
71
+ route = { from, on: edge.on ?? null, label, to: edge.map[label]!, source: 'graph', overlays: applied };
72
+ break;
73
+ }
74
+ }
75
+ return route;
76
+ }
77
+
78
+ /** 실제로 탄 간선을 남긴다 — `taken` 은 실제 다음 노드(그래프 답과 다르면 `honored: false` · 그 이유를 `reason` 에). */
79
+ export function recordJourneyEdge(route: JourneyRoute, taken: string, reason?: string): void {
80
+ try {
81
+ debug.log('self-implement', 'graph-edge-taken', {
82
+ graphId: 'self-implement', ...route, taken, honored: route.to === null || route.to === taken,
83
+ ...(reason === undefined ? {} : { reason }), ...journeyJoinFields(),
84
+ });
85
+ } catch { /* 관측은 fail-soft */ }
86
+ }
87
+
88
+ /** 판독 ⊕ 그 자리에서 기록 — 판독 자리가 곧 실제 단계 경계일 때만 쓴다. */
89
+ export function routeJourneyEdge(
90
+ from: string,
91
+ label: string,
92
+ state: Readonly<Record<string, unknown>> = {},
93
+ deps: { readonly base?: GraphTemplateSpec; readonly overlays?: readonly GraphOverlaySpec[] } = {},
94
+ ): JourneyRoute {
95
+ const route = readJourneyEdge(from, label, state, deps);
96
+ recordJourneyEdge(route, route.to ?? label);
97
+ return route;
98
+ }
99
+
100
+ /** 입구의 대기열 갈래 — 그래프가 고른 다음 노드로 정한다. 그래프가 답을 못 내면 코드 라벨을 따른다.
101
+ * ⛔ `eligible`(자리 있음 · 대기열 자식 아님 · --no-queue 아님)은 그래프가 못 넘는 전제다. */
102
+ export function intakeTakesQueue(label: 'queued' | 'direct', route: Pick<JourneyRoute, 'source' | 'to'>, eligible: boolean): boolean {
103
+ const graphQueues = route.source === 'graph' ? route.to === 'queue' : label === 'queued';
104
+ return graphQueues && eligible;
105
+ }
@@ -538,6 +538,9 @@ export interface LaunchPreflightInput {
538
538
  readonly askTargetPaths?: readonly string[];
539
539
  /** 대상 경로 라벨이 «있는데» 거부된 조각. 0건 막음 문면이 그 이유를 말하게 한다(판정은 안 바꾼다). */
540
540
  readonly askTargetPathRejections?: readonly AskTargetPathHintRejection[];
541
+ /** AUTO-TARGET: machine-suggested target paths dropped because the goal is NOT-GROUNDED (no persistent evidence).
542
+ * Non-empty = the goal is a scope card and must not launch an implementation. */
543
+ readonly notGroundedDroppedTargetPaths?: readonly string[];
541
544
  /** ask 원문 경로. 있으면 ask-outside-path 경고만 이 목록과 최종 대상을 비교한다. */
542
545
  readonly askOutsidePathHints?: readonly string[];
543
546
  /** 이번에 쏠 골의 브랜치 이름. 없으면 형제 PR 축의 경고를 내지 않는다. */
@@ -559,19 +562,31 @@ function emitAskMarkerObservation(result: LaunchPreflightResult): void {
559
562
  emittedAskMarkerObservations.add(result);
560
563
  }
561
564
 
565
+ /** AUTO-TARGET: blocker name for a NOT-GROUNDED goal whose only target paths were machine-suggested (a scope card). */
566
+ export const NOT_GROUNDED_SCOPE_CARD_BLOCKER = '(NOT-GROUNDED 범위 카드)';
567
+
562
568
  export function evaluateLaunchPreflight(input: LaunchPreflightInput): LaunchPreflightResult {
563
569
  const paths = [...new Set(input.paths.filter((path) => path.trim().length > 0))];
564
570
  const blockers: LaunchPreflightBlocker[] = [];
565
571
  const warnings: LaunchPreflightBlocker[] = [];
566
572
 
573
+ // AUTO-TARGET (10-08 canary · TSC-HEAP): a NOT-GROUNDED goal whose only target paths came from the
574
+ // harness candidate search is a scope card — refuse it with that reason, not the generic «no label» text.
575
+ const notGroundedDropped = input.notGroundedDroppedTargetPaths ?? [];
576
+ const notGroundedDetail = notGroundedDropped.length > 0
577
+ ? `골이 NOT-GROUNDED(영속 근거 0)라 하니스 후보 검색이 넣은 대상 경로 ${notGroundedDropped.length}개(${notGroundedDropped.slice(0, 3).join(' · ')}${notGroundedDropped.length > 3 ? ' …' : ''})를 대상으로 쓰지 않는다 — 범위 카드: 구현 발사 대상이 아니다 · ask 첫 줄에 사람이 「대상 경로: <파일>」을 적거나 접지 근거를 복구한 뒤 다시 저작`
578
+ : undefined;
579
+ if (notGroundedDetail !== undefined && paths.length > 0) {
580
+ blockers.push({ kind: 'no-target-paths', name: NOT_GROUNDED_SCOPE_CARD_BLOCKER, detail: notGroundedDetail });
581
+ }
567
582
  // ① 모집단이 0이면 «통과»가 아니라 «막는 사유»다(METHOD v32 를 이 코드에도 적용).
568
583
  if (paths.length === 0) {
569
584
  blockers.push({
570
585
  kind: 'no-target-paths',
571
- name: '(대상 경로 0)',
586
+ name: notGroundedDetail !== undefined ? NOT_GROUNDED_SCOPE_CARD_BLOCKER : '(대상 경로 0)',
572
587
  // ⛔ 2026-09-23 — 라벨이 «있는데» 조각이 거부된 경우를 「라벨을 넣어라」로 뭉개면 「거부됐다」를 「없다」로 읽게 된다
573
588
  // (실측: `대상 경로: README.md — 설명…` 한 줄 → has-whitespace 로 통째 거부 · 문면은 「넣어라」뿐이었다).
574
- detail: (input.askTargetPathRejections?.length
589
+ detail: notGroundedDetail !== undefined ? notGroundedDetail : (input.askTargetPathRejections?.length
575
590
  ? `대상 경로 라벨은 있는데 조각 ${input.askTargetPathRejections.length}개가 거부됐다: ${input.askTargetPathRejections.slice(0, 3).map((r) => `「${r.fragment.length > 40 ? `${r.fragment.slice(0, 40)}…` : r.fragment}」(${r.reason})`).join(' · ')} — 그 줄에는 «경로만» 둔다(설명은 다음 줄)`
576
591
  : '골에서 대상 경로를 하나도 못 뽑았다 — ask 첫 줄에 「대상 경로: <파일> · <파일>」을 넣어라')
577
592
  + ' — 이 상태의 「위반 0」은 「검사했다」가 아니다 — elanous self author --inspect-target-paths "<문면>"',
@@ -1192,6 +1207,9 @@ export interface AskPreflightDeps {
1192
1207
  readonly askTargetPaths?: (document: string) => readonly string[];
1193
1208
  /** 대상 경로 라벨 «안»에서 거부된 조각(이유 포함). 0건 막음 문면이 「라벨이 없다」와 「있는데 거부됐다」를 가르게 한다. */
1194
1209
  readonly askTargetPathRejections?: (document: string) => readonly AskTargetPathHintRejection[];
1210
+ /** AUTO-TARGET: true when the authored goal is NOT-GROUNDED with no persistent evidence (a scope card).
1211
+ * Omitted = this distinction is not made (existing behavior). Production wires `isNotGroundedWithoutPersistentEvidence`. */
1212
+ readonly notGroundedWithoutPersistentEvidence?: (document: string) => boolean;
1195
1213
  }
1196
1214
 
1197
1215
  export interface AskPreflightOptions {
@@ -1212,6 +1230,10 @@ export interface AskPreflightOptions {
1212
1230
  readonly plannedBranch?: string;
1213
1231
  /** 저작 전 ask 원문. 주면 기존 ask-marker-check로 형식을 관측하되 발사를 막지 않는다. */
1214
1232
  readonly askText?: string;
1233
+ /** AUTO-TARGET: target paths the harness put into the ask (candidate search), not the human.
1234
+ * If the authored goal is NOT-GROUNDED without persistent evidence, these paths are dropped and the
1235
+ * goal stops before launch (`no-target-paths` blocker naming the reason). */
1236
+ readonly machineSuggestedTargetPaths?: readonly string[];
1215
1237
  }
1216
1238
 
1217
1239
  export type PlannedBranchResolution =
@@ -1539,7 +1561,24 @@ export function decideAskPreflight(
1539
1561
  }
1540
1562
  }
1541
1563
  // ⛔ 저작 전에는 pathsOverride 자체가 ask 대상 힌트다. 저작 뒤에는 골에서 뽑은 대상만 역할로 쓴다.
1542
- const askTargetPaths = opts.pathsOverride ?? (goalDocument && deps.askTargetPaths ? deps.askTargetPaths(goalDocument) : []);
1564
+ const declaredAskTargetPaths = opts.pathsOverride ?? (goalDocument && deps.askTargetPaths ? deps.askTargetPaths(goalDocument) : []);
1565
+ // AUTO-TARGET: a NOT-GROUNDED goal (no persistent evidence) carries no machine-suggested target path.
1566
+ const machineSuggested = new Set((opts.machineSuggestedTargetPaths ?? []).map((path) => path.trim()).filter(Boolean));
1567
+ let notGroundedGoal = false;
1568
+ if (!opts.pathsOverride && goalDocument !== null && machineSuggested.size > 0 && deps.notGroundedWithoutPersistentEvidence) {
1569
+ try { notGroundedGoal = deps.notGroundedWithoutPersistentEvidence(goalDocument); } catch { notGroundedGoal = false; }
1570
+ }
1571
+ const notGroundedDroppedTargetPaths = notGroundedGoal ? declaredAskTargetPaths.filter((path) => machineSuggested.has(path)) : [];
1572
+ const askTargetPaths = notGroundedDroppedTargetPaths.length > 0
1573
+ ? declaredAskTargetPaths.filter((path) => !machineSuggested.has(path))
1574
+ : declaredAskTargetPaths;
1575
+ if (notGroundedDroppedTargetPaths.length > 0) {
1576
+ try {
1577
+ debug.log('harness.preflight', 'not-grounded-target-paths-dropped', { goalFile: opts.goalFile, dropped: notGroundedDroppedTargetPaths });
1578
+ } catch {
1579
+ // Observation never changes the launch decision.
1580
+ }
1581
+ }
1543
1582
  // 저작 뒤에는 접지가 읽은 경로와 선언 대상 경로를 함께 검사한다. 저작 전 pathsOverride는 그대로 쓴다.
1544
1583
  const paths = opts.pathsOverride ?? [...new Set([...tracedPaths, ...askTargetPaths])];
1545
1584
  const askMarkerInspection = opts.askText === undefined
@@ -1677,6 +1716,7 @@ export function decideAskPreflight(
1677
1716
  ...(goalRulersUnknownReason ? { goalRulersUnknownReason } : {}),
1678
1717
  preexistingFailures,
1679
1718
  ...(askTargetPaths.length > 0 ? { askTargetPaths } : {}),
1719
+ ...(notGroundedDroppedTargetPaths.length > 0 ? { notGroundedDroppedTargetPaths } : {}),
1680
1720
  ...(askTargetPaths.length === 0 && goalDocument && deps.askTargetPathRejections
1681
1721
  ? { askTargetPathRejections: deps.askTargetPathRejections(goalDocument) }
1682
1722
  : {}),
@@ -8,6 +8,8 @@ export interface PreviewOptions {
8
8
  scenario?: string;
9
9
  /** Main-based combined preview: only existing config paths may be enabled. */
10
10
  flags?: readonly string[];
11
+ /** PR heads to preview together on main when no feature flags exist. */
12
+ bundlePrs?: readonly number[];
11
13
  commentPr?: number;
12
14
  }
13
15
  export interface PreviewResult {
@@ -35,14 +37,50 @@ export interface PreviewDeps {
35
37
  probePwa?: (url: string) => Promise<boolean>;
36
38
  }
37
39
 
38
- const SCENARIOS: Record<string, string> = {
39
- S2: '/help', S3: '/status', S6: '/now', S7: '/term list', S8: '/model', S9: '/harness',
40
+ const SCENARIOS: Record<string, { input: string; expected: string; matches: (snapshot: string) => boolean }> = {
41
+ // GOODHART (#24844 review): a group head (`▸ 시작`) or the echoed `/help` is not the list. The /help modal
42
+ // (help-from-registry.ts) prints one `/name description` row per command; the «시작» group alone has six.
43
+ // Pass only when at least three other start-group commands are listed as rows.
44
+ S2: { input: '/help', expected: 'help command list (/status, /model, /clear ... rows)', matches: (s) =>
45
+ ['status', 'model', 'clear', 'new', 'resume'].filter((name) => new RegExp(`(?:^|\\s)/${name}(?: \\([^)]*\\))?\\s{2,}\\S`, 'mu').test(s)).length >= 3 },
46
+ S3: { input: '/status', expected: 'model and connection', matches: (s) => /모델|model/iu.test(s) && /연결|connection/iu.test(s) },
47
+ S6: { input: '/now', expected: 'current runs or schedules', matches: (s) => /지금|도는 런|스케줄|running|schedule/iu.test(s) },
48
+ S7: { input: '/term list', expected: 'terminal/PTY list', matches: (s) => /terminal|pty|터미널/iu.test(s) },
49
+ S8: { input: '/model', expected: 'model choices', matches: (s) => /빠름|보통|깊음|terra|sol|luna|선택/iu.test(s) },
50
+ S9: { input: '/harness', expected: 'harness usage or stages', matches: (s) => /usage:.*harness|저작|구현|리뷰|착지/iu.test(s) },
40
51
  };
41
52
 
53
+ /**
54
+ * Lines of `after` that were not already on `before`'s screen (multiset by line, trailing spaces ignored).
55
+ * A prefix check is not enough: the PTY re-renders and scrolls, so the previous scenario's answer can
56
+ * reappear anywhere on the next screen (#24844 review). A repeated line is conservatively treated as old.
57
+ */
58
+ export function previewFreshLines(before: string, after: string): string {
59
+ const seen = new Map<string, number>();
60
+ for (const line of before.split('\n')) {
61
+ const key = line.trimEnd();
62
+ if (key) seen.set(key, (seen.get(key) ?? 0) + 1);
63
+ }
64
+ return after.split('\n').filter((line) => {
65
+ const key = line.trimEnd();
66
+ if (!key) return false;
67
+ const left = seen.get(key) ?? 0;
68
+ if (left > 0) { seen.set(key, left - 1); return false; }
69
+ return true;
70
+ }).join('\n');
71
+ }
72
+
73
+ /** Whether a fresh screen region shows the scenario's expected answer (exported for the preview tests). */
74
+ export function previewScenarioMatches(scenario: string, fresh: string): boolean {
75
+ const entry = Object.hasOwn(SCENARIOS, scenario) ? SCENARIOS[scenario] : undefined;
76
+ if (!entry) throw new Error(`TUI-COMFORT §4: unsupported scenario ${scenario}`);
77
+ return entry.matches(fresh);
78
+ }
79
+
42
80
  export function previewScenarioInput(scenario: string): string {
43
81
  const text = Object.hasOwn(SCENARIOS, scenario) ? SCENARIOS[scenario] : undefined;
44
82
  if (!text) throw new Error(`TUI-COMFORT §4: unsupported scenario ${scenario}; available: ${Object.keys(SCENARIOS).join(', ')}`);
45
- return text;
83
+ return text.input;
46
84
  }
47
85
 
48
86
  const defaultRun: NonNullable<PreviewDeps['run']> = (command, args, cwd, timeoutMs = 120_000) => {
@@ -60,13 +98,18 @@ export async function runPrPreview(options: PreviewOptions, deps: PreviewDeps =
60
98
  if (isPr && !Number.isSafeInteger(Number(target))) throw new Error('preview: invalid PR number');
61
99
  if (/^\d+$/u.test(target) && !isPr) throw new Error('preview: invalid PR number');
62
100
  if (options.commentPr !== undefined && (!Number.isSafeInteger(options.commentPr) || options.commentPr <= 0)) throw new Error('preview: invalid --comment-pr');
101
+ const bundlePrs = options.bundlePrs ?? [];
102
+ if (bundlePrs.length && (target !== 'main' || (options.flags?.length ?? 0) > 0)) throw new Error('preview: --bundle-pr requires main without feature flags');
103
+ if (bundlePrs.length && (new Set(bundlePrs).size !== bundlePrs.length || bundlePrs.some((pr) => !Number.isSafeInteger(pr) || pr <= 0))) throw new Error('preview: invalid or duplicate --bundle-pr');
63
104
  if (target === 'main' && options.commentPr === undefined) throw new Error('preview: main ⊕ flags requires --comment-pr <PR number> to publish the result');
64
105
  if (isPr && options.commentPr !== undefined && options.commentPr !== Number(target)) throw new Error('preview: --comment-pr must match the target PR');
65
106
  const flags = options.flags ?? [];
66
107
  if (flags.length && target !== 'main') throw new Error('preview: --flag requires main (main ⊕ feature flags)');
67
108
  if (flags.some((flag) => !/^[a-zA-Z][\w-]*(?:\.[a-zA-Z][\w-]*)+$/u.test(flag))) throw new Error('preview: --flag expects an existing dotted config path');
68
- const scenario = options.scenario ?? 'S2';
69
- const input = previewScenarioInput(scenario);
109
+ const scenarios = (options.scenario ?? 'S2').split(',').map((id) => id.trim());
110
+ if (scenarios.length === 0 || new Set(scenarios).size !== scenarios.length) throw new Error('preview: duplicate or empty scenario');
111
+ for (const id of scenarios) previewScenarioInput(id);
112
+ const scenario = scenarios.join(',');
70
113
  const check = (command: string, args: readonly string[], cwd: string, timeout?: number): string => {
71
114
  const r = run(command, args, cwd, timeout);
72
115
  if (r.status !== 0) throw new Error(`preview: ${command} ${args.join(' ')} failed: ${(r.stdout + '\n' + r.stderr).slice(-600)}`);
@@ -99,6 +142,16 @@ export async function runPrPreview(options: PreviewOptions, deps: PreviewDeps =
99
142
  const pr = JSON.parse(check('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,headRefName'], root)) as { headRefOid?: string; headRefName?: string };
100
143
  if (pr.headRefName !== target || pr.headRefOid !== head || (branchPrHead !== undefined && branchPrHead !== head)) throw new Error('preview: branch does not match the target PR head; use the PR number');
101
144
  }
145
+ const bundleHeads = bundlePrs.map((number) => {
146
+ const pr = JSON.parse(check('gh', ['pr', 'view', String(number), '--json', 'number,headRefOid'], root)) as { number?: number; headRefOid?: string };
147
+ if (pr.number !== number || !/^[0-9a-f]{40}$/iu.test(pr.headRefOid ?? '')) throw new Error(`preview: PR #${number} head is unavailable`);
148
+ const oid = pr.headRefOid!;
149
+ if (run('git', ['cat-file', '-e', `${oid}^{commit}`], root).status !== 0) {
150
+ check('git', ['fetch', '--no-tags', 'origin', `pull/${number}/head`], root, 120_000);
151
+ if (check('git', ['rev-parse', '--verify', 'FETCH_HEAD^{commit}'], root) !== oid) throw new Error(`preview: PR #${number} head changed while fetching; retry`);
152
+ }
153
+ return { number, oid };
154
+ });
102
155
  const directory = (deps.makeDir ?? (() => {
103
156
  const previews = join(root, '.elanous-test', 'previews');
104
157
  mkdirSync(previews, { recursive: true });
@@ -112,6 +165,11 @@ export async function runPrPreview(options: PreviewOptions, deps: PreviewDeps =
112
165
  try {
113
166
  check('git', ['worktree', 'add', '--detach', worktree, head], root);
114
167
  added = true;
168
+ for (const { number, oid } of bundleHeads) {
169
+ const current = JSON.parse(check('gh', ['pr', 'view', String(number), '--json', 'number,headRefOid'], root)) as { number?: number; headRefOid?: string };
170
+ if (current.number !== number || current.headRefOid !== oid) throw new Error(`preview: PR #${number} head changed while preparing bundle; retry`);
171
+ check('git', ['-c', 'user.name=elanous-preview', '-c', 'user.email=preview@localhost', 'merge', '--no-ff', '--no-edit', oid], worktree, 120_000);
172
+ }
115
173
  check('bun', ['install', '--frozen-lockfile'], worktree, 300_000);
116
174
  check('bun', ['install', '--frozen-lockfile'], join(worktree, 'apps/pwa'), 300_000);
117
175
  for (const flag of flags) {
@@ -145,17 +203,27 @@ export async function runPrPreview(options: PreviewOptions, deps: PreviewDeps =
145
203
  if (pty.held !== true || !/^pty_[\w-]+$/u.test(pty.ptyId ?? '')) throw new Error('preview: B-1 held TUI did not return a PTY reference');
146
204
  heldPty = pty.ptyId;
147
205
  const snapshotArgs = ['bin/elanous.mjs', '--test', 'pty', 'snapshot', pty.ptyId!] as const;
148
- const before = check('bun', snapshotArgs, worktree);
149
- check('bun', ['bin/elanous.mjs', '--test', 'pty', 'text', pty.ptyId!, input, '--enter'], worktree);
150
- // A constant sleep misses slow frames under load — poll until the screen answers (≤ 20s).
151
- let snapshot = '';
152
- for (let attempt = 0; attempt < 20; attempt++) {
153
- await wait(1000);
154
- snapshot = check('bun', snapshotArgs, worktree);
155
- if (snapshot && snapshot !== 'ok' && snapshot !== before) break;
206
+ const rows: string[] = [];
207
+ const snapshots: string[] = [];
208
+ for (const id of scenarios) {
209
+ const { input, expected, matches } = SCENARIOS[id]!;
210
+ const before = check('bun', snapshotArgs, worktree);
211
+ check('bun', ['bin/elanous.mjs', '--test', 'pty', 'text', pty.ptyId!, input, '--enter'], worktree);
212
+ // A constant sleep misses slow frames under load — poll until this scenario's expected response (≤ 20s).
213
+ let snapshot = '';
214
+ let matched = false;
215
+ for (let attempt = 0; attempt < 20; attempt++) {
216
+ await wait(1000);
217
+ snapshot = check('bun', snapshotArgs, worktree);
218
+ const fresh = previewFreshLines(before, snapshot);
219
+ matched = snapshot !== 'ok' && snapshot !== before && matches(fresh);
220
+ if (matched) break;
221
+ }
222
+ const observed = snapshot && snapshot !== 'ok' && snapshot !== before;
223
+ rows.push(`| TUI-COMFORT §4 ${id} | \`${input}\` → ${matched ? `expected ${expected} matched` : `friction: expected ${expected} not found${observed ? '' : ' (no response within 20s)'}`} |`);
224
+ snapshots.push(`<details><summary>Inner PTY snapshot ${id}</summary>\n\n\`\`\`text\n${snapshot.slice(-3000).replaceAll('```', "'''")}\n\`\`\`\n</details>`);
156
225
  }
157
- if (!snapshot || snapshot === 'ok' || snapshot === before) throw new Error('preview: inner PTY did not show a response to the scenario input within 20s');
158
- report = `| Check | Observation |\n|---|---|\n| head | \`${head}\` |\n| B-1 version | ${version.slice(0, 120)} |\n| P-1 PWA | \`${endpoint}/app/\` served the built PWA |\n| TUI-COMFORT §4 ${scenario} | \`${input}\` → snapshot captured |\n\n<details><summary>Inner PTY snapshot</summary>\n\n\`\`\`text\n${snapshot.slice(-3000).replaceAll('```', "'''")}\n\`\`\`\n</details>`;
226
+ report = `| Check | Observation |\n|---|---|\n| head | \`${head}\` |${bundleHeads.length ? `\n| bundled PR heads | ${bundleHeads.map(({ number, oid }) => `#${number} \`${oid}\``).join(' ⊕ ')} |` : ''}\n| B-1 version | ${version.slice(0, 120)} |\n| P-1 PWA | \`${endpoint}/app/\` served the built PWA |\n${rows.join('\n')}\n\n${snapshots.join('\n\n')}`;
159
227
  } catch (error) {
160
228
  report = `| Check | Friction |\n|---|---|\n| head | \`${head}\` |\n| TUI-COMFORT §4 ${scenario} | ${String(error).replaceAll('|', '\\|').slice(0, 700)} |`;
161
229
  } finally {
@@ -167,7 +235,7 @@ export async function runPrPreview(options: PreviewOptions, deps: PreviewDeps =
167
235
  }
168
236
  (deps.dispose ?? ((dir) => rmSync(dir, { recursive: true, force: true })))(directory);
169
237
  }
170
- const status = report.includes('| Friction |') ? 'friction' : 'passed';
238
+ const status = report.includes('| Friction |') || report.includes('→ friction:') ? 'friction' : 'passed';
171
239
  const body = `## PR preview — ${target} (${status})\n\n${report}`;
172
240
  if (prNumber === undefined) throw new Error('preview: cannot comment without a PR number');
173
241
  check('gh', ['pr', 'comment', String(prNumber), '--body', body], root);
@@ -1,6 +1,9 @@
1
- // Release path = what publishing reads directly: the release scripts and graph, plus the manifest, release notes and cut schedule
2
- // in `src/release-loop/`. The checklist store (`checklist.ts`, `feature-store.ts`) is shared ops ledger code — the gate catches its regressions (OP 10-03).
3
- export const RELEASE_PATH_PREFIXES = ['scripts/release-loop/', 'graphs/release/', 'src/release-loop/manifest', 'src/release-loop/release-note', 'src/release-loop/release-schedule'] as const;
1
+ // Release path = release scripts and graph, manifest, notes and cut schedule, plus gate execution modules
2
+ // imported by scripts/release-loop/gate-node.ts (pod-command-job → pod-pool → pod-lease; pod-bun-cache; pod-install-slots; gate-shards).
3
+ // The checklist store (`checklist.ts`, `feature-store.ts`) remains shared ops ledger code (OP 10-03).
4
+ export const RELEASE_PATH_PREFIXES = ['scripts/release-loop/', 'graphs/release/', 'src/release-loop/manifest', 'src/release-loop/release-note', 'src/release-loop/release-schedule',
5
+ 'src/task-orchestrator/surfaces/pod-command-job.ts', 'src/task-orchestrator/surfaces/pod-pool.ts', 'src/task-orchestrator/surfaces/pod-lease.ts',
6
+ 'src/task-orchestrator/surfaces/pod-bun-cache.ts', 'src/task-orchestrator/surfaces/pod-install-slots.ts', 'src/release-loop/gate-shards.ts'] as const;
4
7
  export const RELEASE_PATH_LABEL = 'elanous:release-path';
5
8
 
6
9
  /** Flatten every GitHub PR file page, including the source of a rename. */
@@ -35,7 +38,7 @@ export function releaseGitDiffPaths(output: string): string[] {
35
38
 
36
39
  /** Evaluate the paths from the opened PR, not the requested goal or local working tree. */
37
40
  export function releasePathHold(paths: readonly string[]): string | undefined {
38
- return paths.find((path) => RELEASE_PATH_PREFIXES.some((prefix) => path.startsWith(prefix)));
41
+ return paths.find((path) => RELEASE_PATH_PREFIXES.some((prefix) => prefix.endsWith('.ts') ? path === prefix : path.startsWith(prefix)));
39
42
  }
40
43
 
41
44
  /** Fixed opening of the hold comment — also how a PR held by several merge surfaces (or polls) is recognised, so it is posted once. */