elanous 0.2.42 → 0.2.44

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 (764) 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/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/08334415.f0e80896acbef722.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1032-78ba4f6391258cab.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1082-53f86a26e03d309d.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1109-7d0e264f6f2edbc7.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1124-7c26330402481143.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{2160.a097e7b138ae1c55.js → 118.2a89982fe4276880.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1244.6c435dbf1bf21d8a.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1252.9e665904d3aa3b1a.js +32 -0
  12. package/apps/pwa/out/_next/static/chunks/1266.a46cc33cb6a72d75.js +104 -0
  13. package/apps/pwa/out/_next/static/chunks/1306.967240ede9a0f757.js +24 -0
  14. package/apps/pwa/out/_next/static/chunks/1344.3b95f3bd1b77a3fe.js +94 -0
  15. package/apps/pwa/out/_next/static/chunks/{4043.6b91203436c9c86b.js → 1401.22dfe92640a2b1ac.js} +4 -4
  16. package/apps/pwa/out/_next/static/chunks/1431-f7c78bd5be21e011.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1451-cdd35a8a0b31834b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{6632.0eac1c554f8f2ef3.js → 1694.18debfd77562e56d.js} +2 -2
  19. package/apps/pwa/out/_next/static/chunks/1708-f03d587b7a7545c8.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1775-fa7152bdeff6c95f.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/178-4da509cd7266672a.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/1850-522de4ee34957210.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1876-c6f6e0ddcc76c6a1.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/1976.097066b072432242.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{3507.97e1977bc4d5fb0a.js → 1978.eeb60a606dc5deac.js} +2 -2
  26. package/apps/pwa/out/_next/static/chunks/2043.e233e3b5a3e790f5.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2150.71b94e3348107c83.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2158.ebc6fc5a10280ab7.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2216.802962c04f40a26e.js +64 -0
  30. package/apps/pwa/out/_next/static/chunks/2294.7890edcfa046c97d.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/235.c89aaae4bcd6233a.js +74 -0
  32. package/apps/pwa/out/_next/static/chunks/{5885.0a3e52c8faccec98.js → 239.de075467b5523469.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/249.ba7051590d603c8f.js +226 -0
  34. package/apps/pwa/out/_next/static/chunks/2571.a6ac4e26c8618403.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/2610.e149cd564a08913e.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/2705.9816f3c244f8b85f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/2801.afeb8a4dae22f85f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/2954.bbefc95d6b20e0d8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/2e0f720a.a0697c08e3806a60.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3042.96ec235fe41c8d4e.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3097-8e358f158acef46b.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3205-93b1abe28b4fb16a.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3273.b4434f0dcae7eb29.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3311.9cbc43ea0c90d60c.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{1487.2f67b79444062da6.js → 3349.b5f09ee474d9533e.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/3503.a47a9755fb4d97b0.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3506-5f429b3b7e1392b0.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/3843.bad404d008893291.js +77 -0
  49. package/apps/pwa/out/_next/static/chunks/3877-4b40e530b47e3bf9.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/435-ce2958253cf7de61.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4393.28fa5228d0eec217.js +149 -0
  52. package/apps/pwa/out/_next/static/chunks/4404.7281c847c6e10dfc.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/{8673-bab689a55f7e13b9.js → 4415-b9d6a90960920a4a.js} +3 -3
  54. package/apps/pwa/out/_next/static/chunks/447-5b304de1fe098f43.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4484-8ebea83d431e6fae.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{8262.ddc03e06b733f184.js → 4502.bdcc877abd437a05.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/4599-f95790fc5c65b8df.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1262.e804feb8fd1acb8c.js → 46.57c783fa4884714f.js} +2 -2
  59. package/apps/pwa/out/_next/static/chunks/463-b9114e411f33728e.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/4659.a57d1f0c5d754cd2.js +36 -0
  61. package/apps/pwa/out/_next/static/chunks/4722-a847e7a28115035f.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/{1063.2fb8a9dc55c731f2.js → 4757.67c6d7473a038e78.js} +1 -1
  63. package/apps/pwa/out/_next/static/chunks/4874-c86f878ec4502ad3.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{6377.bc7df239edbff244.js → 4891.3f80ba517a3b2373.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/4998.810ca8833084caa9.js +62 -0
  66. package/apps/pwa/out/_next/static/chunks/4f98febc.ea5841d4d616bfb2.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/{3482.a9ae9d2ad6a5bd97.js → 5052.7dbb12a55d4f18f5.js} +1 -1
  68. package/apps/pwa/out/_next/static/chunks/5166-ca73b3e361085a6d.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5180-039f4a18b07ad387.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/5232.5a2ce4daf7a9e11d.js +115 -0
  71. package/apps/pwa/out/_next/static/chunks/5439.3fec6dbce29ecb36.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5612-074d9a5e00dfac6a.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/5675-01989d524a84c505.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/5751.af641a1adf5ec697.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/5758-c6cb98714d18ab0c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/578eded8.b582637306e16964.js +122 -0
  77. package/apps/pwa/out/_next/static/chunks/5790.5eb06a653ebd8571.js +34 -0
  78. package/apps/pwa/out/_next/static/chunks/5853-4033e5bd5afbe06b.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/5904.97d70bb7f46b2db7.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{3347.f846266b5e5f3ede.js → 5989.7ecd362c5c44b747.js} +3 -3
  81. package/apps/pwa/out/_next/static/chunks/{73d2eb0e.4966ad55293c801a.js → 5a34fb2f.52f1b4e1baebb48a.js} +3 -3
  82. package/apps/pwa/out/_next/static/chunks/{7a98bc80.fa935989e829f9c2.js → 5a5078f8.2099200e5ea95e16.js} +1 -1
  83. package/apps/pwa/out/_next/static/chunks/6036-c302c34ff0b3d410.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/606.ef81c313381f4264.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/616.1af54a928b1ba704.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/6201.bc936f71f613a8e9.js +41 -0
  87. package/apps/pwa/out/_next/static/chunks/6204-fdc86e0e64c4f92d.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/{7411.9b4b8b747dc7b802.js → 6245.1182e007e9d230d9.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{b450776b.3db34d8d965f82d3.js → 63699a35.17262e162bc514b2.js} +1 -1
  90. package/apps/pwa/out/_next/static/chunks/6420.494801a80030160c.js +27 -0
  91. package/apps/pwa/out/_next/static/chunks/{e8543907.5b040a5f22a0b0e5.js → 6549dad0.2740b25e51bf8f05.js} +1 -1
  92. package/apps/pwa/out/_next/static/chunks/{9427.96aa912ddb5801e0.js → 6881.9e7955847640c7fe.js} +17 -17
  93. package/apps/pwa/out/_next/static/chunks/6931.fcdfb94141e67b3d.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/6991-8e081c6ce38c0ba1.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7010.1bbd17a7f2b3e376.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7029.d1466acf55fae2ed.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7152-a123aa8e129c131f.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7455.196168fffac3b9c4.js +24 -0
  99. package/apps/pwa/out/_next/static/chunks/7638.6ca4770dd1129138.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/7649-f37d76260e5e2a5a.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/7679.32c40cdd14f20b4a.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/7751.04bfbd16b4c6cd0a.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/7864.b1ff31d4030b8994.js +148 -0
  104. package/apps/pwa/out/_next/static/chunks/7869-c47bd2c075c1fefa.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{8138.6c10b2a356d52fca.js → 8442.2f09ca969d631615.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8445.2738dbd59a78c78c.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8447.5510c439f9938c6d.js +286 -0
  108. package/apps/pwa/out/_next/static/chunks/{9415.69e4a21c60c7d2db.js → 8551.f762945c2cda2e95.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/8635-57a9d8d9db70f4f1.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/86961958-4b0689a5048f756b.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/8709.3c6019bb18f8554f.js +8 -0
  112. package/apps/pwa/out/_next/static/chunks/8759.c999528a0a907bf6.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9a852a62-6192a6ea9346ced3.js → 87f498e5-0881de09f2e44707.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/8843.c3197f904c952b81.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{3d0154af.5331fec737ffe8c3.js → 892fd990.456232f326cc39c2.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/8965-135a2c9eaa2464cb.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/8971-8d3b9c96f8a6c958.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9059.c8598d96f8e5e9cd.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9115.90447ae198b84eae.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9147.d9b0a02e0babc9b4.js +93 -0
  121. package/apps/pwa/out/_next/static/chunks/9204-83075f4b70c61cdc.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9244-c32ef14b5dc72bdf.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/930.2a9a30f964350c66.js +90 -0
  124. package/apps/pwa/out/_next/static/chunks/9398.1f56e3f17795f43f.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/9527.3e5ad31c891c5fcb.js +79 -0
  126. package/apps/pwa/out/_next/static/chunks/9571-4ac933e774d1225c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-9fc644de2d8edae3.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/approvals/page-0c9dace2db62bee8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f5e65c3dc9d89f2a.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/board/page-2a9c19b9a140b7b1.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/botlab/page-61533ad92141adfb.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/bots/page-112004ced6fd0329.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f733318c237a49d8.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/chat/page-51ea677d2d33bbc0.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/consult/page-428b41f2f9566e3c.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/control/page-1b29396ea90a61e5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/decisions/page-cf83ec613ac904bf.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/design-check/page-3f4c0ecbc284bb5f.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/editor/page-b63c322f54f70cc6.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/exec/page-fe328c4ee9aac6b4.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/field/page-bfb855c584f0fb98.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/healthz/route-9fc644de2d8edae3.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/inside/page-47b1710c110eabd7.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/intake/page-42895214458bc6d2.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/layout-d03de0ebd8366e23.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/live/page-3ed6c47e4b1c61c2.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/live-run/page-ae653e9bf261c738.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/loops/page-23f3f0a0209c0ac4.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/market/page-88c691273aae66f9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e187ac52a95538b3.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/morning/page-6e45828daed1295e.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/not-found-edb5d7287bb46186.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/observatory/page-4a7eaacd93c3f6a5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ca073d43d74cc84.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1e9fee67b1199436.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-df1283ea963c6816.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/outputs/page-19fcf8d8301ccd18.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/page-5ab699e0303bbb40.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7cde0d29756984c5.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9d4c598e8ee22f7a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/sessions/page-cc1609a71f44ec62.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7659a9a1345bfaa9.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/settings/page-0afef60ecc0c4af5.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a3553949f8f34f5f.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/setup/layout-9fc644de2d8edae3.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/setup/page-057a69702f3c67c7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/share/page-c0f0e570f3f74c73.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/showroom/page-1825071ae34e3b89.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6244e3e135d8ccfc.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/term/page-da787e8a10b8a82e.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/today/page-1316d32498e2be42.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/trace/page-4df94572e343de2e.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/vault/page-708969f7475e88c1.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c58add08c919a1dc.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/workflows/page-a24847f45e5d5bf9.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/app/workspace/page-acfec65a3a60e22e.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-3dfc598e6fbde245.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-c658a626118411b7.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-4c73685fd891445b.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-6310f7e5de7dd01d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-51c326bf48610be1.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-d0beadf754da59b0.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-acd243bfbf3f6732.js +1 -0
  184. package/apps/pwa/out/_next/static/css/d1f8bb401740a549.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 +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/catalog/external-commands.yaml +5 -3
  279. package/catalog/meta/catalogVersion.yaml +2 -1
  280. package/catalog/signing/catalog-signing-public.pem +3 -0
  281. package/graphs/intake/intake-daily.yaml +16 -0
  282. package/graphs/intake/news-sources.yaml +1 -0
  283. package/graphs/intake/recipes.yaml +7 -0
  284. package/graphs/overlays/README.md +6 -0
  285. package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
  286. package/graphs/profiles/local.yaml +5 -0
  287. package/graphs/profiles/pod.yaml +4 -0
  288. package/graphs/release/release-loop.yaml +33 -17
  289. package/graphs/units/verbs/make-doc.yaml +1 -0
  290. package/package.json +6 -2
  291. package/plugins/demo-absorption-briefing/plugin.json +18 -0
  292. package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
  293. package/plugins/demo-browser-hand/plugin.json +13 -0
  294. package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
  295. package/plugins/demo-linear-secretary/plugin.json +15 -0
  296. package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
  297. package/plugins/demo-plugin-wizard/plugin.json +11 -0
  298. package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
  299. package/plugins/demo-research/plugin.json +16 -0
  300. package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
  301. package/plugins/demo-video-briefing/plugin.json +15 -0
  302. package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
  303. package/scripts/bench-metering-plan.ts +229 -0
  304. package/scripts/build-signed-catalog.ts +48 -0
  305. package/scripts/ci-typecheck-main-delta.sh +88 -0
  306. package/scripts/codex-fallback-live-probe.ts +1 -1
  307. package/scripts/demo/demo1104-parallel-host.ts +56 -0
  308. package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
  309. package/scripts/demo/demo1104-parallel.ts +72 -0
  310. package/scripts/demo/demo1104-stage.config.ts +21 -0
  311. package/scripts/demo/demo1104-stage.ts +316 -0
  312. package/scripts/goal-method-audit.ts +17 -1
  313. package/scripts/graph-units/land-enqueue.ts +90 -0
  314. package/scripts/hooks/codex-notify.sh +32 -0
  315. package/scripts/install.sh +10 -38
  316. package/scripts/landing-heal/land-plan.ts +57 -0
  317. package/scripts/public-leak-baseline.txt +0 -1
  318. package/scripts/release-loop/auto-approve-node.ts +1 -1
  319. package/scripts/release-loop/docs-node.ts +4 -2
  320. package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
  321. package/scripts/release-loop/gate-image-pin.ts +116 -2
  322. package/scripts/release-loop/gate-method.ts +139 -0
  323. package/scripts/release-loop/gate-node.ts +395 -43
  324. package/scripts/release-loop/gate-progress-sim.ts +73 -0
  325. package/scripts/release-loop/gate-traffic-mode.ts +151 -3
  326. package/scripts/release-loop/node-verdict.ts +38 -25
  327. package/scripts/release-loop/notes-repair.ts +18 -1
  328. package/scripts/release-loop/preflight.ts +544 -10
  329. package/scripts/release-loop/render-warm-control-manifest.ts +22 -0
  330. package/scripts/release-loop/resume-release.ts +9 -7
  331. package/scripts/release-loop/resume.ts +13 -4
  332. package/scripts/release-loop/unattended-release.ts +20 -9
  333. package/scripts/release-loop/warm-control-forward.ts +178 -0
  334. package/scripts/retro-cycle.ts +30 -8
  335. package/scripts/rhythm/daily.ts +39 -4
  336. package/scripts/rhythm/linear-progress-sync.ts +311 -0
  337. package/scripts/ux-sim.ts +7 -1
  338. package/scripts/video-pipeline.ts +9 -1
  339. package/scripts/warm-pool-provider-config.ts +35 -7
  340. package/src/acp/agent-manager.ts +1 -0
  341. package/src/acp/codex-app-server-agent.ts +33 -0
  342. package/src/acp/codex-app-server-client.ts +153 -16
  343. package/src/acp/core-turn-bridge.ts +17 -12
  344. package/src/acp/event-router.ts +20 -1
  345. package/src/acp/server.ts +6 -0
  346. package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
  347. package/src/agent-mission/claude-headless.ts +4 -1
  348. package/src/agent-mission/codex-exec.ts +105 -0
  349. package/src/agent-mission/driver.ts +192 -11
  350. package/src/agent-mission/grok-auth-status.ts +107 -0
  351. package/src/agent-mission/hand-hooks.ts +101 -0
  352. package/src/agent-mission/mission-cli.ts +56 -21
  353. package/src/agent-mission/mission-hand-reply.ts +118 -0
  354. package/src/agent-mission/mission-line.ts +180 -0
  355. package/src/agent-mission/mission-out.ts +256 -18
  356. package/src/agent-mission/tool-install.ts +122 -11
  357. package/src/agent-substrate/pr-reviewer.ts +147 -11
  358. package/src/agent-substrate/self-review-cli.ts +10 -2
  359. package/src/agents/general-purpose.md +1 -1
  360. package/src/auto-research/research-fanout.ts +221 -0
  361. package/src/auto-research/research-turn.ts +362 -31
  362. package/src/autopilot/mission-codebase-gate.ts +7 -3
  363. package/src/autopilot/pr-manager.ts +31 -3
  364. package/src/boot/daemon-tools/self-implement.ts +3 -1
  365. package/src/boot/daemon-tools/web-search.ts +1 -2
  366. package/src/briefing/brief-items.ts +55 -11
  367. package/src/cli/agent-cli.ts +2 -1
  368. package/src/cli/catalog-cli.ts +31 -0
  369. package/src/cli/connector-cli.ts +16 -0
  370. package/src/cli/control-cli.ts +15 -6
  371. package/src/cli/doctor-fix.ts +2 -2
  372. package/src/cli/intake-source-cli.ts +44 -8
  373. package/src/cli/log-event-names.ts +8 -0
  374. package/src/cli/msg-cli.ts +32 -3
  375. package/src/cli/pr-cli.ts +21 -1
  376. package/src/cli/pr-land-heavy-remote.ts +44 -6
  377. package/src/cli/pr-land-overlap-evidence.ts +13 -1
  378. package/src/cli/pr-land-pod-shadow-job.ts +143 -5
  379. package/src/cli/pr-land-pod-shadow.ts +9 -2
  380. package/src/cli/release-checklist-read-cli.ts +44 -16
  381. package/src/cli/release-cli.ts +23 -3
  382. package/src/cli/research-cli.ts +9 -0
  383. package/src/cli/setup-cli.ts +166 -6
  384. package/src/cli/setup-keys.ts +199 -0
  385. package/src/cli/task-plugin-wizard-host.ts +114 -0
  386. package/src/cli/tasks-cli.ts +54 -9
  387. package/src/cli/tui-test-cli.ts +190 -0
  388. package/src/config.ts +4 -2
  389. package/src/connectors/linear-daily-progress.ts +228 -0
  390. package/src/connectors/linear-projector.ts +34 -12
  391. package/src/connectors/linear.ts +151 -7
  392. package/src/control-plane/ledger.ts +42 -4
  393. package/src/control-plane/member-tokens.ts +25 -2
  394. package/src/control-plane/ports.ts +8 -3
  395. package/src/control-plane/server.ts +26 -5
  396. package/src/core-turn/deep-turn-bloom.ts +67 -0
  397. package/src/core-turn/research-policy.ts +43 -0
  398. package/src/core-turn/run-core-turn.ts +488 -51
  399. package/src/core-turn/types.ts +4 -0
  400. package/src/dashboard/chat/acp-chat.ts +10 -0
  401. package/src/dashboard/classic-sidetab-mission-job.ts +192 -0
  402. package/src/dashboard/classic-sidetab-mission-pair.ts +82 -0
  403. package/src/dashboard/classic-sidetab-mission-trio.ts +242 -0
  404. package/src/dashboard/classic-sidetab-mission.ts +169 -5
  405. package/src/dashboard/index.ts +387 -14
  406. package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
  407. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +8 -0
  408. package/src/dashboard/mission-cli-consumer.ts +20 -8
  409. package/src/dashboard/plugin-wizard-runtime.ts +50 -0
  410. package/src/dashboard/plugin-wizard-tool.ts +55 -0
  411. package/src/dashboard/sidetab-runtime.ts +3 -1
  412. package/src/dashboard/terminal-popup-runtime.ts +6 -3
  413. package/src/dashboard/visible-mission-diagnostics.ts +16 -0
  414. package/src/decisions/linear-progress-summary.ts +78 -0
  415. package/src/decisions/linear-progress-sync.ts +152 -0
  416. package/src/domains/outbound-alert.ts +49 -11
  417. package/src/domains/retro-cycle-observation.ts +43 -0
  418. package/src/domains/retro-cycle.ts +13 -2
  419. package/src/domains/retro-proposals.ts +92 -0
  420. package/src/domains/retro-report.ts +6 -1
  421. package/src/domains/telegram-kind-route.ts +16 -9
  422. package/src/graph-runner/arg-allowance.ts +13 -0
  423. package/src/graph-runner/graph-cli.ts +24 -1
  424. package/src/graph-runner/graph-grow-llm.ts +3 -1
  425. package/src/graph-runner/graph-run-api.ts +3 -1
  426. package/src/graph-runner/runner.ts +310 -46
  427. package/src/graph-wizard/mission-compose.ts +407 -12
  428. package/src/harness/dispatch-backpressure.ts +54 -1
  429. package/src/harness/dispatch-shadow-compare.ts +74 -0
  430. package/src/harness/harness-cli-command.ts +15 -3
  431. package/src/harness/harness-pod-dispatch.ts +3 -0
  432. package/src/harness/skill-exec.ts +21 -9
  433. package/src/harness/skill-select.ts +1 -1
  434. package/src/hooks/error-report-cloud.ts +101 -0
  435. package/src/hooks/receiver.ts +29 -2
  436. package/src/index.ts +129 -12
  437. package/src/intake-plane/actions.ts +354 -0
  438. package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
  439. package/src/intake-plane/intake-sources.ts +78 -8
  440. package/src/intake-plane/items.ts +14 -4
  441. package/src/intake-plane/linear-mission-sync.ts +80 -0
  442. package/src/intake-plane/linear-secretary-runtime.ts +178 -0
  443. package/src/intake-plane/linear-wish.ts +227 -1
  444. package/src/life/life-cli.ts +168 -0
  445. package/src/life/life-kinds.ts +160 -0
  446. package/src/live-supply/budget-consumer.ts +78 -0
  447. package/src/live-supply/read.ts +3 -0
  448. package/src/live-supply/snapshot.ts +45 -0
  449. package/src/llm/child-first-llm-observation.ts +112 -0
  450. package/src/llm/provider-credentials.ts +68 -6
  451. package/src/llm/provider-failure-evidence.ts +44 -0
  452. package/src/llm.ts +172 -12
  453. package/src/maturity/feature-maturity.ts +3 -3
  454. package/src/mcp/client.ts +7 -0
  455. package/src/mcp/proxy-runtime.ts +6 -1
  456. package/src/mcp/server.ts +54 -0
  457. package/src/msg/msg-sse-server.ts +3 -3
  458. package/src/msg/msg-store.ts +177 -19
  459. package/src/native-tool-catalog.ts +36 -2
  460. package/src/nexus/api/consult-requests.ts +18 -6
  461. package/src/nexus/api/discord-trigger-bot.ts +6 -6
  462. package/src/nexus/api/graphs-api.ts +4 -2
  463. package/src/nexus/api/grokbot-trigger-bot.ts +206 -0
  464. package/src/nexus/api/http-server.ts +37 -1
  465. package/src/nexus/api/mcp-public-allowlist.ts +2 -0
  466. package/src/nexus/api/telegram-trigger-bot.ts +6 -6
  467. package/src/nexus/boot/register-mcp-clients.ts +114 -8
  468. package/src/nexus/index.ts +22 -2
  469. package/src/nexus/outbound/format.ts +9 -0
  470. package/src/nexus/outbound/grokbot-adapter.ts +71 -0
  471. package/src/nexus/outbound/router.ts +121 -16
  472. package/src/nexus/setup-status.ts +9 -0
  473. package/src/nexus/state/state.ts +3 -0
  474. package/src/oauth/codex-account-store.ts +20 -7
  475. package/src/oauth/codex-owner-mirror.ts +81 -0
  476. package/src/oauth/codex.ts +17 -2
  477. package/src/oauth/fallback-chain.ts +47 -17
  478. package/src/onboarding/first-run-doctor.ts +8 -1
  479. package/src/onboarding/first-run.ts +126 -29
  480. package/src/onboarding/key-setup.ts +103 -0
  481. package/src/onboarding/menu-answer.ts +13 -0
  482. package/src/onboarding/secret-prompt.ts +37 -0
  483. package/src/plugins/install/plugin-install.ts +59 -0
  484. package/src/pr-tool/census.ts +130 -0
  485. package/src/preview/terminal.ts +22 -7
  486. package/src/prompt-enhance/enhance.ts +10 -0
  487. package/src/pty-shell/pty-control-ipc.ts +4 -1
  488. package/src/pty-shell/pty-write-provenance.ts +21 -3
  489. package/src/pty-shell/registry.ts +9 -2
  490. package/src/registry/catalog-server.ts +232 -0
  491. package/src/registry/loader.ts +45 -1
  492. package/src/registry/types.ts +1 -2
  493. package/src/release-loop/proposal-auto-place.ts +83 -0
  494. package/src/research/axis-fanout.ts +79 -29
  495. package/src/research/lenses/second-order.ts +312 -0
  496. package/src/self-dev/ask-launch-flow.ts +72 -1
  497. package/src/self-dev/dev-cli.ts +7 -2
  498. package/src/self-dev/dev-pipeline.ts +5 -0
  499. package/src/self-dev/draft-residue.ts +64 -5
  500. package/src/self-dev/draft-sweep.ts +31 -10
  501. package/src/self-dev/draft-triage-rules.ts +60 -3
  502. package/src/self-dev/graph-front-nodes.ts +2 -1
  503. package/src/self-dev/graph-journey-route.ts +76 -21
  504. package/src/self-dev/launch-preflight.ts +58 -0
  505. package/src/self-dev/orchestrate.ts +1 -1
  506. package/src/self-dev/run-supervisor.ts +152 -2
  507. package/src/self-dev/shard-aggregate.ts +4 -0
  508. package/src/self-dev/shard-run.ts +36 -15
  509. package/src/self-implement/abandoned-classification.ts +12 -3
  510. package/src/self-implement/budget-gate.ts +7 -0
  511. package/src/self-implement/child-llm-preference.ts +10 -1
  512. package/src/self-implement/doctor-visit.ts +30 -8
  513. package/src/self-implement/elanous-tui-spawn.ts +3 -0
  514. package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
  515. package/src/self-implement/gate-artifacts.ts +2 -1
  516. package/src/self-implement/goal-author-cli.ts +4 -2
  517. package/src/self-implement/goal-author.ts +549 -10
  518. package/src/self-implement/graph-overlay-yaml.ts +181 -4
  519. package/src/self-implement/graph-overlay.ts +3 -1
  520. package/src/self-implement/graph-profile-yaml.ts +107 -0
  521. package/src/self-implement/graph-yaml.ts +94 -5
  522. package/src/self-implement/off-diff-evidence.ts +249 -5
  523. package/src/self-implement/orchestrator.ts +298 -26
  524. package/src/self-implement/run-chart.ts +6 -3
  525. package/src/self-implement/run-ledger.ts +51 -1
  526. package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
  527. package/src/self-implement/tdd-evidence-tags.ts +9 -0
  528. package/src/self-implement/test-scenario-request.ts +37 -6
  529. package/src/self-implement/train-gate-receipt.ts +166 -0
  530. package/src/self-implement/train-gate-remote.ts +62 -18
  531. package/src/session/chat.ts +6 -4
  532. package/src/session/session-fanout.ts +2 -0
  533. package/src/session/streaming/acp-stream-sink.ts +2 -1
  534. package/src/session/streaming/chunk-producer.ts +6 -0
  535. package/src/session/streaming/stream-compositor.ts +3 -2
  536. package/src/session-runtime/index.ts +74 -6
  537. package/src/session-runtime/retry-policy.ts +1 -1
  538. package/src/setup/llm-env-detect.ts +3 -0
  539. package/src/setup/service-key-catalog.ts +46 -0
  540. package/src/setup/service-keys.ts +241 -0
  541. package/src/sidetab-core/model.ts +205 -10
  542. package/src/sidetab-core/visible-agent-mission-pair.ts +51 -0
  543. package/src/sidetab-core/visible-agent-mission.ts +182 -48
  544. package/src/skills/tools/agent.ts +23 -4
  545. package/src/skills/tools/omni-search.ts +127 -27
  546. package/src/task-agent/parent-host.ts +29 -1
  547. package/src/task-agent/recall-inject.ts +98 -0
  548. package/src/task-agent/repair-outcomes.ts +65 -0
  549. package/src/task-agent/task-hand.ts +46 -14
  550. package/src/task-orchestrator/dispatcher.ts +14 -1
  551. package/src/task-orchestrator/linear-capture-events.ts +55 -0
  552. package/src/task-orchestrator/store.ts +16 -5
  553. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +23 -1
  554. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +107 -1
  555. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
  556. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +21 -9
  557. package/src/task-orchestrator/surfaces/pod-source-receive.ts +23 -11
  558. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
  559. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +1 -1
  560. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +467 -77
  561. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +45 -3
  562. package/src/task-orchestrator/surfaces/self-implement-pod.ts +210 -14
  563. package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
  564. package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
  565. package/src/task-orchestrator/types.ts +14 -0
  566. package/src/telegram.ts +14 -16
  567. package/src/terminal/coding-agent.ts +14 -5
  568. package/src/terminal/session-registry.ts +1 -1
  569. package/src/tool-hints/gate.ts +46 -14
  570. package/src/tool-hints/signals.ts +1 -1
  571. package/src/tool-hints/types.ts +2 -0
  572. package/src/tool-runtime/agent-runtime.ts +1 -0
  573. package/src/tool-runtime/browser-hand-runtime.ts +391 -0
  574. package/src/tool-runtime/browser-runtime.ts +33 -19
  575. package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
  576. package/src/tool-runtime/elanous-linear-secretary-runtime.ts +173 -0
  577. package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
  578. package/src/tool-runtime/index.ts +6 -0
  579. package/src/tool-runtime/types.ts +5 -0
  580. package/src/tui/entry.ts +51 -8
  581. package/src/tui/sidetab/attach.ts +252 -11
  582. package/src/tui/sidetab/herdr-portal.ts +225 -0
  583. package/src/tui/sidetab/list.ts +3 -2
  584. package/src/tui-client/next-dashboard-runtime.ts +52 -0
  585. package/src/user-config.ts +34 -9
  586. package/src/user-intent/types.ts +4 -3
  587. package/src/ux-sim/browser-hand.ts +165 -0
  588. package/src/ux-sim/draft-inventory-builder.ts +199 -0
  589. package/src/ux-sim/fake-browser-page.ts +81 -0
  590. package/src/ux-sim/fake-linear-device.ts +31 -0
  591. package/src/ux-sim/graph-engine-sim.ts +47 -0
  592. package/src/ux-sim/linear-secretary.ts +208 -0
  593. package/src/ux-sim/mock-scenario-catalog.json +81 -26
  594. package/src/ux-sim/mock-scenario-catalog.ts +175 -5
  595. package/src/ux-sim/onboarding-first-run-device.ts +31 -21
  596. package/src/ux-sim/release-sim-rig.ts +62 -18
  597. package/src/ux-sim/scenario.ts +70 -26
  598. package/src/ux-sim/service-key-setup.ts +113 -0
  599. package/src/ux-sim/term-slash-device.ts +74 -0
  600. package/src/ux-sim/turn-throw-sim.ts +31 -0
  601. package/src/version/packed-revision.json +1 -1
  602. package/src/web-search/exa.ts +77 -0
  603. package/src/web-search/index.ts +30 -9
  604. package/src/web-search/provider.ts +4 -1
  605. package/src/web-search/x-intent.ts +5 -0
  606. package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +0 -36
  608. package/apps/pwa/out/_next/static/chunks/1147-5196d19c222051b3.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1319.b9b815ae0f181e06.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/1574.878c18ecc97b1bd4.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +0 -32
  614. package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/1945.7b54990d578c119b.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +0 -286
  620. package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +0 -34
  623. package/apps/pwa/out/_next/static/chunks/2456.b6de0e1c05f28843.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/2690.0521c738b7749931.js +0 -115
  629. package/apps/pwa/out/_next/static/chunks/2974.595d1e29d040cb6a.js +0 -64
  630. package/apps/pwa/out/_next/static/chunks/3207.a756c95e9ec8c3c8.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/3285.89ee2f298682f5e5.js +0 -93
  632. package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +0 -41
  633. package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +0 -24
  635. package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/3837.a210d7d0db8d8abd.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +0 -77
  641. package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/4320.583cbab64db6be02.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/4770.769c9cd9c7034eba.js +0 -148
  647. package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +0 -74
  648. package/apps/pwa/out/_next/static/chunks/50061469.0326382241ef3b2d.js +0 -122
  649. package/apps/pwa/out/_next/static/chunks/5112.4b9f300124fab7b3.js +0 -149
  650. package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +0 -27
  652. package/apps/pwa/out/_next/static/chunks/53c73f84.373b6160adfa89a4.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/5440-4236de26c5ea5856.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +0 -226
  664. package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +0 -90
  665. package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +0 -104
  671. package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +0 -94
  672. package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/7279-c199ea83f34338fa.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +0 -24
  679. package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +0 -8
  687. package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/8505.fd803c6c33b54cc3.js +0 -79
  689. package/apps/pwa/out/_next/static/chunks/8546-6f03f8ea34dd61d9.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/9211-330b6736a63d4cb3.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/9249.976f1e69a9d80754.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/9353-12bfff0c130104cf.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/9656-374232558fd528d0.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/9832.f4a98c878ecf2c0a.js +0 -62
  705. package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/morning/page-0f291d3c8fd55a3a.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +0 -1
  763. package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
  764. /package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_ssgManifest.js +0 -0
@@ -9,6 +9,10 @@ export interface MockScenarioDevice {
9
9
  target: string;
10
10
  inputs: string[];
11
11
  observations: string[];
12
+ entryCommands: string[];
13
+ logsRecorded: 'yes' | 'no' | 'conditional' | 'runner-dependent';
14
+ eventNames: string[];
15
+ recentUse: { observedAt: string; runId: string; event: string; scenarioId: string; command: string } | null;
12
16
  }
13
17
 
14
18
  export interface MockScenarioEntry {
@@ -23,8 +27,19 @@ export interface MockScenarioEntry {
23
27
  expected: string;
24
28
  }
25
29
 
30
+ export interface MockScenarioCandidate {
31
+ path: string;
32
+ disposition: 'device' | 'scenario' | 'already-indexed' | 'excluded';
33
+ entryCommand: string;
34
+ logsRecorded: 'yes' | 'no' | 'conditional' | 'runner-dependent';
35
+ logsDetail: string;
36
+ deviceId?: string;
37
+ scenarioIds?: string[];
38
+ excludeReason?: string;
39
+ }
40
+
26
41
  export interface MockScenarioCatalog {
27
- version: 1;
42
+ version: 2;
28
43
  runEvidence: {
29
44
  scope: string;
30
45
  runId: string;
@@ -34,6 +49,16 @@ export interface MockScenarioCatalog {
34
49
  };
35
50
  devices: MockScenarioDevice[];
36
51
  scenarios: MockScenarioEntry[];
52
+ candidateAudit: {
53
+ source: string;
54
+ baseCommit: string;
55
+ sourceRows: number;
56
+ existingPaths: number;
57
+ excludedPaths: number;
58
+ sourceExclusions: Array<{ path: string; reason: string }>;
59
+ omissionCheck: { requiredPaths: string[]; missingPaths: string[] };
60
+ candidates: MockScenarioCandidate[];
61
+ };
37
62
  discovery: { trackedRoot: string; candidateRoots: string[]; limits: string };
38
63
  }
39
64
 
@@ -66,7 +91,7 @@ function uniqueIds(rows: unknown[], path: string): Set<string> {
66
91
 
67
92
  /** Validate the checked-in index before CLI output or scenario metadata is consumed. */
68
93
  export function parseMockScenarioCatalog(value: unknown): MockScenarioCatalog {
69
- if (!isRecord(value) || value.version !== 1) throw new Error('mock scenario catalog must declare version: 1');
94
+ if (!isRecord(value) || value.version !== 2) throw new Error('mock scenario catalog must declare version: 2');
70
95
  if (!Array.isArray(value.devices) || !Array.isArray(value.scenarios)) throw new Error('mock scenario catalog requires devices and scenarios arrays');
71
96
  const deviceIds = uniqueIds(value.devices, 'devices');
72
97
  uniqueIds(value.scenarios, 'scenarios');
@@ -81,6 +106,10 @@ export function parseMockScenarioCatalog(value: unknown): MockScenarioCatalog {
81
106
  target: requireString(row.target, `devices[${index}].target`),
82
107
  inputs: requireStringArray(row.inputs, `devices[${index}].inputs`),
83
108
  observations: requireStringArray(row.observations, `devices[${index}].observations`),
109
+ entryCommands: requireStringArray(row.entryCommands, `devices[${index}].entryCommands`),
110
+ logsRecorded: parseLogsRecorded(row.logsRecorded, `devices[${index}].logsRecorded`),
111
+ eventNames: requireStringArray(row.eventNames, `devices[${index}].eventNames`, true),
112
+ recentUse: parseRecentUse(row.recentUse, `devices[${index}].recentUse`),
84
113
  };
85
114
  });
86
115
  const scenarios = value.scenarios.map((row, index): MockScenarioEntry => {
@@ -99,15 +128,122 @@ export function parseMockScenarioCatalog(value: unknown): MockScenarioCatalog {
99
128
  expected: requireString(row.expected, `scenarios[${index}].expected`),
100
129
  };
101
130
  });
102
- if (!isRecord(value.runEvidence) || !isRecord(value.runEvidence.event)) throw new Error('runEvidence and runEvidence.event are required');
103
- if (!isRecord(value.discovery)) throw new Error('discovery is required');
131
+ if (!isRecord(value.candidateAudit) || !Array.isArray(value.candidateAudit.candidates) || !Array.isArray(value.candidateAudit.sourceExclusions)) {
132
+ throw new Error('candidateAudit and candidateAudit.candidates are required');
133
+ }
134
+ const knownScenarioIds = new Set(scenarios.map((scenario) => scenario.id));
135
+ const scenarioById = new Map(scenarios.map((scenario) => [scenario.id, scenario]));
136
+ const deviceById = new Map(devices.map((device) => [device.id, device]));
137
+ const candidatePaths = new Set<string>();
138
+ const sourceExclusions = value.candidateAudit.sourceExclusions.map((row, index) => {
139
+ if (!isRecord(row)) throw new Error(`candidateAudit.sourceExclusions[${index}] must be an object`);
140
+ const path = requireString(row.path, `candidateAudit.sourceExclusions[${index}].path`);
141
+ if (candidatePaths.has(path)) throw new Error(`candidateAudit.sourceExclusions contains duplicate path: ${path}`);
142
+ candidatePaths.add(path);
143
+ return { path, reason: requireString(row.reason, `candidateAudit.sourceExclusions[${index}].reason`) };
144
+ });
145
+ const candidates = value.candidateAudit.candidates.map((row, index): MockScenarioCandidate => {
146
+ if (!isRecord(row)) throw new Error(`candidateAudit.candidates[${index}] must be an object`);
147
+ const path = requireString(row.path, `candidateAudit.candidates[${index}].path`);
148
+ if (candidatePaths.has(path)) throw new Error(`candidateAudit.candidates contains duplicate path: ${path}`);
149
+ candidatePaths.add(path);
150
+ const disposition = requireString(row.disposition, `candidateAudit.candidates[${index}].disposition`);
151
+ if (!['device', 'scenario', 'already-indexed', 'excluded'].includes(disposition)) {
152
+ throw new Error(`candidateAudit.candidates[${index}].disposition is unknown: ${disposition}`);
153
+ }
154
+ const logsRecorded = requireString(row.logsRecorded, `candidateAudit.candidates[${index}].logsRecorded`);
155
+ if (!['yes', 'no', 'conditional', 'runner-dependent'].includes(logsRecorded)) {
156
+ throw new Error(`candidateAudit.candidates[${index}].logsRecorded is unknown: ${logsRecorded}`);
157
+ }
158
+ const deviceId = row.deviceId === undefined ? undefined : requireString(row.deviceId, `candidateAudit.candidates[${index}].deviceId`);
159
+ if (deviceId && !deviceIds.has(deviceId)) throw new Error(`candidateAudit.candidates[${index}] references unknown device: ${deviceId}`);
160
+ const scenarioIds = row.scenarioIds === undefined ? undefined : requireStringArray(row.scenarioIds, `candidateAudit.candidates[${index}].scenarioIds`);
161
+ for (const scenarioId of scenarioIds ?? []) {
162
+ if (!knownScenarioIds.has(scenarioId)) throw new Error(`candidateAudit.candidates[${index}] references unknown scenario: ${scenarioId}`);
163
+ }
164
+ const excludeReason = row.excludeReason === undefined ? undefined : requireString(row.excludeReason, `candidateAudit.candidates[${index}].excludeReason`);
165
+ if (disposition === 'excluded' && !excludeReason) throw new Error(`candidateAudit.candidates[${index}] excluded entries require excludeReason`);
166
+ if (disposition === 'excluded' && (deviceId || scenarioIds?.length)) {
167
+ throw new Error(`candidateAudit.candidates[${index}] excluded entries cannot have catalog links`);
168
+ }
169
+ if (disposition === 'device' && (!deviceId || !scenarioIds?.length)) {
170
+ throw new Error(`candidateAudit.candidates[${index}] device entries require deviceId and scenarioIds`);
171
+ }
172
+ if (disposition === 'scenario' && (!deviceId || !scenarioIds?.length)) {
173
+ throw new Error(`candidateAudit.candidates[${index}] scenario entries require deviceId and scenarioIds`);
174
+ }
175
+ if (disposition === 'already-indexed' && !deviceId && !scenarioIds?.length) {
176
+ throw new Error(`candidateAudit.candidates[${index}] already-indexed entries require a catalog link`);
177
+ }
178
+ if (scenarioIds?.length && !deviceId) {
179
+ throw new Error(`candidateAudit.candidates[${index}] scenarioIds require a deviceId`);
180
+ }
181
+ if (deviceId) {
182
+ const device = deviceById.get(deviceId)!;
183
+ if (![...device.implementation, ...device.tests].includes(path)) {
184
+ throw new Error(`candidateAudit.candidates[${index}] path is not registered by device ${deviceId}: ${path}`);
185
+ }
186
+ }
187
+ for (const scenarioId of scenarioIds ?? []) {
188
+ const scenario = scenarioById.get(scenarioId)!;
189
+ if (scenario.device !== deviceId) {
190
+ throw new Error(`candidateAudit.candidates[${index}] deviceId does not own scenario ${scenarioId}`);
191
+ }
192
+ if (![...scenario.implementation, ...scenario.tests].includes(path)) {
193
+ throw new Error(`candidateAudit.candidates[${index}] path is not registered by scenario ${scenarioId}: ${path}`);
194
+ }
195
+ }
196
+ return {
197
+ path,
198
+ disposition: disposition as MockScenarioCandidate['disposition'],
199
+ entryCommand: requireString(row.entryCommand, `candidateAudit.candidates[${index}].entryCommand`),
200
+ logsRecorded: logsRecorded as MockScenarioCandidate['logsRecorded'],
201
+ logsDetail: requireString(row.logsDetail, `candidateAudit.candidates[${index}].logsDetail`),
202
+ ...(deviceId ? { deviceId } : {}),
203
+ ...(scenarioIds ? { scenarioIds } : {}),
204
+ ...(excludeReason ? { excludeReason } : {}),
205
+ };
206
+ });
207
+ const omissionCheck = value.candidateAudit.omissionCheck;
208
+ if (!isRecord(omissionCheck)) throw new Error('candidateAudit.omissionCheck is required');
209
+ const requiredPaths = requireStringArray(omissionCheck.requiredPaths, 'candidateAudit.omissionCheck.requiredPaths');
210
+ const missingPaths = requireStringArray(omissionCheck.missingPaths, 'candidateAudit.omissionCheck.missingPaths', true);
211
+ const indexedCandidatePaths = new Set([...candidates, ...sourceExclusions].map((row) => row.path));
212
+ for (const path of requiredPaths) {
213
+ if (!indexedCandidatePaths.has(path)) throw new Error(`candidateAudit.omissionCheck path is not accounted for: ${path}`);
214
+ }
215
+ if (missingPaths.some((path) => !requiredPaths.includes(path))) throw new Error('candidateAudit.omissionCheck.missingPaths must be required paths');
216
+ const candidateAudit = value.candidateAudit;
217
+ const sourceRows = candidateAudit.sourceRows;
218
+ const baseCommit = candidateAudit.baseCommit;
219
+ const existingPaths = candidateAudit.existingPaths;
220
+ const excludedPaths = candidateAudit.excludedPaths;
221
+ if (![sourceRows, existingPaths, excludedPaths].every((n) => Number.isInteger(n) && Number(n) >= 0)) {
222
+ throw new Error('candidateAudit counts must be non-negative integers');
223
+ }
224
+ if (sourceRows !== candidates.length + sourceExclusions.length || excludedPaths !== candidates.filter((candidate) => candidate.disposition === 'excluded').length) {
225
+ throw new Error('candidateAudit counts do not match the candidate rows');
226
+ }
227
+ if (Number(existingPaths) !== candidates.length) throw new Error('candidateAudit.existingPaths must equal the current candidate count');
104
228
  const runEvidence = value.runEvidence;
229
+ if (!isRecord(runEvidence) || !isRecord(runEvidence.event)) throw new Error('runEvidence and runEvidence.event are required');
230
+ if (!isRecord(value.discovery)) throw new Error('discovery is required');
105
231
  const event = runEvidence.event;
106
232
  const discovery = value.discovery;
107
233
  return {
108
- version: 1,
234
+ version: 2,
109
235
  devices,
110
236
  scenarios,
237
+ candidateAudit: {
238
+ source: requireString(candidateAudit.source, 'candidateAudit.source'),
239
+ baseCommit: requireString(baseCommit, 'candidateAudit.baseCommit'),
240
+ sourceRows: Number(sourceRows),
241
+ existingPaths: Number(existingPaths),
242
+ excludedPaths: Number(excludedPaths),
243
+ sourceExclusions,
244
+ omissionCheck: { requiredPaths, missingPaths },
245
+ candidates,
246
+ },
111
247
  runEvidence: {
112
248
  scope: requireString(runEvidence.scope, 'runEvidence.scope'),
113
249
  runId: requireString(runEvidence.runId, 'runEvidence.runId'),
@@ -133,6 +269,7 @@ export function renderMockScenarioList(catalog: MockScenarioCatalog): string[] {
133
269
  'Mock scenario catalog · reusable devices and scenario references',
134
270
  ...catalog.scenarios.map((scenario) => `${scenario.id}\t${scenario.kind}\t${scenario.name}`),
135
271
  `장치 ${catalog.devices.length} · 시나리오 ${catalog.scenarios.length} · 자세히: bun scripts/ux-sim.ts show <MS-id>`,
272
+ `후보 감사 ${catalog.candidateAudit.existingPaths}/${catalog.candidateAudit.sourceRows} 경로 확인 · 제외 ${catalog.candidateAudit.excludedPaths} · entry/logs 근거는 mock-scenario-catalog.json`,
136
273
  ];
137
274
  }
138
275
 
@@ -154,3 +291,36 @@ export function renderMockScenarioDetails(catalog: MockScenarioCatalog, id: stri
154
291
  `ScenarioV0 실행 증거: ${catalog.runEvidence.scope} · runId → ${catalog.runEvidence.event.category}/${catalog.runEvidence.event.name} → test logs.db · ${catalog.runEvidence.artifact}`,
155
292
  ];
156
293
  }
294
+
295
+ /** Read-only device inventory; it reports stored evidence metadata and never runs a device. */
296
+ export function renderMockScenarioDevices(catalog: MockScenarioCatalog): string[] {
297
+ return [
298
+ 'Mock device registry · read-only',
299
+ ...catalog.devices.map((device) => [
300
+ `${device.id}\t${device.name}`,
301
+ `entry=${device.entryCommands.join(' ⊕ ')}`,
302
+ `logs=${device.logsRecorded}`,
303
+ `events=${device.eventNames.length ? device.eventNames.join(',') : '(none recorded)'}`,
304
+ `recent=${device.recentUse ? `${device.recentUse.observedAt} runId=${device.recentUse.runId} event=${device.recentUse.event} scenario=${device.recentUse.scenarioId} cmd=${device.recentUse.command}` : '(not recorded)'}`,
305
+ ].join('\t')),
306
+ `omission check: required=${catalog.candidateAudit.omissionCheck.requiredPaths.length} missing=${catalog.candidateAudit.omissionCheck.missingPaths.length}`,
307
+ ];
308
+ }
309
+
310
+ function parseLogsRecorded(value: unknown, path: string): MockScenarioDevice['logsRecorded'] {
311
+ const result = requireString(value, path);
312
+ if (!['yes', 'no', 'conditional', 'runner-dependent'].includes(result)) throw new Error(`${path} is unknown: ${result}`);
313
+ return result as MockScenarioDevice['logsRecorded'];
314
+ }
315
+
316
+ function parseRecentUse(value: unknown, path: string): MockScenarioDevice['recentUse'] {
317
+ if (value === null) return null;
318
+ if (!isRecord(value)) throw new Error(`${path} must be an object or null`);
319
+ return {
320
+ observedAt: requireString(value.observedAt, `${path}.observedAt`),
321
+ runId: requireString(value.runId, `${path}.runId`),
322
+ event: requireString(value.event, `${path}.event`),
323
+ scenarioId: requireString(value.scenarioId, `${path}.scenarioId`),
324
+ command: requireString(value.command, `${path}.command`),
325
+ };
326
+ }
@@ -1,14 +1,13 @@
1
- // ux-sim device: the PRODUCTION first-run menu, driven under a real util-linux PTY.
1
+ // ux-sim device: the PRODUCTION fresh-install setup menu, driven under a real util-linux PTY.
2
2
  //
3
- // Why this exists: the menu re-ask loop of `src/onboarding/first-run.ts`
4
- // (`promptProviderMenu` → `parseMenuAnswer`) is only reachable when
3
+ // Why this exists: the fresh-install setup menu is only reachable when
5
4
  // `process.stdin.isTTY` is true. A plain pipe makes the CLI take the non-TTY
6
5
  // `needs-llm` shortcut instead, so the board (how many times the menu comes
7
6
  // back, which phrase ends the run, whether `onboarding.ready` is written) is
8
7
  // unmeasurable without a TTY. This device allocates one the same way the live
9
8
  // seat does — util-linux `script -q -e -c` — so the production entrypoint
10
9
  // `bin/elanous.mjs --test` runs its real `src/index.ts` → `runFirstRun` →
11
- // `promptProviderMenu` path.
10
+ // `runFirstRunProviderSetup` path.
12
11
  //
13
12
  // Isolation (K-MK-03): HOME/XDG/claude dirs are a fresh temp tree and the CLI
14
13
  // is spawned with `--test --config-dir <temp>`, so the run cannot touch a real
@@ -19,26 +18,30 @@ import { spawn } from 'node:child_process';
19
18
  import { mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
20
19
  import { tmpdir } from 'node:os';
21
20
  import { join, resolve } from 'node:path';
22
- import { formatProviderMenu, orderProviderChoices } from '../onboarding/first-run.js';
21
+ import { FIRST_RUN_PROVIDER_MENU_PROMPT, formatProviderMenu, orderProviderChoices } from '../onboarding/first-run.js';
22
+ import {
23
+ FIRST_RUN_PROVIDER_SETUP_MENU_CHOICES,
24
+ FIRST_RUN_PROVIDER_SETUP_MENU_HEADING,
25
+ FIRST_RUN_PROVIDER_SETUP_MENU_MAX_MISSES,
26
+ } from '../cli/setup-keys.js';
23
27
  import { spawnElanousSync } from '../instance/spawn-elanous.js';
24
28
  import { createFakeBins, utilLinuxScript, type FakeBinCall } from './fake-bin.js';
25
- /**
26
- * Text `promptProviderMenu` prints before every re-ask — one occurrence per render.
27
- * Every assertion on the re-ask count uses this marker, so it has one source.
28
- */
29
- export const FIRST_RUN_MENU_MARKER = 'Choose LLM';
30
- /**
31
- * Fixed choice line of the first-run menu, taken from the production renderer
32
- * itself (`formatProviderMenu` over the default choice order) rather than retyped.
33
- * Every assertion that the menu printed the expected wording — here and in
34
- * `src/onboarding/first-run.test.ts` — reads this, so production wording drift
35
- * turns into a failure instead of a stale expectation.
36
- */
29
+ /** English provider chooser and Korean fresh-install chooser headings. */
30
+ export const FIRST_RUN_MENU_MARKERS = [FIRST_RUN_PROVIDER_MENU_PROMPT, FIRST_RUN_PROVIDER_SETUP_MENU_HEADING] as const;
31
+
32
+ /** Count menu renders independently of the selected user-facing locale. */
33
+ export function countFirstRunMenuRenders(output: string): number {
34
+ const markerCounts = FIRST_RUN_MENU_MARKERS.map((marker) => output.split(marker).length - 1);
35
+ // A process keeps one locale; max also avoids counting one bilingual render twice.
36
+ return Math.max(...markerCounts);
37
+ }
38
+ /** Fixed provider-chooser choice line, taken from the production renderer. */
37
39
  export const FIRST_RUN_MENU_CHOICES = formatProviderMenu(orderProviderChoices());
40
+ export const FIRST_RUN_MENU_CHOICE_MARKERS = [FIRST_RUN_MENU_CHOICES, FIRST_RUN_PROVIDER_SETUP_MENU_CHOICES] as const;
38
41
  /** Line `runFirstRun` prints before a fresh install has to pick a provider. */
39
42
  export const FIRST_RUN_SETUP_HINT = 'eln setup llm 으로 고르세요';
40
- /** Misses the parser must reject and re-ask: out of range, exponent, full-width, then 1. */
41
- export const FIRST_RUN_MENU_ANSWERS = ['4', '1e0', '1', '1'] as const;
43
+ /** Misses the parser must reject: out of range, exponent, and full-width digits. */
44
+ export const FIRST_RUN_MENU_ANSWERS = ['4', '1e0', '1'] as const;
42
45
 
43
46
  const repoRoot = resolve(import.meta.dir, '../..');
44
47
  const cliEntry = join(repoRoot, 'bin', 'elanous.mjs');
@@ -196,6 +199,7 @@ export async function driveFirstRunMenu(
196
199
  let stdout = '';
197
200
  let stderr = '';
198
201
  let seen = 0;
202
+ let keyPasteAnswered = false;
199
203
  const answersSent: string[] = [];
200
204
  let closed = false;
201
205
  let timedOut = false;
@@ -209,13 +213,19 @@ export async function driveFirstRunMenu(
209
213
 
210
214
  child.stdout.on('data', (chunk: Buffer) => {
211
215
  stdout += chunk.toString('utf8');
212
- const count = stdout.split(FIRST_RUN_MENU_MARKER).length - 1;
216
+ const count = countFirstRunMenuRenders(stdout);
213
217
  while (seen < count) {
214
218
  seen += 1;
215
219
  setTimeout(() => {
216
220
  if (!closed) writeNext();
217
221
  }, answerDelayMs);
218
222
  }
223
+ if (!keyPasteAnswered && stdout.includes('.env 형식 키를 붙여 넣고 빈 줄로 끝내세요')) {
224
+ keyPasteAnswered = true;
225
+ setTimeout(() => {
226
+ if (!closed) child.stdin.write('\n');
227
+ }, answerDelayMs);
228
+ }
219
229
  });
220
230
  child.stderr.on('data', (chunk: Buffer) => {
221
231
  stderr += chunk.toString('utf8');
@@ -253,7 +263,7 @@ export async function driveFirstRunMenu(
253
263
  stderr,
254
264
  status,
255
265
  timedOut,
256
- menuRenderCount: Math.min(seen, stdout.split(FIRST_RUN_MENU_MARKER).length - 1),
266
+ menuRenderCount: Math.min(seen, countFirstRunMenuRenders(stdout)),
257
267
  answersSent,
258
268
  finalPhrase: stdout.includes(FIRST_RUN_SETUP_HINT) ? FIRST_RUN_SETUP_HINT : null,
259
269
  readyRecorded,
@@ -13,7 +13,8 @@ export interface ReleaseSimRigCase {
13
13
  id: string;
14
14
  mode?: 'baseline' | 'cut-tip-moved-after-resume';
15
15
  fault?: { node: string; outcome: 'fail' | 'error' | 'timeout'; evidence?: Record<string, unknown> };
16
- expect: { status: 'done' | 'failed' | 'resume-refused'; mustVisit: string[]; mustNotVisit: string[] };
16
+ nodeOutcomes?: Record<string, { outcome: 'ok' | 'fail' | 'error'; delayMs?: number }>;
17
+ expect: { status: 'done' | 'failed' | 'resume-refused'; mustVisit: string[]; mustNotVisit: string[]; overlap?: [string, string]; refusalIncludes?: string };
17
18
  }
18
19
 
19
20
  export interface ReleaseSimRigScenario {
@@ -32,7 +33,9 @@ export interface ReleaseSimRigCaseResult {
32
33
  path: string[];
33
34
  dispatchedNodes: string[];
34
35
  unexpectedEdges: Array<{ from: string; to: string; outcome: string; expectedTo?: string }>;
35
- checks: { status: boolean; mustVisit: boolean; mustNotVisit: boolean; ledgerEvents: boolean };
36
+ checks: { status: boolean; mustVisit: boolean; mustNotVisit: boolean; overlap: boolean; ledgerEvents: boolean };
37
+ fanOuts?: GraphRunState['fanOuts'];
38
+ nodeTimings?: Record<string, { startedAtMs: number; endedAtMs: number }>;
36
39
  injectedEvidence: Record<string, unknown>;
37
40
  ledgerEvents: Array<Record<string, unknown>>;
38
41
  statePath: string;
@@ -46,6 +49,7 @@ function unexpectedEdges(path: string[], state: GraphRunState, edges: Map<string
46
49
  const from = path[index]!;
47
50
  const to = path[index + 1]!;
48
51
  const edge = edges.get(from);
52
+ if (edge?.branches && edge.join === to) continue; // The runner records a fan-out's barrier as the parent-path successor.
49
53
  const output = nodes.get(from)?.output;
50
54
  let parsed: Record<string, unknown> = {};
51
55
  if (typeof output === 'string') {
@@ -100,8 +104,10 @@ function releaseGraphShape(): { nodeIds: Set<string>; edges: Map<string, Record<
100
104
  const edges = new Map<string, Record<string, unknown>>();
101
105
  for (const raw of graph.edges) {
102
106
  const edge = record(raw, 'release edge');
103
- if (typeof edge.from !== 'string' || edge.on !== 'outcome' || !edge.map || typeof edge.map !== 'object') {
104
- throw new Error('release simulation requires outcome edges with explicit maps');
107
+ const mapped = !!edge.map && typeof edge.map === 'object';
108
+ const branched = !!edge.branches && typeof edge.branches === 'object' && typeof edge.join === 'string';
109
+ if (typeof edge.from !== 'string' || edge.on !== 'outcome' || (!mapped && !branched)) {
110
+ throw new Error('release simulation requires outcome edges with explicit maps or fan-out joins');
105
111
  }
106
112
  if (edges.has(edge.from)) throw new Error(`release graph has multiple outcome edges from ${edge.from}`);
107
113
  edges.set(edge.from, edge);
@@ -128,7 +134,7 @@ export function parseReleaseSimRigScenario(source: string): ReleaseSimRigScenari
128
134
  const ids = new Set<string>();
129
135
  const cases = rawCases.map((raw, index): ReleaseSimRigCase => {
130
136
  const row = record(raw, `scenario.cases[${index}]`);
131
- exactKeys(row, ['id', 'mode', 'fault', 'expect'], `scenario.cases[${index}]`);
137
+ exactKeys(row, ['id', 'mode', 'fault', 'nodeOutcomes', 'expect'], `scenario.cases[${index}]`);
132
138
  if (typeof row.id !== 'string' || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(row.id) || ids.has(row.id)) throw new Error(`scenario.cases[${index}].id must be unique lowercase text`);
133
139
  ids.add(row.id);
134
140
  let mode: ReleaseSimRigCase['mode'];
@@ -145,14 +151,35 @@ export function parseReleaseSimRigScenario(source: string): ReleaseSimRigScenari
145
151
  fault = { node: parsed.node, outcome: parsed.outcome, ...(parsed.evidence === undefined ? {} : { evidence: record(parsed.evidence, `scenario.cases[${index}].fault.evidence`) }) };
146
152
  }
147
153
  if ((mode === undefined) === (fault === undefined)) throw new Error(`scenario.cases[${index}] requires exactly one of mode or fault`);
154
+ const nodeOutcomes: ReleaseSimRigCase['nodeOutcomes'] = {};
155
+ if (row.nodeOutcomes !== undefined) {
156
+ const rawOutcomes = record(row.nodeOutcomes, `scenario.cases[${index}].nodeOutcomes`);
157
+ for (const [node, value] of Object.entries(rawOutcomes)) {
158
+ if (!nodeIds.has(node)) throw new Error(`scenario.cases[${index}].nodeOutcomes names unknown release node ${node}`);
159
+ const injection = record(value, `scenario.cases[${index}].nodeOutcomes.${node}`);
160
+ exactKeys(injection, ['outcome', 'delayMs'], `scenario.cases[${index}].nodeOutcomes.${node}`);
161
+ if (injection.outcome !== 'ok' && injection.outcome !== 'fail' && injection.outcome !== 'error') throw new Error(`scenario.cases[${index}].nodeOutcomes.${node}.outcome is invalid`);
162
+ if (injection.delayMs !== undefined && (!Number.isSafeInteger(injection.delayMs) || (injection.delayMs as number) < 0 || (injection.delayMs as number) > 60_000)) throw new Error(`scenario.cases[${index}].nodeOutcomes.${node}.delayMs must be 0–60000`);
163
+ nodeOutcomes[node] = { outcome: injection.outcome, ...(injection.delayMs === undefined ? {} : { delayMs: injection.delayMs as number }) };
164
+ }
165
+ }
148
166
  const expected = record(row.expect, `scenario.cases[${index}].expect`);
149
- exactKeys(expected, ['status', 'mustVisit', 'mustNotVisit'], `scenario.cases[${index}].expect`);
167
+ exactKeys(expected, ['status', 'mustVisit', 'mustNotVisit', 'overlap', 'refusalIncludes'], `scenario.cases[${index}].expect`);
150
168
  if (expected.status !== 'done' && expected.status !== 'failed' && expected.status !== 'resume-refused') throw new Error(`scenario.cases[${index}].expect.status is invalid`);
151
169
  const mustVisit = stringList(expected.mustVisit, `scenario.cases[${index}].expect.mustVisit`);
152
170
  const mustNotVisit = stringList(expected.mustNotVisit, `scenario.cases[${index}].expect.mustNotVisit`);
171
+ const refusalIncludes = expected.refusalIncludes;
172
+ if (refusalIncludes !== undefined && (typeof refusalIncludes !== 'string' || !refusalIncludes.trim())) throw new Error(`scenario.cases[${index}].expect.refusalIncludes must be nonempty text`);
173
+ let overlap: [string, string] | undefined;
174
+ if (expected.overlap !== undefined) {
175
+ const pair = stringList(expected.overlap, `scenario.cases[${index}].expect.overlap`);
176
+ if (pair.length !== 2 || pair[0] === pair[1] || pair.some((id) => !nodeIds.has(id))) throw new Error(`scenario.cases[${index}].expect.overlap must name two different release nodes`);
177
+ overlap = [pair[0]!, pair[1]!];
178
+ }
153
179
  for (const id of [...mustVisit, ...mustNotVisit]) if (!nodeIds.has(id)) throw new Error(`scenario.cases[${index}] names unknown release node ${id}`);
154
180
  if (mustVisit.some((id) => mustNotVisit.includes(id))) throw new Error(`scenario.cases[${index}] visits and excludes the same node`);
155
- return { id: row.id, ...(mode ? { mode } : {}), ...(fault ? { fault } : {}), expect: { status: expected.status, mustVisit, mustNotVisit } };
181
+ return { id: row.id, ...(mode ? { mode } : {}), ...(fault ? { fault } : {}), ...(Object.keys(nodeOutcomes).length ? { nodeOutcomes } : {}),
182
+ expect: { status: expected.status, mustVisit, mustNotVisit, ...(overlap ? { overlap } : {}), ...(typeof refusalIncludes === 'string' ? { refusalIncludes } : {}) } };
156
183
  });
157
184
  return { version: 1, kind: 'release-graph', id: root.id, isolation: 'test',
158
185
  input: { version: input.version, previousVersion: input.previousVersion }, cases };
@@ -182,11 +209,18 @@ async function runCase(scenario: ReleaseSimRigScenario, item: ReleaseSimRigCase,
182
209
  const runId = `release-sim-${scenario.id}-${item.id}`;
183
210
  const ledgerEvents: Array<Record<string, unknown>> = [];
184
211
  const dispatchedNodes: string[] = [];
212
+ const nodeTimings: NonNullable<ReleaseSimRigCaseResult['nodeTimings']> = {};
185
213
  const runBash = async (command: string, options: { env?: NodeJS.ProcessEnv }) => {
186
214
  const { nodeId } = parseContext(options.env ?? {});
187
215
  if (!command.trim()) throw new Error(`empty command at simulated node ${nodeId}`);
188
216
  dispatchedNodes.push(nodeId);
189
- const result = resultForNode(nodeId, item.fault, scenario.input.version);
217
+ const startedAtMs = performance.now();
218
+ const injection = item.nodeOutcomes?.[nodeId];
219
+ const result = injection ? resultForNode(nodeId, injection.outcome === 'ok' ? undefined : {
220
+ node: nodeId, outcome: injection.outcome, evidence: {},
221
+ }, scenario.input.version) : resultForNode(nodeId, item.fault, scenario.input.version);
222
+ if (injection?.delayMs) await new Promise((resolve) => setTimeout(resolve, injection.delayMs));
223
+ nodeTimings[nodeId] = { startedAtMs, endedAtMs: performance.now() };
190
224
  return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
191
225
  };
192
226
  const capture = (event: string, data: Record<string, unknown>) => ledgerEvents.push({ event, ...data });
@@ -209,15 +243,20 @@ async function runCase(scenario: ReleaseSimRigScenario, item: ReleaseSimRigCase,
209
243
  const interrupted = listGraphRuns(root).runs.find((run) => run.runId === runId);
210
244
  const stateFile = interrupted?.statePath ?? '';
211
245
  const path = interrupted?.path ?? [];
246
+ const visited = new Set([...path, ...Object.values(interrupted?.fanOuts ?? {}).flatMap((fanout) => Object.keys(fanout.branches))]);
212
247
  recordObservedEdges(path, ledgerEvents);
213
248
  const edgeIssues = interrupted ? unexpectedEdges(path, interrupted, edges) : [];
214
- const statusOk = item.expect.status === 'resume-refused' && refusal.includes('release command source differs from the saved cut tip');
215
- const visitOk = item.expect.mustVisit.every((id) => path.includes(id));
216
- const notVisitOk = item.expect.mustNotVisit.every((id) => !path.includes(id));
249
+ const statusOk = item.expect.status === 'resume-refused' && refusal.includes(item.expect.refusalIncludes ?? 'release command source differs from the saved cut tip');
250
+ const visitOk = item.expect.mustVisit.every((id) => visited.has(id));
251
+ const notVisitOk = item.expect.mustNotVisit.every((id) => !visited.has(id));
252
+ const overlapPair = item.expect.overlap;
253
+ const overlapOk = !overlapPair || (!!nodeTimings[overlapPair[0]] && !!nodeTimings[overlapPair[1]] &&
254
+ nodeTimings[overlapPair[0]]!.startedAtMs < nodeTimings[overlapPair[1]]!.endedAtMs &&
255
+ nodeTimings[overlapPair[1]]!.startedAtMs < nodeTimings[overlapPair[0]]!.endedAtMs);
217
256
  const ledgerOk = ledgerEvents.some((row) => row.event === 'node-end')
218
257
  && ledgerEvents.filter((row) => row.event === 'edge-observed').length === Math.max(0, path.length - 1);
219
- return { id: item.id, pass: statusOk && visitOk && notVisitOk && ledgerOk && edgeIssues.length === 0, status: statusOk ? 'resume-refused' : interrupted?.status ?? 'missing',
220
- path, dispatchedNodes, unexpectedEdges: edgeIssues, checks: { status: statusOk, mustVisit: visitOk, mustNotVisit: notVisitOk, ledgerEvents: ledgerOk }, injectedEvidence: {}, ledgerEvents,
258
+ return { id: item.id, pass: statusOk && visitOk && notVisitOk && overlapOk && ledgerOk && edgeIssues.length === 0, status: statusOk ? 'resume-refused' : interrupted?.status ?? 'missing',
259
+ path, dispatchedNodes, unexpectedEdges: edgeIssues, checks: { status: statusOk, mustVisit: visitOk, mustNotVisit: notVisitOk, overlap: overlapOk, ledgerEvents: ledgerOk }, injectedEvidence: {}, ledgerEvents,
221
260
  statePath: stateFile, ...(refusal ? { refusal } : {}) };
222
261
  }
223
262
 
@@ -225,17 +264,22 @@ async function runCase(scenario: ReleaseSimRigScenario, item: ReleaseSimRigCase,
225
264
  const state = await runGraph(RELEASE_GRAPH, { runId, input: scenario.input, pinChildUniverse: true, quiet: true,
226
265
  deps: { root, runBash, log: capture } });
227
266
  const path = state.path;
267
+ const visited = new Set([...path, ...Object.values(state.fanOuts ?? {}).flatMap((fanout) => Object.keys(fanout.branches))]);
228
268
  recordObservedEdges(path, ledgerEvents);
229
269
  const edgeIssues = unexpectedEdges(path, state, edges);
230
270
  const statusOk = state.status === item.expect.status;
231
- const visitOk = item.expect.mustVisit.every((id) => path.includes(id));
232
- const notVisitOk = item.expect.mustNotVisit.every((id) => !path.includes(id));
271
+ const visitOk = item.expect.mustVisit.every((id) => visited.has(id));
272
+ const notVisitOk = item.expect.mustNotVisit.every((id) => !visited.has(id));
273
+ const overlapPair = item.expect.overlap;
274
+ const overlapOk = !overlapPair || (!!nodeTimings[overlapPair[0]] && !!nodeTimings[overlapPair[1]] &&
275
+ nodeTimings[overlapPair[0]]!.startedAtMs < nodeTimings[overlapPair[1]]!.endedAtMs &&
276
+ nodeTimings[overlapPair[1]]!.startedAtMs < nodeTimings[overlapPair[0]]!.endedAtMs);
233
277
  const ledgerOk = ledgerEvents.some((row) => row.event === 'node-start') && ledgerEvents.some((row) => row.event === 'node-end')
234
278
  && ledgerEvents.filter((row) => row.event === 'edge-observed').length === Math.max(0, path.length - 1);
235
279
  const injectedEvidence = item.fault ? item.fault.evidence ?? {} : {};
236
- return { id: item.id, pass: statusOk && visitOk && notVisitOk && ledgerOk && edgeIssues.length === 0, status: state.status, path, dispatchedNodes, unexpectedEdges: edgeIssues,
237
- checks: { status: statusOk, mustVisit: visitOk, mustNotVisit: notVisitOk, ledgerEvents: ledgerOk }, injectedEvidence,
238
- ledgerEvents, statePath: state.statePath };
280
+ return { id: item.id, pass: statusOk && visitOk && notVisitOk && overlapOk && ledgerOk && edgeIssues.length === 0, status: state.status, path, dispatchedNodes, unexpectedEdges: edgeIssues,
281
+ checks: { status: statusOk, mustVisit: visitOk, mustNotVisit: notVisitOk, overlap: overlapOk, ledgerEvents: ledgerOk }, injectedEvidence,
282
+ fanOuts: state.fanOuts, nodeTimings, ledgerEvents, statePath: state.statePath };
239
283
  }
240
284
 
241
285
  export async function runReleaseSimRigScenario(source: string): Promise<ReleaseSimRigResult> {