@ashlr/hub 3.13.0 → 3.14.0

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 (625) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/authority-surface.json +204 -124
  3. package/dist/build-identity.json +2 -2
  4. package/dist/cli/authority.js +112 -18
  5. package/dist/cli/authority.js.map +1 -1
  6. package/dist/cli/comms.d.ts +33 -19
  7. package/dist/cli/comms.js +128 -151
  8. package/dist/cli/comms.js.map +1 -1
  9. package/dist/cli/completions.js +1 -1
  10. package/dist/cli/completions.js.map +1 -1
  11. package/dist/cli/daemon.js +29 -0
  12. package/dist/cli/daemon.js.map +1 -1
  13. package/dist/cli/director.d.ts +8 -12
  14. package/dist/cli/director.js +17 -52
  15. package/dist/cli/director.js.map +1 -1
  16. package/dist/cli/fleet.js +4 -1
  17. package/dist/cli/fleet.js.map +1 -1
  18. package/dist/cli/help.js +1 -0
  19. package/dist/cli/help.js.map +1 -1
  20. package/dist/cli/leader.d.ts +27 -3
  21. package/dist/cli/leader.js +253 -4
  22. package/dist/cli/leader.js.map +1 -1
  23. package/dist/core/authority/server-enforcement.d.ts +110 -0
  24. package/dist/core/authority/server-enforcement.js +260 -0
  25. package/dist/core/authority/server-enforcement.js.map +1 -0
  26. package/dist/core/authority/standing-grant.d.ts +24 -4
  27. package/dist/core/authority/standing-grant.js +19 -3
  28. package/dist/core/authority/standing-grant.js.map +1 -1
  29. package/dist/core/cloud/timeline.js +13 -7
  30. package/dist/core/cloud/timeline.js.map +1 -1
  31. package/dist/core/comms/change-digest.d.ts +130 -0
  32. package/dist/core/comms/change-digest.js +451 -0
  33. package/dist/core/comms/change-digest.js.map +1 -0
  34. package/dist/core/comms/director-prompt.d.ts +4 -5
  35. package/dist/core/comms/director-prompt.js +4 -71
  36. package/dist/core/comms/director-prompt.js.map +1 -1
  37. package/dist/core/comms/director.d.ts +24 -61
  38. package/dist/core/comms/director.js +29 -382
  39. package/dist/core/comms/director.js.map +1 -1
  40. package/dist/core/comms/dispatch.d.ts +37 -12
  41. package/dist/core/comms/dispatch.js +244 -177
  42. package/dist/core/comms/dispatch.js.map +1 -1
  43. package/dist/core/comms/elon-dialogue.d.ts +23 -15
  44. package/dist/core/comms/elon-dialogue.js +36 -307
  45. package/dist/core/comms/elon-dialogue.js.map +1 -1
  46. package/dist/core/comms/fleet-pulse.js +4 -7
  47. package/dist/core/comms/fleet-pulse.js.map +1 -1
  48. package/dist/core/comms/handlers.d.ts +10 -6
  49. package/dist/core/comms/handlers.js +14 -48
  50. package/dist/core/comms/handlers.js.map +1 -1
  51. package/dist/core/comms/migrations.d.ts +47 -0
  52. package/dist/core/comms/migrations.js +125 -0
  53. package/dist/core/comms/migrations.js.map +1 -0
  54. package/dist/core/comms/requests.d.ts +32 -5
  55. package/dist/core/comms/requests.js +101 -5
  56. package/dist/core/comms/requests.js.map +1 -1
  57. package/dist/core/comms/telegram-channel.d.ts +104 -0
  58. package/dist/core/comms/telegram-channel.js +622 -0
  59. package/dist/core/comms/telegram-channel.js.map +1 -0
  60. package/dist/core/comms/telegram-thread-map.d.ts +56 -0
  61. package/dist/core/comms/telegram-thread-map.js +144 -0
  62. package/dist/core/comms/telegram-thread-map.js.map +1 -0
  63. package/dist/core/daemon/capacity-publisher.d.ts +8 -1
  64. package/dist/core/daemon/capacity-publisher.js +40 -2
  65. package/dist/core/daemon/capacity-publisher.js.map +1 -1
  66. package/dist/core/daemon/loop.js +18 -4
  67. package/dist/core/daemon/loop.js.map +1 -1
  68. package/dist/core/daemon/tick-deadline.d.ts +44 -0
  69. package/dist/core/daemon/tick-deadline.js +83 -0
  70. package/dist/core/daemon/tick-deadline.js.map +1 -0
  71. package/dist/core/daemon/tick-hooks.d.ts +7 -0
  72. package/dist/core/daemon/tick-hooks.js.map +1 -1
  73. package/dist/core/daemon/tick-progress.d.ts +39 -0
  74. package/dist/core/daemon/tick-progress.js +194 -0
  75. package/dist/core/daemon/tick-progress.js.map +1 -0
  76. package/dist/core/dashboard.js +3 -1
  77. package/dist/core/dashboard.js.map +1 -1
  78. package/dist/core/fleet/fleet-merge-state.d.ts +6 -0
  79. package/dist/core/fleet/fleet-merge-state.js.map +1 -1
  80. package/dist/core/fleet/host-merge.d.ts +9 -0
  81. package/dist/core/fleet/host-merge.js +13 -2
  82. package/dist/core/fleet/host-merge.js.map +1 -1
  83. package/dist/core/fleet/merge-gates.d.ts +13 -0
  84. package/dist/core/fleet/merge-gates.js +14 -0
  85. package/dist/core/fleet/merge-gates.js.map +1 -1
  86. package/dist/core/fleet/mirrors.d.ts +162 -6
  87. package/dist/core/fleet/mirrors.js +1051 -49
  88. package/dist/core/fleet/mirrors.js.map +1 -1
  89. package/dist/core/fleet/standing-merge-pass.d.ts +8 -0
  90. package/dist/core/fleet/standing-merge-pass.js +72 -1
  91. package/dist/core/fleet/standing-merge-pass.js.map +1 -1
  92. package/dist/core/fleet/status.d.ts +17 -0
  93. package/dist/core/fleet/status.js +22 -0
  94. package/dist/core/fleet/status.js.map +1 -1
  95. package/dist/core/fleet/tick-hooks-live.d.ts +1 -1
  96. package/dist/core/fleet/tick-hooks-live.js +13 -3
  97. package/dist/core/fleet/tick-hooks-live.js.map +1 -1
  98. package/dist/core/git.d.ts +17 -0
  99. package/dist/core/git.js +124 -25
  100. package/dist/core/git.js.map +1 -1
  101. package/dist/core/goals/open-goals.d.ts +47 -0
  102. package/dist/core/goals/open-goals.js +33 -0
  103. package/dist/core/goals/open-goals.js.map +1 -0
  104. package/dist/core/inbox/merge.d.ts +5 -0
  105. package/dist/core/inbox/merge.js +58 -2
  106. package/dist/core/inbox/merge.js.map +1 -1
  107. package/dist/core/integrations/locus.d.ts +28 -0
  108. package/dist/core/integrations/locus.js +155 -30
  109. package/dist/core/integrations/locus.js.map +1 -1
  110. package/dist/core/integrations/telegram-format.d.ts +40 -0
  111. package/dist/core/integrations/telegram-format.js +123 -0
  112. package/dist/core/integrations/telegram-format.js.map +1 -0
  113. package/dist/core/integrations/telegram.d.ts +60 -4
  114. package/dist/core/integrations/telegram.js +161 -28
  115. package/dist/core/integrations/telegram.js.map +1 -1
  116. package/dist/core/mcp-registry.d.ts +12 -0
  117. package/dist/core/mcp-registry.js +70 -0
  118. package/dist/core/mcp-registry.js.map +1 -1
  119. package/dist/core/observability/rollup.d.ts +12 -10
  120. package/dist/core/observability/rollup.js +44 -17
  121. package/dist/core/observability/rollup.js.map +1 -1
  122. package/dist/core/resources/connection-monitor.d.ts +9 -0
  123. package/dist/core/resources/connection-monitor.js +19 -9
  124. package/dist/core/resources/connection-monitor.js.map +1 -1
  125. package/dist/core/resources/quota-refresh-lease.d.ts +17 -0
  126. package/dist/core/resources/quota-refresh-lease.js +34 -1
  127. package/dist/core/resources/quota-refresh-lease.js.map +1 -1
  128. package/dist/core/routing/budget-api.d.ts +7 -1
  129. package/dist/core/routing/budget-api.js +56 -2
  130. package/dist/core/routing/budget-api.js.map +1 -1
  131. package/dist/core/routing/readiness-types.d.ts +82 -0
  132. package/dist/core/routing/readiness-types.js +23 -0
  133. package/dist/core/routing/readiness-types.js.map +1 -0
  134. package/dist/core/routing/readiness.d.ts +103 -0
  135. package/dist/core/routing/readiness.js +480 -0
  136. package/dist/core/routing/readiness.js.map +1 -0
  137. package/dist/core/sandbox/confine.js +22 -1
  138. package/dist/core/sandbox/confine.js.map +1 -1
  139. package/dist/core/sandbox/policy.d.ts +23 -0
  140. package/dist/core/sandbox/policy.js +100 -0
  141. package/dist/core/sandbox/policy.js.map +1 -1
  142. package/dist/core/types.d.ts +13 -0
  143. package/dist/core/types.js.map +1 -1
  144. package/dist/core/universe/builtins/preparation/manifest.json +1 -1
  145. package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +1204 -939
  146. package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +1319 -1054
  147. package/dist/core/usage/frontier-usage.d.ts +20 -2
  148. package/dist/core/usage/frontier-usage.js +75 -17
  149. package/dist/core/usage/frontier-usage.js.map +1 -1
  150. package/dist/core/verse/accounts.d.ts +45 -0
  151. package/dist/core/verse/accounts.js +246 -17
  152. package/dist/core/verse/accounts.js.map +1 -1
  153. package/dist/core/verse/apps-api.js +23 -11
  154. package/dist/core/verse/apps-api.js.map +1 -1
  155. package/dist/core/verse/apps.d.ts +11 -9
  156. package/dist/core/verse/apps.js +2 -2
  157. package/dist/core/verse/apps.js.map +1 -1
  158. package/dist/core/verse/authority-api.d.ts +8 -2
  159. package/dist/core/verse/authority-api.js +40 -5
  160. package/dist/core/verse/authority-api.js.map +1 -1
  161. package/dist/core/verse/autonomy-ladder.d.ts +172 -0
  162. package/dist/core/verse/autonomy-ladder.js +251 -0
  163. package/dist/core/verse/autonomy-ladder.js.map +1 -0
  164. package/dist/core/verse/context-fit.js +7 -5
  165. package/dist/core/verse/context-fit.js.map +1 -1
  166. package/dist/core/verse/control-api.d.ts +23 -1
  167. package/dist/core/verse/control-api.js +117 -10
  168. package/dist/core/verse/control-api.js.map +1 -1
  169. package/dist/core/verse/fleet-live-api.js +13 -5
  170. package/dist/core/verse/fleet-live-api.js.map +1 -1
  171. package/dist/core/verse/folder-io.d.ts +50 -0
  172. package/dist/core/verse/folder-io.js +142 -0
  173. package/dist/core/verse/folder-io.js.map +1 -0
  174. package/dist/core/verse/git-api.js +5 -4
  175. package/dist/core/verse/git-api.js.map +1 -1
  176. package/dist/core/verse/git-ops.d.ts +10 -1
  177. package/dist/core/verse/git-ops.js +18 -2
  178. package/dist/core/verse/git-ops.js.map +1 -1
  179. package/dist/core/verse/github-api.d.ts +1 -1
  180. package/dist/core/verse/github-api.js +5 -4
  181. package/dist/core/verse/github-api.js.map +1 -1
  182. package/dist/core/verse/github-repo.js +118 -14
  183. package/dist/core/verse/github-repo.js.map +1 -1
  184. package/dist/core/verse/leader-api.d.ts +5 -4
  185. package/dist/core/verse/leader-api.js +237 -10
  186. package/dist/core/verse/leader-api.js.map +1 -1
  187. package/dist/core/verse/local-models.d.ts +10 -0
  188. package/dist/core/verse/local-models.js +10 -1
  189. package/dist/core/verse/local-models.js.map +1 -1
  190. package/dist/core/verse/login-path.d.ts +73 -0
  191. package/dist/core/verse/login-path.js +123 -14
  192. package/dist/core/verse/login-path.js.map +1 -1
  193. package/dist/core/verse/mcp-control-api.js +4 -4
  194. package/dist/core/verse/mcp-control-api.js.map +1 -1
  195. package/dist/core/verse/mcp-scope.d.ts +22 -0
  196. package/dist/core/verse/mcp-scope.js +41 -1
  197. package/dist/core/verse/mcp-scope.js.map +1 -1
  198. package/dist/core/verse/mcp-seat-view.d.ts +10 -0
  199. package/dist/core/verse/mcp-seat-view.js +30 -4
  200. package/dist/core/verse/mcp-seat-view.js.map +1 -1
  201. package/dist/core/verse/overnight-api.js +20 -2
  202. package/dist/core/verse/overnight-api.js.map +1 -1
  203. package/dist/core/verse/path-guard.d.ts +24 -0
  204. package/dist/core/verse/path-guard.js +91 -22
  205. package/dist/core/verse/path-guard.js.map +1 -1
  206. package/dist/core/verse/preview-api.js +22 -0
  207. package/dist/core/verse/preview-api.js.map +1 -1
  208. package/dist/core/verse/projects.d.ts +21 -0
  209. package/dist/core/verse/projects.js +82 -0
  210. package/dist/core/verse/projects.js.map +1 -1
  211. package/dist/core/verse/session-controls-api.js +5 -3
  212. package/dist/core/verse/session-controls-api.js.map +1 -1
  213. package/dist/core/verse/session-handoff.d.ts +26 -0
  214. package/dist/core/verse/session-handoff.js +90 -12
  215. package/dist/core/verse/session-handoff.js.map +1 -1
  216. package/dist/core/verse/terminal-api.js +7 -4
  217. package/dist/core/verse/terminal-api.js.map +1 -1
  218. package/dist/core/verse/terminal.js +9 -5
  219. package/dist/core/verse/terminal.js.map +1 -1
  220. package/dist/core/verse/verse-api.js +81 -27
  221. package/dist/core/verse/verse-api.js.map +1 -1
  222. package/dist/core/verse/workspaces.d.ts +51 -0
  223. package/dist/core/verse/workspaces.js +177 -47
  224. package/dist/core/verse/workspaces.js.map +1 -1
  225. package/dist/core/vision/leader-apply.d.ts +40 -0
  226. package/dist/core/vision/leader-apply.js +101 -30
  227. package/dist/core/vision/leader-apply.js.map +1 -1
  228. package/dist/core/vision/leader-cadence.d.ts +114 -0
  229. package/dist/core/vision/leader-cadence.js +127 -0
  230. package/dist/core/vision/leader-cadence.js.map +1 -0
  231. package/dist/core/vision/leader-goal-evidence.d.ts +25 -0
  232. package/dist/core/vision/leader-goal-evidence.js +36 -0
  233. package/dist/core/vision/leader-goal-evidence.js.map +1 -0
  234. package/dist/core/vision/leader-health.d.ts +53 -0
  235. package/dist/core/vision/leader-health.js +92 -0
  236. package/dist/core/vision/leader-health.js.map +1 -0
  237. package/dist/core/vision/leader-operator.d.ts +176 -0
  238. package/dist/core/vision/leader-operator.js +355 -0
  239. package/dist/core/vision/leader-operator.js.map +1 -0
  240. package/dist/core/vision/leader-run-chain.d.ts +41 -0
  241. package/dist/core/vision/leader-run-chain.js +54 -0
  242. package/dist/core/vision/leader-run-chain.js.map +1 -0
  243. package/dist/core/vision/leader-seat-plan.d.ts +68 -0
  244. package/dist/core/vision/leader-seat-plan.js +93 -0
  245. package/dist/core/vision/leader-seat-plan.js.map +1 -0
  246. package/dist/core/vision/leader-seat.d.ts +71 -5
  247. package/dist/core/vision/leader-seat.js +235 -33
  248. package/dist/core/vision/leader-seat.js.map +1 -1
  249. package/dist/core/vision/leader-thread-types.d.ts +104 -0
  250. package/dist/core/vision/leader-thread-types.js +9 -0
  251. package/dist/core/vision/leader-thread-types.js.map +1 -0
  252. package/dist/core/vision/leader-thread.d.ts +138 -0
  253. package/dist/core/vision/leader-thread.js +926 -0
  254. package/dist/core/vision/leader-thread.js.map +1 -0
  255. package/dist/core/vision/leader-types.d.ts +75 -1
  256. package/dist/core/vision/leader.d.ts +88 -18
  257. package/dist/core/vision/leader.js +269 -69
  258. package/dist/core/vision/leader.js.map +1 -1
  259. package/dist/core/web/public/next/assets/{ActionMenu-Dwjk6rUQ.js → ActionMenu-CIiX2X8w.js} +2 -2
  260. package/dist/core/web/public/next/assets/{ActionMenu-Dwjk6rUQ.js.map → ActionMenu-CIiX2X8w.js.map} +1 -1
  261. package/dist/core/web/public/next/assets/Advanced-DHsysoIL.js +2 -0
  262. package/dist/core/web/public/next/assets/{Advanced-cVYTAsfB.js.map → Advanced-DHsysoIL.js.map} +1 -1
  263. package/dist/core/web/public/next/assets/{App-IsaWDsdF.js → App-CMeAocmW.js} +5 -5
  264. package/dist/core/web/public/next/assets/{App-IsaWDsdF.js.map → App-CMeAocmW.js.map} +1 -1
  265. package/dist/core/web/public/next/assets/AppsSection-DISYnMnc.js +2 -0
  266. package/dist/core/web/public/next/assets/{AppsSection-DDqeSrty.js.map → AppsSection-DISYnMnc.js.map} +1 -1
  267. package/dist/core/web/public/next/assets/AreaTrend-DK2Y2TbZ.js +2 -0
  268. package/dist/core/web/public/next/assets/AreaTrend-DK2Y2TbZ.js.map +1 -0
  269. package/dist/core/web/public/next/assets/{AutonomyOffState-CpFYS3tQ.js → AutonomyOffState-CEPSZToP.js} +3 -3
  270. package/dist/core/web/public/next/assets/{AutonomyOffState-CpFYS3tQ.js.map → AutonomyOffState-CEPSZToP.js.map} +1 -1
  271. package/dist/core/web/public/next/assets/AutonomySection-DWc3ciAD.js +2 -0
  272. package/dist/core/web/public/next/assets/{AutonomySection-Dwn8UtOy.js.map → AutonomySection-DWc3ciAD.js.map} +1 -1
  273. package/dist/core/web/public/next/assets/AutonomyStatus-CYaHjJ9U.js +2 -0
  274. package/dist/core/web/public/next/assets/AutonomyStatus-CYaHjJ9U.js.map +1 -0
  275. package/dist/core/web/public/next/assets/{BranchBar-ISZ7xUCj.js → BranchBar-BxhdiIpx.js} +2 -2
  276. package/dist/core/web/public/next/assets/{BranchBar-ISZ7xUCj.js.map → BranchBar-BxhdiIpx.js.map} +1 -1
  277. package/dist/core/web/public/next/assets/{BudgetControl-BARVp-En.js → BudgetControl-C-0KhjRS.js} +2 -2
  278. package/dist/core/web/public/next/assets/{BudgetControl-BARVp-En.js.map → BudgetControl-C-0KhjRS.js.map} +1 -1
  279. package/dist/core/web/public/next/assets/{Button-DtE0rlWD.js → Button-D90dzI_o.js} +2 -2
  280. package/dist/core/web/public/next/assets/{Button-DtE0rlWD.js.map → Button-D90dzI_o.js.map} +1 -1
  281. package/dist/core/web/public/next/assets/{CapacityStrip-DKbKA_Aa.js → CapacityStrip-qKDBC65C.js} +2 -2
  282. package/dist/core/web/public/next/assets/{CapacityStrip-DKbKA_Aa.js.map → CapacityStrip-qKDBC65C.js.map} +1 -1
  283. package/dist/core/web/public/next/assets/ChartFrame-DY-GVUb3.js +2 -0
  284. package/dist/core/web/public/next/assets/ChartFrame-DY-GVUb3.js.map +1 -0
  285. package/dist/core/web/public/next/assets/ChartFrame-DyjmyV8N.css +1 -0
  286. package/dist/core/web/public/next/assets/ChatSection-DlT4QU6a.js +3 -0
  287. package/dist/core/web/public/next/assets/{ChatSection-C9myY4ei.js.map → ChatSection-DlT4QU6a.js.map} +1 -1
  288. package/dist/core/web/public/next/assets/{CloudBudgetForm-CvjK4Oh6.js → CloudBudgetForm-BrNun_Yu.js} +2 -2
  289. package/dist/core/web/public/next/assets/{CloudBudgetForm-CvjK4Oh6.js.map → CloudBudgetForm-BrNun_Yu.js.map} +1 -1
  290. package/dist/core/web/public/next/assets/CommandPalette-C5lDDKN0.js +2 -0
  291. package/dist/core/web/public/next/assets/CommandPalette-C5lDDKN0.js.map +1 -0
  292. package/dist/core/web/public/next/assets/CommandSection-B0xuU-yZ.css +1 -0
  293. package/dist/core/web/public/next/assets/CommandSection-DXFvPgKp.js +3 -0
  294. package/dist/core/web/public/next/assets/CommandSection-DXFvPgKp.js.map +1 -0
  295. package/dist/core/web/public/next/assets/{ConfirmDialog-CLUhzaBj.js → ConfirmDialog-BR4nZQ2D.js} +2 -2
  296. package/dist/core/web/public/next/assets/{ConfirmDialog-CLUhzaBj.js.map → ConfirmDialog-BR4nZQ2D.js.map} +1 -1
  297. package/dist/core/web/public/next/assets/{DeleteChatDialog-C_eDhV8b.js → DeleteChatDialog-BCfP12GH.js} +2 -2
  298. package/dist/core/web/public/next/assets/{DeleteChatDialog-C_eDhV8b.js.map → DeleteChatDialog-BCfP12GH.js.map} +1 -1
  299. package/dist/core/web/public/next/assets/{Dialog-BRd_B9OE.js → Dialog-D3msQlCj.js} +2 -2
  300. package/dist/core/web/public/next/assets/{Dialog-BRd_B9OE.js.map → Dialog-D3msQlCj.js.map} +1 -1
  301. package/dist/core/web/public/next/assets/{DiffPane-Cpr9soB2.js → DiffPane-Ix6hvXlY.js} +2 -2
  302. package/dist/core/web/public/next/assets/{DiffPane-Cpr9soB2.js.map → DiffPane-Ix6hvXlY.js.map} +1 -1
  303. package/dist/core/web/public/next/assets/{DiffViewer-CNwd0W3Q.js → DiffViewer-C4WKsCIe.js} +2 -2
  304. package/dist/core/web/public/next/assets/{DiffViewer-CNwd0W3Q.js.map → DiffViewer-C4WKsCIe.js.map} +1 -1
  305. package/dist/core/web/public/next/assets/DockHost-aWP7liri.js +2 -0
  306. package/dist/core/web/public/next/assets/{DockHost-BcEq2qaS.js.map → DockHost-aWP7liri.js.map} +1 -1
  307. package/dist/core/web/public/next/assets/{EmptyState-DsN1H6MC.js → EmptyState-D2IRy3Cg.js} +2 -2
  308. package/dist/core/web/public/next/assets/{EmptyState-DsN1H6MC.js.map → EmptyState-D2IRy3Cg.js.map} +1 -1
  309. package/dist/core/web/public/next/assets/{Epistemic-fycQTBRO.js → Epistemic-DMr18muX.js} +2 -2
  310. package/dist/core/web/public/next/assets/{Epistemic-fycQTBRO.js.map → Epistemic-DMr18muX.js.map} +1 -1
  311. package/dist/core/web/public/next/assets/{EvidenceTimeline-sCCAdnBK.js → EvidenceTimeline-DXmmz6Fi.js} +2 -2
  312. package/dist/core/web/public/next/assets/{EvidenceTimeline-sCCAdnBK.js.map → EvidenceTimeline-DXmmz6Fi.js.map} +1 -1
  313. package/dist/core/web/public/next/assets/FleetSection-BfplcwFU.js +3 -0
  314. package/dist/core/web/public/next/assets/FleetSection-BfplcwFU.js.map +1 -0
  315. package/dist/core/web/public/next/assets/Funnel-Dh2yVHws.js +2 -0
  316. package/dist/core/web/public/next/assets/Funnel-Dh2yVHws.js.map +1 -0
  317. package/dist/core/web/public/next/assets/{GearTray-CpDt0xwj.js → GearTray-Dt-ee32-.js} +2 -2
  318. package/dist/core/web/public/next/assets/{GearTray-CpDt0xwj.js.map → GearTray-Dt-ee32-.js.map} +1 -1
  319. package/dist/core/web/public/next/assets/GrowthSection-P9EUfGeA.js +2 -0
  320. package/dist/core/web/public/next/assets/{GrowthSection-BvZezOsX.js.map → GrowthSection-P9EUfGeA.js.map} +1 -1
  321. package/dist/core/web/public/next/assets/{HandoffDialog-B1G6gQyk.js → HandoffDialog-CLJQLe7M.js} +2 -2
  322. package/dist/core/web/public/next/assets/{HandoffDialog-B1G6gQyk.js.map → HandoffDialog-CLJQLe7M.js.map} +1 -1
  323. package/dist/core/web/public/next/assets/{Input-CI0yBHmn.js → Input-D_KRJA9V.js} +2 -2
  324. package/dist/core/web/public/next/assets/{Input-CI0yBHmn.js.map → Input-D_KRJA9V.js.map} +1 -1
  325. package/dist/core/web/public/next/assets/LeaderCard-D-7DlJuR.js +2 -0
  326. package/dist/core/web/public/next/assets/LeaderCard-D-7DlJuR.js.map +1 -0
  327. package/dist/core/web/public/next/assets/LeaderCard-DNsbLwY3.css +1 -0
  328. package/dist/core/web/public/next/assets/LeaderConversation-DGZjWI-E.js +2 -0
  329. package/dist/core/web/public/next/assets/LeaderConversation-DGZjWI-E.js.map +1 -0
  330. package/dist/core/web/public/next/assets/LeaderConversation-DPHUTq6W.css +1 -0
  331. package/dist/core/web/public/next/assets/MatrixHeatmap-C7BCG2d7.js +2 -0
  332. package/dist/core/web/public/next/assets/MatrixHeatmap-C7BCG2d7.js.map +1 -0
  333. package/dist/core/web/public/next/assets/McpSection-DGbRcyv8.js +2 -0
  334. package/dist/core/web/public/next/assets/{McpSection-nuXer4K-.js.map → McpSection-DGbRcyv8.js.map} +1 -1
  335. package/dist/core/web/public/next/assets/{MessageMarkdown-BCe4TsXk.js → MessageMarkdown-DFvk06qG.js} +3 -3
  336. package/dist/core/web/public/next/assets/{MessageMarkdown-BCe4TsXk.js.map → MessageMarkdown-DFvk06qG.js.map} +1 -1
  337. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DL3LU5kL.js → MessageMarkdownRenderer-BAv4oEUf.js} +2 -2
  338. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DL3LU5kL.js.map → MessageMarkdownRenderer-BAv4oEUf.js.map} +1 -1
  339. package/dist/core/web/public/next/assets/{Meter-b69LM0mU.js → Meter-CMj-VafN.js} +2 -2
  340. package/dist/core/web/public/next/assets/{Meter-b69LM0mU.js.map → Meter-CMj-VafN.js.map} +1 -1
  341. package/dist/core/web/public/next/assets/MindSection-C6kLPIjt.js +3 -0
  342. package/dist/core/web/public/next/assets/MindSection-C6kLPIjt.js.map +1 -0
  343. package/dist/core/web/public/next/assets/{MutationTokenDialog-Bm34BNVV.js → MutationTokenDialog-DbnO8aYi.js} +2 -2
  344. package/dist/core/web/public/next/assets/{MutationTokenDialog-Bm34BNVV.js.map → MutationTokenDialog-DbnO8aYi.js.map} +1 -1
  345. package/dist/core/web/public/next/assets/NeedsYouDrawer-crsiX-Nc.js +3 -0
  346. package/dist/core/web/public/next/assets/NeedsYouDrawer-crsiX-Nc.js.map +1 -0
  347. package/dist/core/web/public/next/assets/{NeedsYouList-D5Kk549g.js → NeedsYouList-CCsijdWt.js} +2 -2
  348. package/dist/core/web/public/next/assets/{NeedsYouList-D5Kk549g.js.map → NeedsYouList-CCsijdWt.js.map} +1 -1
  349. package/dist/core/web/public/next/assets/NewChatDialog-BlCHtOIr.js +3 -0
  350. package/dist/core/web/public/next/assets/{NewChatDialog-BqFTWgHU.js.map → NewChatDialog-BlCHtOIr.js.map} +1 -1
  351. package/dist/core/web/public/next/assets/{OnboardingFlow-DcDsguAM.js → OnboardingFlow-Cy9BA9eR.js} +3 -3
  352. package/dist/core/web/public/next/assets/{OnboardingFlow-DcDsguAM.js.map → OnboardingFlow-Cy9BA9eR.js.map} +1 -1
  353. package/dist/core/web/public/next/assets/OnboardingGate-BXpNFoLt.js +3 -0
  354. package/dist/core/web/public/next/assets/{OnboardingGate-BZafM1Vf.js.map → OnboardingGate-BXpNFoLt.js.map} +1 -1
  355. package/dist/core/web/public/next/assets/PreviewPane-COid5A0f.js +2 -0
  356. package/dist/core/web/public/next/assets/{PreviewPane-zT3gK9TD.js.map → PreviewPane-COid5A0f.js.map} +1 -1
  357. package/dist/core/web/public/next/assets/{ProviderLogo-AwHn2sKm.js → ProviderLogo-Cq-CYIwT.js} +2 -2
  358. package/dist/core/web/public/next/assets/{ProviderLogo-AwHn2sKm.js.map → ProviderLogo-Cq-CYIwT.js.map} +1 -1
  359. package/dist/core/web/public/next/assets/{RailStatus-xHrovWvI.js → RailStatus-Co5UB6We.js} +2 -2
  360. package/dist/core/web/public/next/assets/{RailStatus-xHrovWvI.js.map → RailStatus-Co5UB6We.js.map} +1 -1
  361. package/dist/core/web/public/next/assets/{RefreshIndicator-SEFZlMB2.js → RefreshIndicator-DO9ibnSq.js} +2 -2
  362. package/dist/core/web/public/next/assets/{RefreshIndicator-SEFZlMB2.js.map → RefreshIndicator-DO9ibnSq.js.map} +1 -1
  363. package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-Dr2WRgkq.js +7 -0
  364. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-CAxPQ4sZ.js.map → ResourcePoolConsoleApp-Dr2WRgkq.js.map} +1 -1
  365. package/dist/core/web/public/next/assets/ResourcesChrome-CwMnbqI1.js +3 -0
  366. package/dist/core/web/public/next/assets/ResourcesChrome-CwMnbqI1.js.map +1 -0
  367. package/dist/core/web/public/next/assets/ResourcesDrawer-B_Xp_JNc.js +2 -0
  368. package/dist/core/web/public/next/assets/ResourcesDrawer-B_Xp_JNc.js.map +1 -0
  369. package/dist/core/web/public/next/assets/ResourcesDrawer-DrGoO8KG.css +1 -0
  370. package/dist/core/web/public/next/assets/{RouteErrorBoundary-C8WGiixc.js → RouteErrorBoundary-SkNhhUbt.js} +2 -2
  371. package/dist/core/web/public/next/assets/{RouteErrorBoundary-C8WGiixc.js.map → RouteErrorBoundary-SkNhhUbt.js.map} +1 -1
  372. package/dist/core/web/public/next/assets/{RunInCloudAction-1-IPLYhf.js → RunInCloudAction-BXPlZwJQ.js} +2 -2
  373. package/dist/core/web/public/next/assets/{RunInCloudAction-1-IPLYhf.js.map → RunInCloudAction-BXPlZwJQ.js.map} +1 -1
  374. package/dist/core/web/public/next/assets/{SeatSelector-DpwNiX8F.js → SeatSelector-J5R3zDkB.js} +3 -3
  375. package/dist/core/web/public/next/assets/{SeatSelector-DpwNiX8F.js.map → SeatSelector-J5R3zDkB.js.map} +1 -1
  376. package/dist/core/web/public/next/assets/{Segmented-Wt1ATod9.js → Segmented-CGh_-tBb.js} +2 -2
  377. package/dist/core/web/public/next/assets/{Segmented-Wt1ATod9.js.map → Segmented-CGh_-tBb.js.map} +1 -1
  378. package/dist/core/web/public/next/assets/{Select-By-V9lMc.js → Select-CWnmUzs3.js} +2 -2
  379. package/dist/core/web/public/next/assets/{Select-By-V9lMc.js.map → Select-CWnmUzs3.js.map} +1 -1
  380. package/dist/core/web/public/next/assets/{SessionGate-WROS02tK.js → SessionGate-sp4KsnUo.js} +2 -2
  381. package/dist/core/web/public/next/assets/{SessionGate-WROS02tK.js.map → SessionGate-sp4KsnUo.js.map} +1 -1
  382. package/dist/core/web/public/next/assets/{SessionInsightChip-DNUcruwp.js → SessionInsightChip-DLFAzdbi.js} +2 -2
  383. package/dist/core/web/public/next/assets/{SessionInsightChip-DNUcruwp.js.map → SessionInsightChip-DLFAzdbi.js.map} +1 -1
  384. package/dist/core/web/public/next/assets/{SessionSearch-UHtt7a8f.js → SessionSearch-DbFjwR1h.js} +2 -2
  385. package/dist/core/web/public/next/assets/{SessionSearch-UHtt7a8f.js.map → SessionSearch-DbFjwR1h.js.map} +1 -1
  386. package/dist/core/web/public/next/assets/{SettingsSection-Bf74l0Gj.js → SettingsSection-Ch23msJ5.js} +2 -2
  387. package/dist/core/web/public/next/assets/SettingsSection-Ch23msJ5.js.map +1 -0
  388. package/dist/core/web/public/next/assets/{SetupChecklist-CzpEcfOl.js → SetupChecklist-Bd76MBAR.js} +2 -2
  389. package/dist/core/web/public/next/assets/{SetupChecklist-CzpEcfOl.js.map → SetupChecklist-Bd76MBAR.js.map} +1 -1
  390. package/dist/core/web/public/next/assets/ShadowDecisions-C5RAY91f.js +3 -0
  391. package/dist/core/web/public/next/assets/ShadowDecisions-C5RAY91f.js.map +1 -0
  392. package/dist/core/web/public/next/assets/{Sheet-HkBOBMTT.js → Sheet-BZ2AG4Eo.js} +2 -2
  393. package/dist/core/web/public/next/assets/{Sheet-HkBOBMTT.js.map → Sheet-BZ2AG4Eo.js.map} +1 -1
  394. package/dist/core/web/public/next/assets/{ShortcutsOverlay-DiigiT8H.js → ShortcutsOverlay-C8n8y3zf.js} +2 -2
  395. package/dist/core/web/public/next/assets/{ShortcutsOverlay-DiigiT8H.js.map → ShortcutsOverlay-C8n8y3zf.js.map} +1 -1
  396. package/dist/core/web/public/next/assets/Sidebar-DN--cPYN.js +3 -0
  397. package/dist/core/web/public/next/assets/{Sidebar-C9YtBYVZ.js.map → Sidebar-DN--cPYN.js.map} +1 -1
  398. package/dist/core/web/public/next/assets/{Slider-DaEDws-b.js → Slider-KVoJLDD6.js} +2 -2
  399. package/dist/core/web/public/next/assets/{Slider-DaEDws-b.js.map → Slider-KVoJLDD6.js.map} +1 -1
  400. package/dist/core/web/public/next/assets/StatTile-C4KgjltA.js +2 -0
  401. package/dist/core/web/public/next/assets/StatTile-C4KgjltA.js.map +1 -0
  402. package/dist/core/web/public/next/assets/StatTile-CNCqDoPO.css +1 -0
  403. package/dist/core/web/public/next/assets/{StatusBadge-CXG3iNL4.js → StatusBadge-CXsYqmdU.js} +2 -2
  404. package/dist/core/web/public/next/assets/{StatusBadge-CXG3iNL4.js.map → StatusBadge-CXsYqmdU.js.map} +1 -1
  405. package/dist/core/web/public/next/assets/StepBand-BMtVOFpK.js +2 -0
  406. package/dist/core/web/public/next/assets/StepBand-BMtVOFpK.js.map +1 -0
  407. package/dist/core/web/public/next/assets/{Surface-5bNA08tK.js → Surface-BfDmQcKe.js} +2 -2
  408. package/dist/core/web/public/next/assets/{Surface-5bNA08tK.js.map → Surface-BfDmQcKe.js.map} +1 -1
  409. package/dist/core/web/public/next/assets/Swimlane-B9Exxekk.js +2 -0
  410. package/dist/core/web/public/next/assets/Swimlane-B9Exxekk.js.map +1 -0
  411. package/dist/core/web/public/next/assets/Swimlane-Bf4Rjoy9.css +1 -0
  412. package/dist/core/web/public/next/assets/{Switch-BmCzfFnu.js → Switch-9NtO_6Lj.js} +2 -2
  413. package/dist/core/web/public/next/assets/{Switch-BmCzfFnu.js.map → Switch-9NtO_6Lj.js.map} +1 -1
  414. package/dist/core/web/public/next/assets/{Tag-WSUIaMVy.js → Tag-DscCRFcN.js} +2 -2
  415. package/dist/core/web/public/next/assets/{Tag-WSUIaMVy.js.map → Tag-DscCRFcN.js.map} +1 -1
  416. package/dist/core/web/public/next/assets/{TerminalPane-BVFgYX6K.js → TerminalPane-B668-DJW.js} +5 -5
  417. package/dist/core/web/public/next/assets/{TerminalPane-BVFgYX6K.js.map → TerminalPane-B668-DJW.js.map} +1 -1
  418. package/dist/core/web/public/next/assets/UniverseConsoleApp-BUV_brY7.js +2 -0
  419. package/dist/core/web/public/next/assets/{UniverseConsoleApp-BpphLqoz.js.map → UniverseConsoleApp-BUV_brY7.js.map} +1 -1
  420. package/dist/core/web/public/next/assets/{UniverseView-DbpbSMwO.js → UniverseView-DG70zH0W.js} +4 -4
  421. package/dist/core/web/public/next/assets/{UniverseView-DbpbSMwO.js.map → UniverseView-DG70zH0W.js.map} +1 -1
  422. package/dist/core/web/public/next/assets/UsageSection-DY7uOTm1.js +3 -0
  423. package/dist/core/web/public/next/assets/UsageSection-DY7uOTm1.js.map +1 -0
  424. package/dist/core/web/public/next/assets/VerseConsoleApp-CWU6R3By.js +3 -0
  425. package/dist/core/web/public/next/assets/VerseConsoleApp-CWU6R3By.js.map +1 -0
  426. package/dist/core/web/public/next/assets/Workspace-D1nP9BhD.js +10 -0
  427. package/dist/core/web/public/next/assets/{Workspace-RXy0pqp6.js.map → Workspace-D1nP9BhD.js.map} +1 -1
  428. package/dist/core/web/public/next/assets/actions-CY-PjpGc.js +2 -0
  429. package/dist/core/web/public/next/assets/{actions-BZTidCXZ.js.map → actions-CY-PjpGc.js.map} +1 -1
  430. package/dist/core/web/public/next/assets/actions-DkWhhWIg.css +1 -0
  431. package/dist/core/web/public/next/assets/{apps-model-CHO133qt.js → apps-model-Du02KhAf.js} +2 -2
  432. package/dist/core/web/public/next/assets/{apps-model-CHO133qt.js.map → apps-model-Du02KhAf.js.map} +1 -1
  433. package/dist/core/web/public/next/assets/{authority-model-8NeAEwAF.js → authority-model-79SeuKlJ.js} +2 -2
  434. package/dist/core/web/public/next/assets/{authority-model-8NeAEwAF.js.map → authority-model-79SeuKlJ.js.map} +1 -1
  435. package/dist/core/web/public/next/assets/autonomy-ladder-BGWmZzP7.css +1 -0
  436. package/dist/core/web/public/next/assets/autonomy-ladder.module-ArDv4bkr.js +2 -0
  437. package/dist/core/web/public/next/assets/autonomy-ladder.module-ArDv4bkr.js.map +1 -0
  438. package/dist/core/web/public/next/assets/budget-queries-D8QV5XtH.js +2 -0
  439. package/dist/core/web/public/next/assets/{budget-queries-DFF-3ICg.js.map → budget-queries-D8QV5XtH.js.map} +1 -1
  440. package/dist/core/web/public/next/assets/{capacity-strip-model-5ViUgUlP.js → capacity-strip-model-BwZ1ZbkU.js} +2 -2
  441. package/dist/core/web/public/next/assets/{capacity-strip-model-5ViUgUlP.js.map → capacity-strip-model-BwZ1ZbkU.js.map} +1 -1
  442. package/dist/core/web/public/next/assets/charts-BZ50mZD_.js +2 -0
  443. package/dist/core/web/public/next/assets/charts-BZ50mZD_.js.map +1 -0
  444. package/dist/core/web/public/next/assets/charts-ClCB18la.css +1 -0
  445. package/dist/core/web/public/next/assets/{cloud-model-CfRydq8N.js → cloud-model-BDivRMqv.js} +2 -2
  446. package/dist/core/web/public/next/assets/{cloud-model-CfRydq8N.js.map → cloud-model-BDivRMqv.js.map} +1 -1
  447. package/dist/core/web/public/next/assets/{cloud-queries-DmptbjS8.js → cloud-queries-BPQQ5_pJ.js} +2 -2
  448. package/dist/core/web/public/next/assets/{cloud-queries-DmptbjS8.js.map → cloud-queries-BPQQ5_pJ.js.map} +1 -1
  449. package/dist/core/web/public/next/assets/{colors-BZ3a9wFf.js → colors-DvK0wMHH.js} +2 -2
  450. package/dist/core/web/public/next/assets/{colors-BZ3a9wFf.js.map → colors-DvK0wMHH.js.map} +1 -1
  451. package/dist/core/web/public/next/assets/{command-catalog-ffCAijVY.js → command-catalog-BIntSa9l.js} +2 -2
  452. package/dist/core/web/public/next/assets/command-catalog-BIntSa9l.js.map +1 -0
  453. package/dist/core/web/public/next/assets/{context-model-CDeyP0cA.js → context-model-Br8t9jgG.js} +2 -2
  454. package/dist/core/web/public/next/assets/{context-model-CDeyP0cA.js.map → context-model-Br8t9jgG.js.map} +1 -1
  455. package/dist/core/web/public/next/assets/{context-model-Bb15chFt.js → context-model-CokrgEUq.js} +3 -3
  456. package/dist/core/web/public/next/assets/{context-model-Bb15chFt.js.map → context-model-CokrgEUq.js.map} +1 -1
  457. package/dist/core/web/public/next/assets/context-queries-eL3caKVG.js +2 -0
  458. package/dist/core/web/public/next/assets/{context-queries-_9bFWb9v.js.map → context-queries-eL3caKVG.js.map} +1 -1
  459. package/dist/core/web/public/next/assets/{control-queries-CXtmZZH6.js → control-queries-B9K-wmcB.js} +2 -2
  460. package/dist/core/web/public/next/assets/{control-queries-CXtmZZH6.js.map → control-queries-B9K-wmcB.js.map} +1 -1
  461. package/dist/core/web/public/next/assets/{copy-setup-BIp0iaiZ.js → copy-setup-XMgCC5f8.js} +2 -2
  462. package/dist/core/web/public/next/assets/{copy-setup-BIp0iaiZ.js.map → copy-setup-XMgCC5f8.js.map} +1 -1
  463. package/dist/core/web/public/next/assets/{dock-icons-Cc43W7r4.js → dock-icons-BJ6ZqB2t.js} +2 -2
  464. package/dist/core/web/public/next/assets/{dock-icons-Cc43W7r4.js.map → dock-icons-BJ6ZqB2t.js.map} +1 -1
  465. package/dist/core/web/public/next/assets/{fleet-model-DOK8ZtEt.js → fleet-model-BvDR3gjp.js} +2 -2
  466. package/dist/core/web/public/next/assets/{fleet-model-DOK8ZtEt.js.map → fleet-model-BvDR3gjp.js.map} +1 -1
  467. package/dist/core/web/public/next/assets/{fleet-queries-BeEAqD6y.js → fleet-queries-W2UFVMZJ.js} +2 -2
  468. package/dist/core/web/public/next/assets/{fleet-queries-BeEAqD6y.js.map → fleet-queries-W2UFVMZJ.js.map} +1 -1
  469. package/dist/core/web/public/next/assets/{focus-trap-ChZ5EFfM.js → focus-trap-CtI1SlMX.js} +2 -2
  470. package/dist/core/web/public/next/assets/{focus-trap-ChZ5EFfM.js.map → focus-trap-CtI1SlMX.js.map} +1 -1
  471. package/dist/core/web/public/next/assets/{format-BmH2yWL6.js → format-CH4g_sl1.js} +2 -2
  472. package/dist/core/web/public/next/assets/{format-BmH2yWL6.js.map → format-CH4g_sl1.js.map} +1 -1
  473. package/dist/core/web/public/next/assets/{format-DKrNjdwD.js → format-D7nBg2bn.js} +2 -2
  474. package/dist/core/web/public/next/assets/{format-DKrNjdwD.js.map → format-D7nBg2bn.js.map} +1 -1
  475. package/dist/core/web/public/next/assets/{git-model-BFwAVbxF.js → git-model-Dnkd1TnK.js} +2 -2
  476. package/dist/core/web/public/next/assets/{git-model-BFwAVbxF.js.map → git-model-Dnkd1TnK.js.map} +1 -1
  477. package/dist/core/web/public/next/assets/global-CMNW_dqn.js +2 -0
  478. package/dist/core/web/public/next/assets/{global-y_exIyAP.js.map → global-CMNW_dqn.js.map} +1 -1
  479. package/dist/core/web/public/next/assets/guarded-runners-YeAc9wLQ.js +2 -0
  480. package/dist/core/web/public/next/assets/{guarded-runners-Cd4POBtI.js.map → guarded-runners-YeAc9wLQ.js.map} +1 -1
  481. package/dist/core/web/public/next/assets/{icons-CygCEFWs.js → icons-D1sYbCTQ.js} +2 -2
  482. package/dist/core/web/public/next/assets/{icons-CygCEFWs.js.map → icons-D1sYbCTQ.js.map} +1 -1
  483. package/dist/core/web/public/next/assets/{index-CyK31YRm.js → index-DZ-UQ7v8.js} +3 -3
  484. package/dist/core/web/public/next/assets/{index-CyK31YRm.js.map → index-DZ-UQ7v8.js.map} +1 -1
  485. package/dist/core/web/public/next/assets/leader-focus-BjeJv7CW.js +2 -0
  486. package/dist/core/web/public/next/assets/leader-focus-BjeJv7CW.js.map +1 -0
  487. package/dist/core/web/public/next/assets/leader-thread-types-CDb-VPPO.js +2 -0
  488. package/dist/core/web/public/next/assets/leader-thread-types-CDb-VPPO.js.map +1 -0
  489. package/dist/core/web/public/next/assets/{live-model-D7hilYFk.js → live-model-D_32RAOR.js} +2 -2
  490. package/dist/core/web/public/next/assets/{live-model-D7hilYFk.js.map → live-model-D_32RAOR.js.map} +1 -1
  491. package/dist/core/web/public/next/assets/{mind.module-B15k0Y9q.js → mind.module-7hA92hRg.js} +2 -2
  492. package/dist/core/web/public/next/assets/{mind.module-B15k0Y9q.js.map → mind.module-7hA92hRg.js.map} +1 -1
  493. package/dist/core/web/public/next/assets/mutations-DQPbFdRJ.js +2 -0
  494. package/dist/core/web/public/next/assets/{mutations-CWlxEMEm.js.map → mutations-DQPbFdRJ.js.map} +1 -1
  495. package/dist/core/web/public/next/assets/{nav-mimleI0R.js → nav-0dOYe2rJ.js} +2 -2
  496. package/dist/core/web/public/next/assets/{nav-mimleI0R.js.map → nav-0dOYe2rJ.js.map} +1 -1
  497. package/dist/core/web/public/next/assets/{overnight-queries-DJ4mZKSj.js → overnight-queries-C4wOnFtE.js} +2 -2
  498. package/dist/core/web/public/next/assets/{overnight-queries-DJ4mZKSj.js.map → overnight-queries-C4wOnFtE.js.map} +1 -1
  499. package/dist/core/web/public/next/assets/primitives-2A5Eq8FQ.js +1 -0
  500. package/dist/core/web/public/next/assets/{queries-Bw1McHTj.js → queries-BTXWdZzU.js} +2 -2
  501. package/dist/core/web/public/next/assets/{queries-Bw1McHTj.js.map → queries-BTXWdZzU.js.map} +1 -1
  502. package/dist/core/web/public/next/assets/{reasoning-pref-KkhI_5-j.js → reasoning-pref-Ca6lN6x_.js} +2 -2
  503. package/dist/core/web/public/next/assets/{reasoning-pref-KkhI_5-j.js.map → reasoning-pref-Ca6lN6x_.js.map} +1 -1
  504. package/dist/core/web/public/next/assets/{reveal-anchor-CCCx_kfT.js → reveal-anchor-DfNLgK_I.js} +2 -2
  505. package/dist/core/web/public/next/assets/{reveal-anchor-CCCx_kfT.js.map → reveal-anchor-DfNLgK_I.js.map} +1 -1
  506. package/dist/core/web/public/next/assets/seat-subscription-C5uPHBsN.js +2 -0
  507. package/dist/core/web/public/next/assets/{seat-subscription-BhUUz7VL.js.map → seat-subscription-C5uPHBsN.js.map} +1 -1
  508. package/dist/core/web/public/next/assets/{sidebar-model-Dcd437cf.js → sidebar-model-CLCdqwkR.js} +2 -2
  509. package/dist/core/web/public/next/assets/{sidebar-model-Dcd437cf.js.map → sidebar-model-CLCdqwkR.js.map} +1 -1
  510. package/dist/core/web/public/next/assets/{slots-BL_J5mmV.js → slots-C-qBeu-8.js} +3 -3
  511. package/dist/core/web/public/next/assets/{slots-BL_J5mmV.js.map → slots-C-qBeu-8.js.map} +1 -1
  512. package/dist/core/web/public/next/assets/{surface-data-C3UAQ4QX.js → surface-data-Dj71tdD-.js} +2 -2
  513. package/dist/core/web/public/next/assets/{surface-data-C3UAQ4QX.js.map → surface-data-Dj71tdD-.js.map} +1 -1
  514. package/dist/core/web/public/next/assets/surface-prefetch-B0WdJOJG.js +2 -0
  515. package/dist/core/web/public/next/assets/surface-prefetch-B0WdJOJG.js.map +1 -0
  516. package/dist/core/web/public/next/assets/{tasks-model-CzHvclVm.js → tasks-model-O8yR5YXp.js} +2 -2
  517. package/dist/core/web/public/next/assets/{tasks-model-CzHvclVm.js.map → tasks-model-O8yR5YXp.js.map} +1 -1
  518. package/dist/core/web/public/next/assets/{terminal-icons-BwgQTQP0.js → terminal-icons-CoRZq9iO.js} +2 -2
  519. package/dist/core/web/public/next/assets/{terminal-icons-BwgQTQP0.js.map → terminal-icons-CoRZq9iO.js.map} +1 -1
  520. package/dist/core/web/public/next/assets/thread-data-DQB_g66d.js +2 -0
  521. package/dist/core/web/public/next/assets/thread-data-DQB_g66d.js.map +1 -0
  522. package/dist/core/web/public/next/assets/{usage-queries-pXxvy54x.js → usage-queries-AdjEyEtn.js} +2 -2
  523. package/dist/core/web/public/next/assets/{usage-queries-pXxvy54x.js.map → usage-queries-AdjEyEtn.js.map} +1 -1
  524. package/dist/core/web/public/next/assets/{use-guarded-action-EgVWjM5c.js → use-guarded-action-CuuMHeDX.js} +2 -2
  525. package/dist/core/web/public/next/assets/{use-guarded-action-EgVWjM5c.js.map → use-guarded-action-CuuMHeDX.js.map} +1 -1
  526. package/dist/core/web/public/next/assets/{use-ticker-BoqFxRFG.js → use-ticker-BBcp02SZ.js} +2 -2
  527. package/dist/core/web/public/next/assets/{use-ticker-BoqFxRFG.js.map → use-ticker-BBcp02SZ.js.map} +1 -1
  528. package/dist/core/web/public/next/assets/{use-token-gate-DSNIIpI6.js → use-token-gate-CbXVYQYI.js} +2 -2
  529. package/dist/core/web/public/next/assets/{use-token-gate-DSNIIpI6.js.map → use-token-gate-CbXVYQYI.js.map} +1 -1
  530. package/dist/core/web/public/next/assets/{useOnboarding-Bk0VnkxQ.js → useOnboarding-C_Fpe_sH.js} +2 -2
  531. package/dist/core/web/public/next/assets/{useOnboarding-Bk0VnkxQ.js.map → useOnboarding-C_Fpe_sH.js.map} +1 -1
  532. package/dist/core/web/public/next/assets/{useSeatsRefresh-q7Id9RcW.js → useSeatsRefresh-Co1CnxLc.js} +2 -2
  533. package/dist/core/web/public/next/assets/{useSeatsRefresh-q7Id9RcW.js.map → useSeatsRefresh-Co1CnxLc.js.map} +1 -1
  534. package/dist/core/web/public/next/assets/{useVerseTranscript-CqH51rt9.js → useVerseTranscript-DgbigUlV.js} +2 -2
  535. package/dist/core/web/public/next/assets/{useVerseTranscript-CqH51rt9.js.map → useVerseTranscript-DgbigUlV.js.map} +1 -1
  536. package/dist/core/web/public/next/assets/{verse-icons-DsG1dOQx.js → verse-icons-S56hIiXS.js} +2 -2
  537. package/dist/core/web/public/next/assets/{verse-icons-DsG1dOQx.js.map → verse-icons-S56hIiXS.js.map} +1 -1
  538. package/dist/core/web/public/next/assets/verse-model-DAVevkNe.js +2 -0
  539. package/dist/core/web/public/next/assets/{verse-model-JTuvRBVK.js.map → verse-model-DAVevkNe.js.map} +1 -1
  540. package/dist/core/web/public/next/assets/{warmup-Bv1RumVq.js → warmup-B_RAtNZ_.js} +3 -3
  541. package/dist/core/web/public/next/assets/{warmup-Bv1RumVq.js.map → warmup-B_RAtNZ_.js.map} +1 -1
  542. package/dist/core/web/public/next/assets/{why-seat-model-Cau8qG6O.js → why-seat-model-M_r0wX3b.js} +2 -2
  543. package/dist/core/web/public/next/assets/{why-seat-model-Cau8qG6O.js.map → why-seat-model-M_r0wX3b.js.map} +1 -1
  544. package/dist/core/web/public/next/assets/{workspace-model-D-SLfads.js → workspace-model-dji5-Al3.js} +2 -2
  545. package/dist/core/web/public/next/assets/{workspace-model-D-SLfads.js.map → workspace-model-dji5-Al3.js.map} +1 -1
  546. package/dist/core/web/public/next/index.html +1 -1
  547. package/dist/core/web/read-projection-worker.js +2 -1
  548. package/dist/core/web/read-projection-worker.js.map +1 -1
  549. package/dist/core/web/read-projections.d.ts +3 -0
  550. package/dist/core/web/read-projections.js +2 -2
  551. package/dist/core/web/read-projections.js.map +1 -1
  552. package/dist/core/web/visibility.js +3 -4
  553. package/dist/core/web/visibility.js.map +1 -1
  554. package/dist/release-dependency-inventory.json +1 -1
  555. package/package.json +3 -2
  556. package/dist/core/web/public/next/assets/Advanced-cVYTAsfB.js +0 -2
  557. package/dist/core/web/public/next/assets/AppsSection-DDqeSrty.js +0 -2
  558. package/dist/core/web/public/next/assets/AreaTrend-C32rUaxm.js +0 -2
  559. package/dist/core/web/public/next/assets/AreaTrend-C32rUaxm.js.map +0 -1
  560. package/dist/core/web/public/next/assets/AutonomySection-Dwn8UtOy.js +0 -2
  561. package/dist/core/web/public/next/assets/ChartFrame-BVuBe6RP.css +0 -1
  562. package/dist/core/web/public/next/assets/ChartFrame-DK_BDXCt.js +0 -2
  563. package/dist/core/web/public/next/assets/ChartFrame-DK_BDXCt.js.map +0 -1
  564. package/dist/core/web/public/next/assets/ChatSection-C9myY4ei.js +0 -3
  565. package/dist/core/web/public/next/assets/CommandPalette-DzPsth0u.js +0 -2
  566. package/dist/core/web/public/next/assets/CommandPalette-DzPsth0u.js.map +0 -1
  567. package/dist/core/web/public/next/assets/CommandSection-Brp73iox.js +0 -3
  568. package/dist/core/web/public/next/assets/CommandSection-Brp73iox.js.map +0 -1
  569. package/dist/core/web/public/next/assets/CommandSection-CvAVd1w4.css +0 -1
  570. package/dist/core/web/public/next/assets/DockHost-BcEq2qaS.js +0 -2
  571. package/dist/core/web/public/next/assets/FleetSection-BG8iGraG.js +0 -3
  572. package/dist/core/web/public/next/assets/FleetSection-BG8iGraG.js.map +0 -1
  573. package/dist/core/web/public/next/assets/Funnel-B88_wpA4.js +0 -2
  574. package/dist/core/web/public/next/assets/Funnel-B88_wpA4.js.map +0 -1
  575. package/dist/core/web/public/next/assets/GrowthSection-BvZezOsX.js +0 -2
  576. package/dist/core/web/public/next/assets/LeaderCard-BxxiEg4e.js +0 -2
  577. package/dist/core/web/public/next/assets/LeaderCard-BxxiEg4e.js.map +0 -1
  578. package/dist/core/web/public/next/assets/MatrixHeatmap-iPFEU2Tv.js +0 -2
  579. package/dist/core/web/public/next/assets/MatrixHeatmap-iPFEU2Tv.js.map +0 -1
  580. package/dist/core/web/public/next/assets/McpSection-nuXer4K-.js +0 -2
  581. package/dist/core/web/public/next/assets/MindSection-Dc5v5rH3.js +0 -2
  582. package/dist/core/web/public/next/assets/MindSection-Dc5v5rH3.js.map +0 -1
  583. package/dist/core/web/public/next/assets/NeedsYouDrawer-N1cWJjpz.js +0 -3
  584. package/dist/core/web/public/next/assets/NeedsYouDrawer-N1cWJjpz.js.map +0 -1
  585. package/dist/core/web/public/next/assets/NewChatDialog-BqFTWgHU.js +0 -3
  586. package/dist/core/web/public/next/assets/OnboardingGate-BZafM1Vf.js +0 -3
  587. package/dist/core/web/public/next/assets/PreviewPane-zT3gK9TD.js +0 -2
  588. package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-CAxPQ4sZ.js +0 -7
  589. package/dist/core/web/public/next/assets/ResourcesChrome-BnhnEdJe.js +0 -3
  590. package/dist/core/web/public/next/assets/ResourcesChrome-BnhnEdJe.js.map +0 -1
  591. package/dist/core/web/public/next/assets/ResourcesDrawer-BAFGodny.js +0 -2
  592. package/dist/core/web/public/next/assets/ResourcesDrawer-BAFGodny.js.map +0 -1
  593. package/dist/core/web/public/next/assets/ResourcesDrawer-BCFJ2Uq8.css +0 -1
  594. package/dist/core/web/public/next/assets/SettingsSection-Bf74l0Gj.js.map +0 -1
  595. package/dist/core/web/public/next/assets/Sidebar-C9YtBYVZ.js +0 -3
  596. package/dist/core/web/public/next/assets/StatTile-BuLMsJMx.css +0 -1
  597. package/dist/core/web/public/next/assets/StatTile-CTX41O6y.js +0 -2
  598. package/dist/core/web/public/next/assets/StatTile-CTX41O6y.js.map +0 -1
  599. package/dist/core/web/public/next/assets/StepBand-jJTqYIdX.js +0 -2
  600. package/dist/core/web/public/next/assets/StepBand-jJTqYIdX.js.map +0 -1
  601. package/dist/core/web/public/next/assets/Swimlane-LrslsGxw.js +0 -2
  602. package/dist/core/web/public/next/assets/Swimlane-LrslsGxw.js.map +0 -1
  603. package/dist/core/web/public/next/assets/Swimlane-o6_Zsrnr.css +0 -1
  604. package/dist/core/web/public/next/assets/UniverseConsoleApp-BpphLqoz.js +0 -2
  605. package/dist/core/web/public/next/assets/UsageSection-CUlaKtws.js +0 -3
  606. package/dist/core/web/public/next/assets/UsageSection-CUlaKtws.js.map +0 -1
  607. package/dist/core/web/public/next/assets/VerseConsoleApp-DXDv1aOi.js +0 -3
  608. package/dist/core/web/public/next/assets/VerseConsoleApp-DXDv1aOi.js.map +0 -1
  609. package/dist/core/web/public/next/assets/Workspace-RXy0pqp6.js +0 -10
  610. package/dist/core/web/public/next/assets/actions-BZTidCXZ.js +0 -2
  611. package/dist/core/web/public/next/assets/actions-BmIf9avl.css +0 -1
  612. package/dist/core/web/public/next/assets/budget-queries-DFF-3ICg.js +0 -2
  613. package/dist/core/web/public/next/assets/charts-CzxWrZn7.js +0 -2
  614. package/dist/core/web/public/next/assets/charts-CzxWrZn7.js.map +0 -1
  615. package/dist/core/web/public/next/assets/charts-DhKTrQLw.css +0 -1
  616. package/dist/core/web/public/next/assets/command-catalog-ffCAijVY.js.map +0 -1
  617. package/dist/core/web/public/next/assets/context-queries-_9bFWb9v.js +0 -2
  618. package/dist/core/web/public/next/assets/global-y_exIyAP.js +0 -2
  619. package/dist/core/web/public/next/assets/guarded-runners-Cd4POBtI.js +0 -2
  620. package/dist/core/web/public/next/assets/mutations-CWlxEMEm.js +0 -2
  621. package/dist/core/web/public/next/assets/primitives-DMijqcu0.js +0 -1
  622. package/dist/core/web/public/next/assets/seat-subscription-BhUUz7VL.js +0 -2
  623. package/dist/core/web/public/next/assets/surface-prefetch-BXKjPsV5.js +0 -2
  624. package/dist/core/web/public/next/assets/surface-prefetch-BXKjPsV5.js.map +0 -1
  625. package/dist/core/web/public/next/assets/verse-model-JTuvRBVK.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"GearTray-CpDt0xwj.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/GearTray.module.css","../../../../../../src/web-ui/routes/verse/shell/GearTray.tsx"],"sourcesContent":["/* The ⚙ menu: a raised list beside the rail foot (above the bottom bar on a phone). */\n\n.menu {\n position: fixed;\n z-index: var(--z-dropdown);\n min-width: 232px;\n padding: var(--space-1);\n background: var(--bg-surface-raised);\n border: 1px solid var(--border-default);\n border-radius: var(--radius-lg);\n box-shadow: var(--shadow-menu);\n animation: pop var(--duration-fast) var(--ease-decelerate);\n}\n.menu[data-compact] { right: var(--space-2); }\n\n.item {\n display: grid;\n grid-template-columns: 16px minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--space-2);\n width: 100%;\n min-height: var(--control-h);\n padding: 0 var(--space-2);\n border-radius: var(--radius-sm);\n color: var(--text-primary);\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n text-align: left;\n}\n.item:hover,\n.item:focus-visible { background: var(--bg-hover); outline: none; box-shadow: none; }\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--text-secondary);\n}\n\n.check {\n width: 6px;\n height: 10px;\n margin-top: -2px;\n border: solid var(--accent-500);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n.key {\n font-family: var(--font-mono);\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n}\n\n.separator {\n margin: var(--space-1) var(--space-2);\n border-top: 1px solid var(--border-subtle);\n}\n\n.groupLabel {\n display: block;\n padding-top: var(--space-2);\n font-family: var(--font-display);\n font-size: var(--text-2xs-size);\n line-height: var(--text-2xs-line);\n letter-spacing: var(--tracking-label);\n text-transform: uppercase;\n color: var(--text-tertiary);\n}\n\n@keyframes pop { from { opacity: 0; transform: translateY(2px); } }\n\n@media (prefers-reduced-motion: reduce) {\n :root:not([data-motion='full']) .menu { animation: none; }\n}\n:root[data-motion='reduce'] .menu { animation: none; }\n","/**\n * routes/verse/shell/GearTray.tsx — the rail foot's ⚙ menu (unit C1;\n * SPEC-310C §0.1): Settings (⌘,), Apps & Accounts, Usage and Keyboard\n * shortcuts (⌘/), plus the two shell preferences that used to sit on the rail\n * itself (rail labels, theme).\n *\n * A real menu: role=\"menu\" with menuitem / menuitemcheckbox / menuitemradio,\n * one roving tab stop, ↑ ↓ Home End to move, Enter / Space to choose, Esc\n * closes and puts focus back on the gear (a press outside just closes).\n * Portalled to <body> so the 56px rail cannot clip it.\n */\nimport { useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent as ReactKeyboardEvent, type ReactNode, type RefObject } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useTheme } from '../../../data/hooks.js';\nimport type { ThemePreference } from '../../../data/theme-store.js';\nimport { useVerseUi } from '../useVerseUi.js';\nimport { AppsIcon, SettingsIcon, UsageIcon } from '../verse-icons.js';\nimport { IconKeyboard } from '../../../components/primitives/icons.js';\nimport { openVerseOverlay, setVerseSection, toggleVerseRail } from '../verse-ui-store.js';\nimport { detectKeyPlatform, findCommand, formatChord } from './command-catalog.js';\nimport styles from './GearTray.module.css';\n\nexport interface GearTrayProps {\n open: boolean;\n anchorRef: RefObject<HTMLElement | null>;\n onClose: () => void;\n /** Phone layout: the rail is a bottom bar, so the menu rises from it. */\n compact: boolean;\n}\n\ninterface Entry {\n key: string;\n role: 'menuitem' | 'menuitemcheckbox' | 'menuitemradio';\n label: string;\n icon?: ReactNode;\n shortcut?: string | null;\n checked?: boolean;\n run: () => void;\n /** Keep the menu open after choosing (theme / rail toggles). */\n stay?: boolean;\n}\n\nfunction shortcutOf(id: string): string | null {\n const chord = findCommand(id)?.keys[0];\n return chord ? formatChord(chord, detectKeyPlatform()) : null;\n}\n\nconst THEMES: ReadonlyArray<{ value: ThemePreference; label: string }> = [\n { value: 'system', label: 'Match system' },\n { value: 'light', label: 'Light' },\n { value: 'dark', label: 'Dark' },\n];\n\nexport function GearTray({ open, anchorRef, onClose, compact }: GearTrayProps) {\n const ui = useVerseUi();\n const theme = useTheme();\n const menuRef = useRef<HTMLDivElement>(null);\n const [active, setActive] = useState(0);\n const [position, setPosition] = useState<{ left: number; bottom: number } | null>(null);\n\n const entries: Entry[] = [\n { key: 'settings', role: 'menuitem', label: 'Settings', icon: <SettingsIcon />, shortcut: shortcutOf('section.settings'), run: () => setVerseSection('settings') },\n { key: 'apps', role: 'menuitem', label: 'Apps & Accounts', icon: <AppsIcon />, run: () => setVerseSection('apps') },\n { key: 'usage', role: 'menuitem', label: 'Usage', icon: <UsageIcon />, run: () => setVerseSection('usage') },\n { key: 'shortcuts', role: 'menuitem', label: 'Keyboard shortcuts', icon: <IconKeyboard />, shortcut: shortcutOf('shortcuts.open'), run: () => openVerseOverlay('shortcuts') },\n ...(compact\n ? []\n : [{ key: 'rail', role: 'menuitemcheckbox' as const, label: 'Show rail labels', shortcut: shortcutOf('rail.toggle-labels'), checked: ui.railExpanded, run: toggleVerseRail, stay: true }]),\n ...THEMES.map((t) => ({\n key: `theme-${t.value}`,\n role: 'menuitemradio' as const,\n label: t.label,\n checked: theme.theme === t.value,\n run: () => theme.set(t.value),\n stay: true,\n })),\n ];\n\n useLayoutEffect(() => {\n if (!open) return;\n const rect = anchorRef.current?.getBoundingClientRect();\n if (!rect) return;\n setPosition(\n compact\n ? { left: 8, bottom: Math.max(8, window.innerHeight - rect.top + 8) }\n : { left: rect.right + 8, bottom: Math.max(8, window.innerHeight - rect.bottom) },\n );\n }, [open, anchorRef, compact]);\n\n // Every open starts on the first item. Reset while rendering (React's\n // \"adjust state when a prop changes\"), not in an effect: an effect runs\n // after the focus effect below has already focused wherever the LAST open\n // left off, so focus would hop there and then back to the first item.\n const [wasOpen, setWasOpen] = useState(open);\n if (open !== wasOpen) {\n setWasOpen(open);\n if (open) setActive(0);\n }\n\n // The latest onClose, without re-subscribing the outside-press listener:\n // the shell passes an inline closure and re-renders on every activity poll.\n const closeRef = useRef(onClose);\n closeRef.current = onClose;\n\n useEffect(() => {\n if (!open) return;\n function onDown(event: MouseEvent) {\n const target = event.target as Node;\n if (menuRef.current?.contains(target) || anchorRef.current?.contains(target)) return;\n closeRef.current();\n }\n document.addEventListener('mousedown', onDown);\n return () => document.removeEventListener('mousedown', onDown);\n }, [open, anchorRef]);\n\n // Focus follows the roving tab stop — once the menu is placed. Until the\n // layout effect above has measured the gear, the menu renders\n // visibility:hidden and a browser will not focus it; the placed re-render\n // follows in the same task, before paint, and this effect runs again then.\n // (This used to be a requestAnimationFrame that focused item 0 whatever\n // `active` was: an arrow key pressed before that frame moved the tab stop,\n // then the frame pulled focus back to the first item, so focus and the tab\n // stop sat on different items and Enter chose the wrong one.)\n const placed = position !== null;\n useEffect(() => {\n if (!open || !placed) return;\n menuRef.current?.querySelector<HTMLElement>(`[data-index=\"${active}\"]`)?.focus();\n }, [active, open, placed]);\n\n // Escape hands focus back to the gear AFTER the close has rendered, not in\n // the key handler. The shell turns the gear's tooltip off while the tray is\n // open and back on when it closes, and that re-creates the gear <button>:\n // focusing `anchorRef.current` synchronously focused the button that was\n // about to leave the document, and focus fell to <body>. This effect runs\n // after the shell's commit, when the ref already points at the live button.\n const refocusOnClose = useRef(false);\n useEffect(() => {\n if (open || !refocusOnClose.current) return;\n refocusOnClose.current = false;\n anchorRef.current?.focus();\n }, [open, anchorRef]);\n\n if (!open) return null;\n\n function close(restoreFocus = true) {\n refocusOnClose.current = restoreFocus;\n onClose();\n }\n\n function choose(entry: Entry) {\n entry.run();\n if (!entry.stay) close(false);\n }\n\n function onKeyDown(event: ReactKeyboardEvent<HTMLDivElement>) {\n const count = entries.length;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActive((i) => (i + 1) % count);\n break;\n case 'ArrowUp':\n event.preventDefault();\n setActive((i) => (i - 1 + count) % count);\n break;\n case 'Home':\n event.preventDefault();\n setActive(0);\n break;\n case 'End':\n event.preventDefault();\n setActive(count - 1);\n break;\n case 'Escape':\n event.preventDefault();\n event.stopPropagation();\n close();\n break;\n case 'Tab':\n // A menu is one tab stop: Tab leaves it (and closes it).\n close(false);\n break;\n default:\n break;\n }\n }\n\n const themeStart = entries.findIndex((e) => e.key.startsWith('theme-'));\n\n return createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n aria-label=\"Settings and more\"\n className={styles.menu}\n data-compact={compact || undefined}\n style={position ? { left: position.left, bottom: position.bottom } : { visibility: 'hidden' }}\n onKeyDown={onKeyDown}\n >\n {entries.map((entry, index) => (\n <div key={entry.key} role=\"none\">\n {index === themeStart ? (\n <div role=\"separator\" className={styles.separator}>\n <span className={styles.groupLabel}>Theme</span>\n </div>\n ) : null}\n {entry.key === 'rail' ? <div role=\"separator\" className={styles.separator} /> : null}\n <button\n type=\"button\"\n role={entry.role}\n data-index={index}\n tabIndex={index === active ? 0 : -1}\n aria-checked={entry.role === 'menuitem' ? undefined : entry.checked === true}\n className={styles.item}\n onClick={() => choose(entry)}\n onMouseMove={() => index !== active && setActive(index)}\n >\n <span className={styles.icon} aria-hidden=\"true\">\n {entry.role === 'menuitem' ? entry.icon : entry.checked ? <span className={styles.check} /> : null}\n </span>\n <span className={styles.label}>{entry.label}</span>\n {entry.shortcut ? <kbd className={styles.key}>{entry.shortcut}</kbd> : null}\n </button>\n </div>\n ))}\n </div>,\n document.body,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"GearTray-Dt-ee32-.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/GearTray.module.css","../../../../../../src/web-ui/routes/verse/shell/GearTray.tsx"],"sourcesContent":["/* The ⚙ menu: a raised list beside the rail foot (above the bottom bar on a phone). */\n\n.menu {\n position: fixed;\n z-index: var(--z-dropdown);\n min-width: 232px;\n padding: var(--space-1);\n background: var(--bg-surface-raised);\n border: 1px solid var(--border-default);\n border-radius: var(--radius-lg);\n box-shadow: var(--shadow-menu);\n animation: pop var(--duration-fast) var(--ease-decelerate);\n}\n.menu[data-compact] { right: var(--space-2); }\n\n.item {\n display: grid;\n grid-template-columns: 16px minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--space-2);\n width: 100%;\n min-height: var(--control-h);\n padding: 0 var(--space-2);\n border-radius: var(--radius-sm);\n color: var(--text-primary);\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n text-align: left;\n}\n.item:hover,\n.item:focus-visible { background: var(--bg-hover); outline: none; box-shadow: none; }\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--text-secondary);\n}\n\n.check {\n width: 6px;\n height: 10px;\n margin-top: -2px;\n border: solid var(--accent-500);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n.key {\n font-family: var(--font-mono);\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n}\n\n.separator {\n margin: var(--space-1) var(--space-2);\n border-top: 1px solid var(--border-subtle);\n}\n\n.groupLabel {\n display: block;\n padding-top: var(--space-2);\n font-family: var(--font-display);\n font-size: var(--text-2xs-size);\n line-height: var(--text-2xs-line);\n letter-spacing: var(--tracking-label);\n text-transform: uppercase;\n color: var(--text-tertiary);\n}\n\n@keyframes pop { from { opacity: 0; transform: translateY(2px); } }\n\n@media (prefers-reduced-motion: reduce) {\n :root:not([data-motion='full']) .menu { animation: none; }\n}\n:root[data-motion='reduce'] .menu { animation: none; }\n","/**\n * routes/verse/shell/GearTray.tsx — the rail foot's ⚙ menu (unit C1;\n * SPEC-310C §0.1): Settings (⌘,), Apps & Accounts, Usage and Keyboard\n * shortcuts (⌘/), plus the two shell preferences that used to sit on the rail\n * itself (rail labels, theme).\n *\n * A real menu: role=\"menu\" with menuitem / menuitemcheckbox / menuitemradio,\n * one roving tab stop, ↑ ↓ Home End to move, Enter / Space to choose, Esc\n * closes and puts focus back on the gear (a press outside just closes).\n * Portalled to <body> so the 56px rail cannot clip it.\n */\nimport { useEffect, useLayoutEffect, useRef, useState, type KeyboardEvent as ReactKeyboardEvent, type ReactNode, type RefObject } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useTheme } from '../../../data/hooks.js';\nimport type { ThemePreference } from '../../../data/theme-store.js';\nimport { useVerseUi } from '../useVerseUi.js';\nimport { AppsIcon, SettingsIcon, UsageIcon } from '../verse-icons.js';\nimport { IconKeyboard } from '../../../components/primitives/icons.js';\nimport { openVerseOverlay, setVerseSection, toggleVerseRail } from '../verse-ui-store.js';\nimport { detectKeyPlatform, findCommand, formatChord } from './command-catalog.js';\nimport styles from './GearTray.module.css';\n\nexport interface GearTrayProps {\n open: boolean;\n anchorRef: RefObject<HTMLElement | null>;\n onClose: () => void;\n /** Phone layout: the rail is a bottom bar, so the menu rises from it. */\n compact: boolean;\n}\n\ninterface Entry {\n key: string;\n role: 'menuitem' | 'menuitemcheckbox' | 'menuitemradio';\n label: string;\n icon?: ReactNode;\n shortcut?: string | null;\n checked?: boolean;\n run: () => void;\n /** Keep the menu open after choosing (theme / rail toggles). */\n stay?: boolean;\n}\n\nfunction shortcutOf(id: string): string | null {\n const chord = findCommand(id)?.keys[0];\n return chord ? formatChord(chord, detectKeyPlatform()) : null;\n}\n\nconst THEMES: ReadonlyArray<{ value: ThemePreference; label: string }> = [\n { value: 'system', label: 'Match system' },\n { value: 'light', label: 'Light' },\n { value: 'dark', label: 'Dark' },\n];\n\nexport function GearTray({ open, anchorRef, onClose, compact }: GearTrayProps) {\n const ui = useVerseUi();\n const theme = useTheme();\n const menuRef = useRef<HTMLDivElement>(null);\n const [active, setActive] = useState(0);\n const [position, setPosition] = useState<{ left: number; bottom: number } | null>(null);\n\n const entries: Entry[] = [\n { key: 'settings', role: 'menuitem', label: 'Settings', icon: <SettingsIcon />, shortcut: shortcutOf('section.settings'), run: () => setVerseSection('settings') },\n { key: 'apps', role: 'menuitem', label: 'Apps & Accounts', icon: <AppsIcon />, run: () => setVerseSection('apps') },\n { key: 'usage', role: 'menuitem', label: 'Usage', icon: <UsageIcon />, run: () => setVerseSection('usage') },\n { key: 'shortcuts', role: 'menuitem', label: 'Keyboard shortcuts', icon: <IconKeyboard />, shortcut: shortcutOf('shortcuts.open'), run: () => openVerseOverlay('shortcuts') },\n ...(compact\n ? []\n : [{ key: 'rail', role: 'menuitemcheckbox' as const, label: 'Show rail labels', shortcut: shortcutOf('rail.toggle-labels'), checked: ui.railExpanded, run: toggleVerseRail, stay: true }]),\n ...THEMES.map((t) => ({\n key: `theme-${t.value}`,\n role: 'menuitemradio' as const,\n label: t.label,\n checked: theme.theme === t.value,\n run: () => theme.set(t.value),\n stay: true,\n })),\n ];\n\n useLayoutEffect(() => {\n if (!open) return;\n const rect = anchorRef.current?.getBoundingClientRect();\n if (!rect) return;\n setPosition(\n compact\n ? { left: 8, bottom: Math.max(8, window.innerHeight - rect.top + 8) }\n : { left: rect.right + 8, bottom: Math.max(8, window.innerHeight - rect.bottom) },\n );\n }, [open, anchorRef, compact]);\n\n // Every open starts on the first item. Reset while rendering (React's\n // \"adjust state when a prop changes\"), not in an effect: an effect runs\n // after the focus effect below has already focused wherever the LAST open\n // left off, so focus would hop there and then back to the first item.\n const [wasOpen, setWasOpen] = useState(open);\n if (open !== wasOpen) {\n setWasOpen(open);\n if (open) setActive(0);\n }\n\n // The latest onClose, without re-subscribing the outside-press listener:\n // the shell passes an inline closure and re-renders on every activity poll.\n const closeRef = useRef(onClose);\n closeRef.current = onClose;\n\n useEffect(() => {\n if (!open) return;\n function onDown(event: MouseEvent) {\n const target = event.target as Node;\n if (menuRef.current?.contains(target) || anchorRef.current?.contains(target)) return;\n closeRef.current();\n }\n document.addEventListener('mousedown', onDown);\n return () => document.removeEventListener('mousedown', onDown);\n }, [open, anchorRef]);\n\n // Focus follows the roving tab stop — once the menu is placed. Until the\n // layout effect above has measured the gear, the menu renders\n // visibility:hidden and a browser will not focus it; the placed re-render\n // follows in the same task, before paint, and this effect runs again then.\n // (This used to be a requestAnimationFrame that focused item 0 whatever\n // `active` was: an arrow key pressed before that frame moved the tab stop,\n // then the frame pulled focus back to the first item, so focus and the tab\n // stop sat on different items and Enter chose the wrong one.)\n const placed = position !== null;\n useEffect(() => {\n if (!open || !placed) return;\n menuRef.current?.querySelector<HTMLElement>(`[data-index=\"${active}\"]`)?.focus();\n }, [active, open, placed]);\n\n // Escape hands focus back to the gear AFTER the close has rendered, not in\n // the key handler. The shell turns the gear's tooltip off while the tray is\n // open and back on when it closes, and that re-creates the gear <button>:\n // focusing `anchorRef.current` synchronously focused the button that was\n // about to leave the document, and focus fell to <body>. This effect runs\n // after the shell's commit, when the ref already points at the live button.\n const refocusOnClose = useRef(false);\n useEffect(() => {\n if (open || !refocusOnClose.current) return;\n refocusOnClose.current = false;\n anchorRef.current?.focus();\n }, [open, anchorRef]);\n\n if (!open) return null;\n\n function close(restoreFocus = true) {\n refocusOnClose.current = restoreFocus;\n onClose();\n }\n\n function choose(entry: Entry) {\n entry.run();\n if (!entry.stay) close(false);\n }\n\n function onKeyDown(event: ReactKeyboardEvent<HTMLDivElement>) {\n const count = entries.length;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActive((i) => (i + 1) % count);\n break;\n case 'ArrowUp':\n event.preventDefault();\n setActive((i) => (i - 1 + count) % count);\n break;\n case 'Home':\n event.preventDefault();\n setActive(0);\n break;\n case 'End':\n event.preventDefault();\n setActive(count - 1);\n break;\n case 'Escape':\n event.preventDefault();\n event.stopPropagation();\n close();\n break;\n case 'Tab':\n // A menu is one tab stop: Tab leaves it (and closes it).\n close(false);\n break;\n default:\n break;\n }\n }\n\n const themeStart = entries.findIndex((e) => e.key.startsWith('theme-'));\n\n return createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n aria-label=\"Settings and more\"\n className={styles.menu}\n data-compact={compact || undefined}\n style={position ? { left: position.left, bottom: position.bottom } : { visibility: 'hidden' }}\n onKeyDown={onKeyDown}\n >\n {entries.map((entry, index) => (\n <div key={entry.key} role=\"none\">\n {index === themeStart ? (\n <div role=\"separator\" className={styles.separator}>\n <span className={styles.groupLabel}>Theme</span>\n </div>\n ) : null}\n {entry.key === 'rail' ? <div role=\"separator\" className={styles.separator} /> : null}\n <button\n type=\"button\"\n role={entry.role}\n data-index={index}\n tabIndex={index === active ? 0 : -1}\n aria-checked={entry.role === 'menuitem' ? undefined : entry.checked === true}\n className={styles.item}\n onClick={() => choose(entry)}\n onMouseMove={() => index !== active && setActive(index)}\n >\n <span className={styles.icon} aria-hidden=\"true\">\n {entry.role === 'menuitem' ? entry.icon : entry.checked ? <span className={styles.check} /> : null}\n </span>\n <span className={styles.label}>{entry.label}</span>\n {entry.shortcut ? <kbd className={styles.key}>{entry.shortcut}</kbd> : null}\n </button>\n </div>\n ))}\n </div>,\n document.body,\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{a as e,c as t,n}from"./index-DZ-UQ7v8.js";import{g as r,h as i}from"./global-CMNW_dqn.js";import{p as a}from"./queries-BTXWdZzU.js";import{t as o}from"./RefreshIndicator-DO9ibnSq.js";import{c as s,y as c}from"./colors-DvK0wMHH.js";import{l,s as u}from"./format-D7nBg2bn.js";import{t as d}from"./AreaTrend-DK2Y2TbZ.js";import{n as f,t as p}from"./Funnel-Dh2yVHws.js";import{n as ee,r as te,t as m}from"./StepBand-BMtVOFpK.js";import{t as h}from"./calendar-day-BxBYHfX1.js";import{L as g}from"./VerseConsoleApp-CWU6R3By.js";import{c as _,n as v,t as ne}from"./AutonomyOffState-CEPSZToP.js";import{i as y,s as b}from"./surface-data-Dj71tdD-.js";import{a as x,r as S}from"./Surface-BfDmQcKe.js";import{t as re}from"./use-ticker-BBcp02SZ.js";var C=t(e(),1),w={"oversized-file":`some records are over the size bound`,"invalid-file":`some records are malformed`,"unsafe-file":`some records were refused (symlink, shared or foreign-owned)`,"unsafe-directory":`the store directory is not private`,"io-error":`some records could not be read`,"file-limit":`the store has more records than one read covers`,"invalid-row":`some ledger rows are malformed`,"oversized-row":`some ledger rows are over the size bound`,"duplicate-canonical-realized-merge-identity":`two proposals claim the same merge, so merges are unknown`,"claim-integrity-verdicts-not-persisted":`claim-check verdicts are not recorded per proposal yet`,"scorecard-trend-pending":`the scorecard trend is still being collected`,"scorecard-worker-unavailable":`the scorecard trend could not be read this time`};function T(e){return w[e]??e.replace(/-/g,` `)}function E(e,t){if(t.complete||t.state===`not-recorded`||t.reasons.length===0)return;let n=t.recordsSkipped>0?` (${t.recordsSkipped} skipped)`:``;return`${e} are lower bounds: ${t.reasons.map(T).join(`; `)}${n}.`}function D(e,t){return t.state===`not-recorded`?{kind:`unknown`,reason:`${T(t.reasons[0]??`not recorded`)}.`}:t.state===`degraded`&&t.recordsRead===0?{kind:`unknown`,reason:`${T(t.reasons[0]??`io-error`)}.`}:e.darkSince?{kind:`dark`,since:e.darkSince}:{kind:`ready`}}function O(e){let t=e.funnel,n=E(`Pipeline counts`,e.sources.proposals)??E(`Pipeline counts`,e.sources.decisions);return{stages:[{id:`filed`,label:`Filed`,value:t.filed},{id:`verified`,label:`Verified`,value:t.verified},{id:`passed`,label:`Verification passed`,value:t.verificationPassed},{id:`ship`,label:`Judged ship`,value:t.judgedShip},{id:`merged`,label:`Merged`,value:t.merged}],status:D(e,e.sources.proposals),...n?{caveat:n}:{}}}function k(e,t){return e.days.map(e=>({day:e.day,value:t(e)}))}var A=Object.freeze({minPairs:8,ciLevel:.95,minLiftCiLow:0,maxCostIncreasePct:20,canaryHours:48,rollbackStandardErrors:1,minHeldOutTasks:12});function ie(e){let t=[];for(let n=e.length;n-7>=0;n-=7){let r=e.slice(n-7,n),i=e=>{let t=0;for(let n of r){let r=e(n);if(r===null||!Number.isFinite(r))return null;t+=r}return t},a=r[r.length-1].day;t.unshift({end:h(a),endDay:a,merges:i(e=>e.merges.realized),costUsd:i(e=>e.estCostUsd)})}return t}function ae(e){return e.merges===null||e.costUsd===null||e.merges===0?null:e.costUsd/e.merges}var oe=[{id:`merged`,label:`Merged`,color:c(`success`)},{id:`ship`,label:`Judged ship, not merged`,color:c(`info`)},{id:`rejected`,label:`Judged not worth shipping`,color:c(`warning`)},{id:`unjudged`,label:`Not judged`,color:c(`neutral`)}],j=/[-@](?:\d{8}|\d{4}-\d{2}-\d{2})$/;function M(e,t=18){if(e.length<=t)return e;let n=e.slice(0,t),r=Math.max(n.lastIndexOf(` `),n.lastIndexOf(`-`),n.lastIndexOf(`:`));return r>0?`${e.slice(0,r)}…`:e}function N(e){let t=e.map(e=>{let t=e.model.includes(`/`)?e.model.split(`/`).pop():e.model,n=t.replace(j,``)||t;return[M(n),n,t,e.model,`${e.engine}:${e.model}`]}),n=e.map(()=>0),r=()=>t.map((e,t)=>e[n[t]]),i=t[0]?.length??0;for(let e=1;e<i;e++){let t=r(),i=new Map;for(let e of t)i.set(e,(i.get(e)??0)+1);let a=t.map(e=>i.get(e)>1);if(!a.includes(!0))break;a.forEach((t,r)=>{t&&(n[r]=e)})}let a=new Set;return r().map(e=>{let t=e;for(let n=2;a.has(t);n++)t=`${e} #${n}`;return a.add(t),t})}function se(e,t=6){let n=[...e].filter(e=>e.dispatches>0).sort((e,t)=>t.dispatches-e.dispatches).slice(0,t);return{categories:N(n),values:n.map(e=>{let t=Math.max(0,e.merged);return[t,Math.max(0,e.shipVerdicts-t),Math.max(0,e.judged-e.shipVerdicts),Math.max(0,e.dispatches-e.judged)]}),costPerMerged:n.map(e=>e.costPerMergedUsd),models:n}}var P=Date.UTC(2020,0,1),F=7776e6;function I(e){if(!e)return null;let t=Date.parse(e);return Number.isFinite(t)&&t>=P?t:null}function L(e,t,n){let r=I(t.createdAt);if(r!==null)return r;let i=[...e.versions.filter(e=>e.id!==t.id).flatMap(e=>[e.createdAt,e.adoptedAt,e.rolledBackAt]),...e.experiments.flatMap(e=>[e.startedAt,e.finishedAt])].map(I).filter(e=>e!==null);return i.length>0?Math.min(...i):n-F}function R(e,t){if(!e||e.versions.length===0)return{steps:[],markers:[]};let n=new Map(e.versions.map(e=>[e.id,e])),r=new Map(e.experiments.map(e=>[e.id,e])),i=new Map,a=[],o=[...e.versions].sort((e,t)=>e.seq-t.seq)[0];i.set(o.id,0);let s=L(e,o,t??I(e.generatedAt)??Date.now());a.push({at:s,step:{id:`${o.id}@base`,at:s,value:0,low:0,high:0,label:o.status===`baseline`?`Compiled defaults`:o.id,detail:`baseline`}});let c=e.versions.filter(e=>e.adoptedAt&&e.id!==o.id).sort((e,t)=>Date.parse(e.adoptedAt)-Date.parse(t.adoptedAt));for(let e of c){let t=e.experimentId?r.get(e.experimentId):void 0,s=t?.baseVersionId??e.parentId??o.id,c=i.get(s)??(n.has(s)?null:0),l=t?.lift??null,u=l&&c!=null?c+l.mean:null;i.set(e.id,u);let d=I(e.adoptedAt);if(d===null)continue;let f=e.status===`canary`?`canary`:e.status===`rolled-back`?`adopted, later rolled back`:`adopted`;if(a.push({at:d,step:{id:`${e.id}@adopt`,at:d,value:u,low:u!==null&&l?c+l.ciLow:null,high:u!==null&&l?c+l.ciHigh:null,label:e.id,detail:f}}),e.rolledBackAt){let t=I(e.rolledBackAt);if(t!==null){let r=i.get(s)??null,o=n.get(s);a.push({at:t,marker:{id:`${e.id}@rb`,at:t,kind:`rollback`,label:`${e.id}: ${e.rollbackReason??`rolled back`}`}}),a.push({at:t+1,step:{id:`${e.id}@rb-step`,at:t+1,value:r,low:null,high:null,label:o?.id??s,detail:`restored after ${e.id} rolled back`}})}}}return a.sort((e,t)=>e.at-t.at),{steps:a.flatMap(e=>e.step?[e.step]:[]),markers:a.flatMap(e=>e.marker?[e.marker]:[])}}var z={adopt:`passed the gate`,reject:`rejected`,inconclusive:`inconclusive`};function B(e){return e?e.experiments.map(e=>({id:e.id,label:`${e.candidateVersionId} vs ${e.baseVersionId}`,estimate:e.lift?.mean??null,low:e.lift?.ciLow??null,high:e.lift?.ciHigh??null,n:e.pairs,detail:e.status===`running`||e.status===`queued`?`${e.status} · ${e.pairs}/${A.minPairs} pairs`:e.verdict?z[e.verdict]??e.verdict:e.status})):[]}var V=n(),H=3e5,U=a(`30d`),W=[{id:`merges`,label:`Merges`,color:s}];function G(e,t){return{kind:`unknown`,reason:e??t}}function K(){let e=i(y,{freshMs:6e4}),t=i(b,{freshMs:6e4}),n=i(U,{freshMs:6e4}),a=r(y),c=r(b),h=r(U);g(()=>{a(),c(),h()},H);let w=re(6e4),T=e.data?.value??null,j=t.data?.value??null,M=(0,C.useMemo)(()=>T?ie(T.days):[],[T]),N=e.data?T?_(D(T,T.sources.runs)):G(e.data.reason,`fleet history did not answer.`):{kind:`loading`},P=N.kind===`ready`?M.length===0?{kind:`empty`,message:`Less than a week of history.`}:{kind:`ready`}:N,F=T?E(`Merge counts`,T.sources.decisions):void 0,I=T?O(T):null,L=(0,C.useMemo)(()=>se(n.data?.models??[]),[n.data]),z=n.status===`loading`?{kind:`loading`}:n.status===`error`||!n.data?{kind:`unknown`,reason:`per-model economics could not be read.`}:L.categories.length===0?{kind:`empty`,message:`No fleet dispatches in 30 days.`}:{kind:`ready`},K=(0,C.useMemo)(()=>R(j),[j]),q=(0,C.useMemo)(()=>B(j),[j]),J=(e,n)=>t.data?j?n?{kind:`ready`}:{kind:`empty`,message:e}:G(t.data.reason,`self-improvement did not answer.`):{kind:`loading`},Y=T?.darkSince??null,X=v(Y),Z=Y!==null&&X!=null,Q=K.steps.length>1||K.markers.length>0,ce=!Z||z.kind===`ready`,le=!Z||Q,ue=!Z||q.length>0,de=Z&&z.kind!==`ready`&&!Q&&q.length===0,$=e=>`wk to ${u(e)}`;return(0,V.jsxs)(x,{title:`Growth`,actions:[e,t].some(e=>e.status===`refreshing`)?(0,V.jsx)(o,{}):null,children:[X?(0,V.jsx)(S,{span:12,children:(0,V.jsx)(ne,{state:X,here:`growth`,title:de?`Growth starts with the first fleet run.`:void 0})}):null,Z?null:(0,V.jsx)(S,{span:8,children:(0,V.jsx)(f,{title:`Merges per week`,description:`Rolling 7-day windows ending today`,caveat:F,status:P,categories:M.map(e=>$(e.end)),segments:W,values:M.map(e=>[e.merges]),height:200})}),Z?null:(0,V.jsx)(S,{span:4,children:(0,V.jsx)(d,{title:`Cost per merge`,description:`Estimated run spend ÷ merges, per week`,status:P,series:[{id:`cpm`,label:`Cost per merge`,color:s,points:M.map(e=>({x:e.end,y:ae(e)}))}],formatX:$,formatY:l,height:200})}),Z?null:(0,V.jsx)(S,{span:4,children:(0,V.jsx)(p,{title:`Pipeline · 90d`,description:`Filed → verified → passed → judged ship → merged`,caveat:I?.caveat,status:I?_(I.status):N,stages:I?.stages??[]})}),ce?(0,V.jsx)(S,{span:4,children:(0,V.jsx)(f,{title:`Model outcomes · 30d`,description:`What each model's dispatches became`,status:z,categories:L.categories,segments:oe,values:L.values,height:200})}):null,Z?null:(0,V.jsx)(S,{span:4,children:(0,V.jsx)(te,{title:`Merges by day`,description:`Last 90 days`,status:N,days:T?k(T,e=>e.merges.realized):[],unit:`merges`})}),le?(0,V.jsx)(S,{span:8,children:(0,V.jsx)(`div`,{title:`Band = each step's own 95% interval. A new harness runs as a canary for ${A.canaryHours} h first.`,children:(0,V.jsx)(m,{title:`Harness level`,description:`Pass-rate lift vs defaults`,status:J(`Compiled defaults in force.`,K.steps.length>0),steps:K.steps,markers:K.markers,now:w,baseline:{value:0,label:`Compiled defaults`},unit:`pts`})})}):null,ue?(0,V.jsx)(S,{span:4,children:(0,V.jsx)(`div`,{title:`Adopted only when the interval's low end is above ${A.minLiftCiLow}, over at least ${A.minPairs} pairs.`,children:(0,V.jsx)(ee,{title:`Experiments`,description:`Paired lift, 95% interval`,status:J(`No experiments yet.`,q.length>0),rows:q,unit:`pts`,unknownText:`under ${A.minPairs} pairs`})})}):null]})}export{H as GROWTH_POLL_MS,K as GrowthSection};
2
+ //# sourceMappingURL=GrowthSection-P9EUfGeA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GrowthSection-BvZezOsX.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/fleet-history-view.ts","../../../../../../src/core/learn/harness-types.ts","../../../../../../src/web-ui/routes/verse/growth/growth-model.ts","../../../../../../src/web-ui/routes/verse/sections/GrowthSection.tsx"],"sourcesContent":["/**\n * components/charts/fleet-history-view.ts — maps the `GET /api/verse/fleet/history`\n * payload (core/verse/fleet-history-types.ts) onto the chart kit's props, so\n * every surface that charts fleet history (Command, Fleet, Growth) makes the\n * same honesty decisions:\n *\n * - the fleet is DARK → every chart shows \"Fleet dark since <date>\", not\n * empty axes;\n * - a source could not be read at all → \"unknown\", not zeros;\n * - a source was only partly read → a caveat naming why (lower bounds);\n * - claim-check → always the not-recorded state, never a fabricated series.\n *\n * Pure functions over the wire type; no fetching here.\n */\nimport type {\n FleetHistoryDay,\n FleetHistoryResponse,\n FleetHistorySource,\n} from '../../../core/verse/fleet-history-types.js';\nimport type { ChartStatus } from './ChartFrame.js';\nimport type { BarStackProps } from './BarStack.js';\nimport type { FunnelStage } from './Funnel.js';\nimport type { SwimlaneLane } from './Swimlane.js';\nimport type { CalendarDatum } from './CalendarHeatmap.js';\nimport type { AreaTrendSeries } from './AreaTrend.js';\nimport { toneColor } from './colors.js';\nimport { formatDayLabel } from './format.js';\n\nconst REASON_TEXT: Record<string, string> = {\n 'oversized-file': 'some records are over the size bound',\n 'invalid-file': 'some records are malformed',\n 'unsafe-file': 'some records were refused (symlink, shared or foreign-owned)',\n 'unsafe-directory': 'the store directory is not private',\n 'io-error': 'some records could not be read',\n 'file-limit': 'the store has more records than one read covers',\n 'invalid-row': 'some ledger rows are malformed',\n 'oversized-row': 'some ledger rows are over the size bound',\n 'duplicate-canonical-realized-merge-identity': 'two proposals claim the same merge, so merges are unknown',\n 'claim-integrity-verdicts-not-persisted': 'claim-check verdicts are not recorded per proposal yet',\n 'scorecard-trend-pending': 'the scorecard trend is still being collected',\n 'scorecard-worker-unavailable': 'the scorecard trend could not be read this time',\n};\n\nfunction reasonText(reason: string): string {\n return REASON_TEXT[reason] ?? reason.replace(/-/g, ' ');\n}\n\n/** A caveat sentence for a partly-read source, or undefined when it is complete. */\nexport function sourceCaveat(label: string, source: FleetHistorySource): string | undefined {\n if (source.complete || source.state === 'not-recorded') return undefined;\n if (source.reasons.length === 0) return undefined;\n const skipped = source.recordsSkipped > 0 ? ` (${source.recordsSkipped} skipped)` : '';\n return `${label} are lower bounds: ${source.reasons.map(reasonText).join('; ')}${skipped}.`;\n}\n\n/**\n * The shared status for a chart over one source. Order matters: unreadable\n * beats dark (we cannot claim darkness from a store we cannot read), and dark\n * beats an all-zero window (the designed \"since\" message is more useful).\n */\nexport function historyStatus(history: FleetHistoryResponse, source: FleetHistorySource): ChartStatus {\n if (source.state === 'not-recorded') return { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'not recorded')}.` };\n if (source.state === 'degraded' && source.recordsRead === 0) {\n return { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'io-error')}.` };\n }\n if (history.darkSince) return { kind: 'dark', since: history.darkSince };\n return { kind: 'ready' };\n}\n\n/** \"Sep 3\" for a day row (the wire's days are already in the caller's zone). */\nexport function dayLabel(day: FleetHistoryDay): string {\n return formatDayLabel(day.day);\n}\n\n/** Runs per day as done / failed / aborted / unfinished — status tones, legend-labelled. */\nexport function runsByDay(history: FleetHistoryResponse): Pick<BarStackProps, 'categories' | 'segments' | 'values' | 'status' | 'caveat'> {\n return {\n categories: history.days.map(dayLabel),\n segments: [\n { id: 'done', label: 'Done', color: toneColor('success') },\n { id: 'failed', label: 'Failed', color: toneColor('danger') },\n { id: 'aborted', label: 'Aborted', color: toneColor('neutral') },\n { id: 'unfinished', label: 'Unfinished', color: toneColor('running') },\n ],\n values: history.days.map((d) => [d.runs.done, d.runs.failed, d.runs.aborted, d.runs.unfinished]),\n status: historyStatus(history, history.sources.runs),\n caveat: sourceCaveat('Run counts', history.sources.runs),\n };\n}\n\n/** Judge verdicts per day (the considered ones, plus failed judge calls). */\nexport function verdictsByDay(history: FleetHistoryResponse): Pick<BarStackProps, 'categories' | 'segments' | 'values' | 'status' | 'caveat'> {\n return {\n categories: history.days.map(dayLabel),\n segments: [\n { id: 'ship', label: 'Ship', color: toneColor('success') },\n { id: 'review', label: 'Review', color: toneColor('warning') },\n { id: 'noise', label: 'Noise', color: toneColor('neutral') },\n { id: 'harmful', label: 'Harmful', color: toneColor('danger') },\n { id: 'failed', label: 'Judge failed', color: toneColor('unknown') },\n ],\n values: history.days.map((d) => [d.judged.ship, d.judged.review, d.judged.noise, d.judged.harmful, d.judged.failed]),\n status: historyStatus(history, history.sources.decisions),\n caveat: sourceCaveat('Verdict counts', history.sources.decisions),\n };\n}\n\n/** Proposal pipeline for the window (cumulative stages — see FleetHistoryFunnel). */\nexport function pipelineFunnel(history: FleetHistoryResponse): { stages: FunnelStage[]; status: ChartStatus; caveat?: string } {\n const f = history.funnel;\n const caveat = sourceCaveat('Pipeline counts', history.sources.proposals) ?? sourceCaveat('Pipeline counts', history.sources.decisions);\n return {\n stages: [\n { id: 'filed', label: 'Filed', value: f.filed },\n { id: 'verified', label: 'Verified', value: f.verified },\n { id: 'passed', label: 'Verification passed', value: f.verificationPassed },\n { id: 'ship', label: 'Judged ship', value: f.judgedShip },\n { id: 'merged', label: 'Merged', value: f.merged },\n ],\n status: historyStatus(history, history.sources.proposals),\n ...(caveat ? { caveat } : {}),\n };\n}\n\n/** Swimlane lanes straight from the projection (runs → bars, engine as detail). */\nexport function runLanes(history: FleetHistoryResponse): { lanes: SwimlaneLane[]; from: number; to: number; status: ChartStatus; caveat?: string } {\n const truncated = history.swimlanesTruncated ? 'Showing the newest runs only; the full list is longer.' : undefined;\n const caveat = [sourceCaveat('Runs', history.sources.runs), truncated].filter(Boolean).join(' ') || undefined;\n return {\n lanes: history.swimlanes.map((lane) => ({\n id: lane.id,\n label: lane.label,\n items: lane.items.map((item) => ({\n id: item.id,\n start: item.startMs,\n end: item.endMs,\n status: item.status,\n detail: item.engine,\n stale: item.stale,\n })),\n })),\n from: Date.parse(history.window.from),\n to: Date.parse(history.window.to),\n status: historyStatus(history, history.sources.runs),\n ...(caveat ? { caveat } : {}),\n };\n}\n\n/** One number per day for the calendar heatmap. */\nexport function dailyValues(history: FleetHistoryResponse, pick: (day: FleetHistoryDay) => number | null): CalendarDatum[] {\n return history.days.map((d) => ({ day: d.day, value: pick(d) }));\n}\n\n/** Scorecard trend (daily snapshots of the trailing window) as AreaTrend series. */\nexport function scorecardSeries(history: FleetHistoryResponse, window: '7d' | '30d' = '7d'): { series: AreaTrendSeries[]; status: ChartStatus; caveat?: string } {\n const points = window === '7d' ? history.scorecard.trend7d : history.scorecard.trend30d;\n const source = history.scorecard.source;\n const status: ChartStatus = points.length === 0\n ? source.state === 'degraded'\n ? { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'io-error')}.` }\n : { kind: 'empty', message: 'No scorecard snapshots yet — the first is taken today, then one a day.' }\n : { kind: 'ready' };\n const caveat = points.length > 0 ? sourceCaveat('Scorecard points', source) : undefined;\n return {\n series: [\n { id: 'merges', label: 'Merges', points: points.map((p) => ({ x: Date.parse(p.ts), y: p.merges.realized })) },\n { id: 'filed', label: 'Proposals filed', points: points.map((p) => ({ x: Date.parse(p.ts), y: p.proposalsFiled })) },\n ],\n status,\n ...(caveat ? { caveat } : {}),\n };\n}\n","/**\n * Harness registry + experiments — V3.10 Track B contract (unit B-U1, frozen day 0).\n *\n * A HARNESS is the config-only envelope around the fleet's models: prompt\n * overlays, effort, sampling, routing weights and enabled skills. The\n * self-improvement loop (unit U9) versions harnesses, A/B-tests a candidate\n * against the active version on free local slots (paired runs, 95% CI,\n * ≥ 8 pairs, held-out tasks), and adopts a winner only through the Leader's\n * class-B action, behind a 48 h canary with automatic rollback.\n *\n * WHY config-only: a harness can never carry code, so adopting one can never\n * change authority (SPEC-310B I2). Code self-improvement arrives as ordinary\n * fleet PRs that pass every merge gate and only run after Mason deploys them.\n *\n * Honesty rule: `null` = unknown / not measured, never zero.\n *\n * BROWSER-SAFE: the Growth surface imports this — type-only imports, plain consts.\n */\nimport type { RoutingDifficulty } from '../routing/types.js';\nimport type { FleetEngine } from '../fleet/fleet-types.js';\n\nexport const VERSE_LEARNING_PATH = '/api/verse/learning';\n\n// ---------------------------------------------------------------------------\n// Harness config (what a version pins)\n// ---------------------------------------------------------------------------\n\nexport type HarnessEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\n/** Roles a prompt overlay can target. */\nexport type HarnessRole = 'producer' | 'judge' | 'leader' | 'planner';\n\nexport interface HarnessSampling {\n /** null = the engine's own default. */\n temperature: number | null;\n topP: number | null;\n maxOutputTokens: number | null;\n}\n\n/**\n * The dispatch router's tunables. Precedence at dispatch (U5): a Leader\n * `router.tune` override (LeaderDirectivesV1) › the active harness › the\n * router's compiled defaults. All λ are ≥ 0.\n */\nexport interface HarnessRoutingWeights {\n lambdaCost: number;\n lambdaPressure: number;\n lambdaLatency: number;\n /** Best-of-N runs at and above this difficulty. */\n bonThreshold: RoutingDifficulty;\n}\n\nexport interface HarnessConfigV1 {\n v: 1;\n /** Text appended to a role's system prompt; absent role = no overlay. Scrubbed, ≤ 4 KB each. */\n prompts: Partial<Record<HarnessRole, string>>;\n /** Effort per fleet engine; absent = engine default. */\n effort: Partial<Record<FleetEngine, HarnessEffort>>;\n /** Sampling per fleet engine; absent = engine default. */\n sampling: Partial<Record<FleetEngine, HarnessSampling>>;\n routing: HarnessRoutingWeights;\n /** Enabled skill ids, sorted. */\n skills: string[];\n}\n\n/** A config change. Top-level fields present here REPLACE the base's field wholesale (no deep merge). */\nexport type HarnessConfigPatch = Partial<Omit<HarnessConfigV1, 'v'>>;\n\n// ---------------------------------------------------------------------------\n// Versions\n// ---------------------------------------------------------------------------\n\n/**\n * - `baseline` — version 0: the compiled defaults.\n * - `candidate` — under experiment.\n * - `canary` — adopted, inside its 48 h canary.\n * - `adopted` — canary passed; the active version.\n * - `rolled-back` — canary fell below baseline − 1 SE (or vetoed).\n * - `rejected` — failed the adoption gate.\n */\nexport type HarnessVersionStatus = 'baseline' | 'candidate' | 'canary' | 'adopted' | 'rolled-back' | 'rejected';\n\nexport interface HarnessVersion {\n v: 1;\n /** Stable id, e.g. `h-0007`. */\n id: string;\n /** Monotonic; baseline = 0. */\n seq: number;\n parentId: string | null;\n createdAt: string;\n status: HarnessVersionStatus;\n config: HarnessConfigV1;\n /** sha256 hex of the canonical config — what experiments and ledger rows bind to. */\n configDigest: string;\n source: { kind: 'baseline' | 'hypothesis' | 'manual'; hypothesisId: string | null };\n /** The experiment whose verdict justified adoption; null for baseline / manual. */\n experimentId: string | null;\n adoptedAt: string | null;\n /** End of the 48 h canary; null when not in canary. */\n canaryUntil: string | null;\n rolledBackAt: string | null;\n rollbackReason: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Hypotheses and experiments\n// ---------------------------------------------------------------------------\n\nexport type HarnessTarget = 'prompt' | 'effort' | 'sampling' | 'routing' | 'skill';\n\n/** A typed, testable claim about a config change (the Leader emits ≤ 3 per memo; A7 insights may too). */\nexport interface HarnessHypothesis {\n v: 1;\n id: string;\n source: { kind: 'leader' | 'insight' | 'manual'; ref: string | null };\n target: HarnessTarget;\n /** Config only — never code. */\n patch: HarnessConfigPatch;\n /** The claim in one sentence. Untrusted model text: scrubbed, rendered as text. */\n statement: string;\n /** Metric it should move, e.g. `local-eval.pass-rate`. */\n metric: string;\n /** Predicted change, in the metric's units. */\n predictedDelta: number;\n createdAt: string;\n}\n\nexport type ExperimentVerdict = 'adopt' | 'reject' | 'inconclusive';\n\nexport type ExperimentStatus = 'queued' | 'running' | 'done' | 'cancelled' | 'failed';\n\nexport interface ExperimentLift {\n /** Paired pass-rate lift of candidate over base, in percentage points. */\n mean: number;\n ciLow: number;\n ciHigh: number;\n level: 0.95;\n}\n\nexport interface ExperimentResultV1 {\n v: 1;\n id: string;\n hypothesisId: string | null;\n baseVersionId: string;\n candidateVersionId: string;\n /** The held-out task set the pairs were drawn from. */\n taskSet: { id: string; digest: string };\n status: ExperimentStatus;\n /** Complete pairs so far. */\n pairs: number;\n wins: number;\n losses: number;\n ties: number;\n /** null until pairs ≥ HARNESS_ADOPTION_GATE.minPairs. */\n lift: ExperimentLift | null;\n /** Any `refuse`-class task regressed (blocks adoption). null = not measured yet. */\n refuseRegression: boolean | null;\n /** candidate − base count of `claimed-change-none-made` failures; must be ≤ 0 to adopt. */\n claimedChangeNoneMadeDelta: number | null;\n /** Wall-time / cost change in percent; must be ≤ +20 to adopt. */\n costDeltaPct: number | null;\n /** null while running. */\n verdict: ExperimentVerdict | null;\n /** Specific sentences behind the verdict. */\n reasons: string[];\n startedAt: string | null;\n finishedAt: string | null;\n}\n\n/**\n * The adoption gate (SPEC-310B §5) — frozen numbers. Adoption is a Leader\n * class-B action and requires ALL of: pairs ≥ minPairs, lift.ciLow >\n * minLiftCiLow, no refuse regression, claimedChangeNoneMadeDelta ≤ 0, and\n * costDeltaPct ≤ maxCostIncreasePct.\n */\nexport const HARNESS_ADOPTION_GATE = Object.freeze({\n minPairs: 8,\n ciLevel: 0.95,\n minLiftCiLow: 0,\n maxCostIncreasePct: 20,\n canaryHours: 48,\n /** Roll back when the canary pass rate falls below baseline − this many standard errors. */\n rollbackStandardErrors: 1,\n /** local-eval/tasks-heldout.ts must hold at least this many tasks (20 of 22 current tasks are saturated). */\n minHeldOutTasks: 12,\n} as const);\n\n/** Ledger payload for harness:adopted / harness:rolled-back / harness:rejected. */\nexport interface HarnessTransition {\n versionId: string;\n /** The version active before; null when none. */\n fromVersionId: string | null;\n configDigest: string;\n experimentId: string | null;\n reason: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cross-unit request / result shapes (learn/{experiments,harness-registry}.ts)\n// ---------------------------------------------------------------------------\n\nexport type HarnessActor = 'mason' | 'leader' | 'daemon';\n\nexport interface StartExperimentRequest {\n hypothesis: HarnessHypothesis;\n requestedBy: HarnessActor;\n}\n\nexport type StartExperimentResult = { ok: true; experimentId: string } | { ok: false; reason: string };\n\nexport interface CancelExperimentRequest {\n experimentId: string;\n reason: string;\n actor: HarnessActor;\n}\n\n/** A finished experiment cannot be cancelled (ok: false). */\nexport type CancelExperimentResult = { ok: true } | { ok: false; reason: string };\n\nexport interface AdoptHarnessRequest {\n versionId: string;\n /** The experiment whose verdict passed the gate. */\n experimentId: string;\n actor: HarnessActor;\n}\n\nexport interface RollbackHarnessRequest {\n /** The version to make active again; null = back to the baseline defaults. */\n toVersionId: string | null;\n reason: string;\n actor: HarnessActor;\n}\n\n/** `before` is the version active before the call, so a veto can restore it exactly. */\nexport type HarnessChangeResult =\n | { ok: true; before: HarnessVersion | null; after: HarnessVersion | null }\n | { ok: false; reason: string };\n\n// ---------------------------------------------------------------------------\n// Learning API (U9) — GET /api/verse/learning\n// ---------------------------------------------------------------------------\n\nexport interface HarnessCanaryState {\n versionId: string;\n startedAt: string;\n until: string;\n baselinePassRate: number | null;\n baselineStandardError: number | null;\n currentPassRate: number | null;\n runs: number;\n}\n\nexport interface LearningStateV1 {\n v: 1;\n generatedAt: string;\n /** null = nothing adopted; the baseline defaults are in force. */\n active: HarnessVersion | null;\n canary: HarnessCanaryState | null;\n /** Oldest → newest (Growth step chart with CI band and rollback markers). */\n versions: HarnessVersion[];\n /** Newest first (ForestPlot). */\n experiments: ExperimentResultV1[];\n /** Open hypotheses not yet tested. */\n hypotheses: HarnessHypothesis[];\n}\n","/**\n * routes/verse/growth/growth-model.ts — \"is the output compounding?\" as pure\n * data (unit C7; SPEC-310B §6 Growth, SPEC-310C §5).\n *\n * weeklyBins rolling 7-day windows ENDING TODAY, so every point is a\n * complete week (a calendar week-to-date would dip every\n * Monday and read as a regression);\n * costPerMerge spend ÷ merges per window — undefined (null) for a week\n * with no merges, never $0 or ∞;\n * modelOutcomes what each model's dispatches became (ROI composition);\n * harnessSteps the active harness's level over time: each adoption\n * steps up by its experiment's lift, a rollback steps back\n * down with a ▼ marker; only real timestamps, never the\n * baseline's epoch stamp;\n * forestRows one row per experiment, newest first.\n *\n * Framework-free; tested directly.\n */\nimport type { FleetHistoryDay } from '../../../../core/verse/fleet-history-types.js';\nimport type { ExperimentResultV1, HarnessVersion, LearningStateV1 } from '../../../../core/learn/harness-types.js';\nimport { HARNESS_ADOPTION_GATE } from '../../../../core/learn/harness-types.js';\nimport type { ModelStats } from '../../../data/api-types.js';\nimport type { BarStackSegment } from '../../../components/charts/BarStack.js';\nimport { toneColor } from '../../../components/charts/colors.js';\nimport type { ForestRow } from '../../../components/charts/ForestPlot.js';\nimport type { StepMarker, StepPoint } from '../../../components/charts/StepBand.js';\nimport { calendarDayStart } from './calendar-day.js';\n\nexport interface WeekBin {\n /**\n * Epoch ms of the window's last day at the viewer's LOCAL midnight\n * (`calendarDayStart`), so every local time label names that day.\n */\n end: number;\n /** YYYY-MM-DD of the last day. */\n endDay: string;\n merges: number | null;\n costUsd: number | null;\n}\n\n/** Complete 7-day windows ending on the last day of `days`, oldest first. */\nexport function weeklyBins(days: readonly FleetHistoryDay[]): WeekBin[] {\n const bins: WeekBin[] = [];\n for (let end = days.length; end - 7 >= 0; end -= 7) {\n const week = days.slice(end - 7, end);\n const sum = (pick: (d: FleetHistoryDay) => number | null): number | null => {\n let total = 0;\n for (const d of week) {\n const v = pick(d);\n if (v === null || !Number.isFinite(v)) return null;\n total += v;\n }\n return total;\n };\n const lastDay = week[week.length - 1]!.day;\n bins.unshift({ end: calendarDayStart(lastDay), endDay: lastDay, merges: sum((d) => d.merges.realized), costUsd: sum((d) => d.estCostUsd) });\n }\n return bins;\n}\n\n/** Dollars per merge; null when either side is unknown or nothing merged. */\nexport function costPerMerge(bin: WeekBin): number | null {\n if (bin.merges === null || bin.costUsd === null || bin.merges === 0) return null;\n return bin.costUsd / bin.merges;\n}\n\n// ---------------------------------------------------------------------------\n// Model outcomes (ROI)\n// ---------------------------------------------------------------------------\n\nexport const OUTCOME_SEGMENTS: BarStackSegment[] = [\n { id: 'merged', label: 'Merged', color: toneColor('success') },\n { id: 'ship', label: 'Judged ship, not merged', color: toneColor('info') },\n { id: 'rejected', label: 'Judged not worth shipping', color: toneColor('warning') },\n { id: 'unjudged', label: 'Not judged', color: toneColor('neutral') },\n];\n\nexport interface ModelOutcomes {\n categories: string[];\n values: (number | null)[][];\n /** Per category, for the caption / table: dollars per merge. */\n costPerMerged: (number | null)[];\n models: ModelStats[];\n}\n\n/** The longest model name an axis category keeps before it is shortened. */\nexport const MODEL_LABEL_MAX = 18;\n\n/** A snapshot date at the end of a model id: `-20251001`, `-2025-10-01`, `@20251001`. */\nconst DATE_SUFFIX = /[-@](?:\\d{8}|\\d{4}-\\d{2}-\\d{2})$/;\n\n/**\n * `name` shortened to at most `max` characters by cutting at a word boundary\n * (a space, `-` or `:`) and closing with \"…\" — never mid-word\n * (`grok-4.7-fast-reasoning` → `grok-4.7-fast…`). A name with no boundary\n * early enough stays whole: a long label beats a broken word.\n */\nfunction cutAtBoundary(name: string, max = MODEL_LABEL_MAX): string {\n if (name.length <= max) return name;\n const head = name.slice(0, max);\n const at = Math.max(head.lastIndexOf(' '), head.lastIndexOf('-'), head.lastIndexOf(':'));\n return at > 0 ? `${name.slice(0, at)}…` : name;\n}\n\n/**\n * Each model's axis name, UNIQUE across the chart. A model reads as its id\n * without a vendor path or snapshot date (`claude-haiku-4-5`), shortened only\n * at a word boundary. Names that would read the same — two dated snapshots of\n * one model, two long ids sharing a prefix, one tag on two engines — step\n * down TOGETHER through the same fuller forms until they differ: the whole\n * name, the id with its date, the id with its vendor path, `engine:model`\n * (so `claude-haiku-4-5-20251001` and `claude-haiku-4-5` both keep plain\n * ids). An ordinal (\"#2\") is the last resort: two columns never share a label.\n */\nexport function modelLabels(models: readonly Pick<ModelStats, 'engine' | 'model'>[]): string[] {\n // One rung per form, the same rungs for every model (a form that adds\n // nothing for this model simply repeats), so a group steps in lockstep.\n const ladders = models.map((m) => {\n const id = m.model.includes('/') ? m.model.split('/').pop()! : m.model;\n const name = id.replace(DATE_SUFFIX, '') || id;\n return [cutAtBoundary(name), name, id, m.model, `${m.engine}:${m.model}`];\n });\n const level = models.map(() => 0);\n const current = () => ladders.map((l, i) => l[level[i]!]!);\n const rungs = ladders[0]?.length ?? 0;\n for (let rung = 1; rung < rungs; rung++) {\n const labels = current();\n const seen = new Map<string, number>();\n for (const l of labels) seen.set(l, (seen.get(l) ?? 0) + 1);\n const clashing = labels.map((l) => seen.get(l)! > 1);\n if (!clashing.includes(true)) break;\n clashing.forEach((clash, i) => {\n if (clash) level[i] = rung;\n });\n }\n const taken = new Set<string>();\n return current().map((l) => {\n let label = l;\n for (let n = 2; taken.has(label); n++) label = `${l} #${n}`;\n taken.add(label);\n return label;\n });\n}\n\n/** Top `limit` models by dispatches, each split into what its dispatches became. */\nexport function modelOutcomes(models: readonly ModelStats[], limit = 6): ModelOutcomes {\n const top = [...models].filter((m) => m.dispatches > 0).sort((a, b) => b.dispatches - a.dispatches).slice(0, limit);\n return {\n categories: modelLabels(top),\n values: top.map((m) => {\n const merged = Math.max(0, m.merged);\n const ship = Math.max(0, m.shipVerdicts - merged);\n const rejected = Math.max(0, m.judged - m.shipVerdicts);\n const unjudged = Math.max(0, m.dispatches - m.judged);\n return [merged, ship, rejected, unjudged];\n }),\n costPerMerged: top.map((m) => m.costPerMergedUsd),\n models: top,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Harness steps + experiments\n// ---------------------------------------------------------------------------\n\nexport interface HarnessSeries {\n steps: StepPoint[];\n markers: StepMarker[];\n}\n\n/**\n * Anything stamped before this is not a real harness event. The registry\n * stamps the compiled-defaults baseline `1970-01-01T00:00:00.000Z` (it has no\n * creation time — core/learn/harness-registry.ts `baselineVersion`), and a\n * step drawn there stretched the x-axis from \"Dec 31\" to today. No Ashlr\n * harness predates 2020, so the floor also catches any other zero-ish stamp.\n */\nexport const HARNESS_TIME_FLOOR_MS = Date.UTC(2020, 0, 1);\n\n/** With nothing but the compiled defaults on record, the chart shows this trailing window. */\nexport const HARNESS_BASELINE_WINDOW_MS = 90 * 86_400_000;\n\n/** Epoch ms of a real harness timestamp; null for missing, unparsable or pre-floor (epoch) stamps. */\nexport function harnessTime(iso: string | null | undefined): number | null {\n if (!iso) return null;\n const t = Date.parse(iso);\n return Number.isFinite(t) && t >= HARNESS_TIME_FLOOR_MS ? t : null;\n}\n\n/**\n * When the compiled-defaults step starts: the baseline's own time when it has\n * a real one, else the first real harness event (a candidate created, an\n * experiment started, an adoption, a rollback), else — nothing but the\n * defaults on record — `HARNESS_BASELINE_WINDOW_MS` before `now`.\n */\nfunction baselineStart(learning: LearningStateV1, baseline: HarnessVersion, now: number): number {\n const own = harnessTime(baseline.createdAt);\n if (own !== null) return own;\n const times = [\n ...learning.versions.filter((v) => v.id !== baseline.id).flatMap((v) => [v.createdAt, v.adoptedAt, v.rolledBackAt]),\n ...learning.experiments.flatMap((e) => [e.startedAt, e.finishedAt]),\n ]\n .map(harnessTime)\n .filter((t): t is number => t !== null);\n return times.length > 0 ? Math.min(...times) : now - HARNESS_BASELINE_WINDOW_MS;\n}\n\n/**\n * The level of the ACTIVE harness over time, in points of paired pass-rate\n * lift over the compiled defaults. Each adoption adds its own experiment's\n * lift to the level of the version it was measured against; its band is that\n * experiment's 95% interval (the step's own uncertainty, not a compounded\n * one — the caption says so). A rollback returns to the parent's level.\n *\n * Every step and marker carries a REAL timestamp (`harnessTime`): an event\n * without one is left out rather than drawn at the epoch. `now` (default: the\n * state's own `generatedAt`) only anchors the defaults-only window.\n */\nexport function harnessSteps(learning: LearningStateV1 | null, now?: number): HarnessSeries {\n if (!learning || learning.versions.length === 0) return { steps: [], markers: [] };\n const byId = new Map(learning.versions.map((v) => [v.id, v]));\n const exps = new Map(learning.experiments.map((e) => [e.id, e]));\n const level = new Map<string, number | null>();\n const events: { at: number; step?: StepPoint; marker?: StepMarker }[] = [];\n\n const baseline = [...learning.versions].sort((a, b) => a.seq - b.seq)[0]!;\n level.set(baseline.id, 0);\n const t0 = baselineStart(learning, baseline, now ?? harnessTime(learning.generatedAt) ?? Date.now());\n events.push({ at: t0, step: { id: `${baseline.id}@base`, at: t0, value: 0, low: 0, high: 0, label: baseline.status === 'baseline' ? 'Compiled defaults' : baseline.id, detail: 'baseline' } });\n\n const adopted = learning.versions\n .filter((v) => v.adoptedAt && v.id !== baseline.id)\n .sort((a, b) => Date.parse(a.adoptedAt!) - Date.parse(b.adoptedAt!));\n for (const v of adopted) {\n const exp: ExperimentResultV1 | undefined = v.experimentId ? exps.get(v.experimentId) : undefined;\n const baseId = exp?.baseVersionId ?? v.parentId ?? baseline.id;\n const baseLevel = level.get(baseId) ?? (byId.has(baseId) ? null : 0);\n const lift = exp?.lift ?? null;\n const value = lift && baseLevel !== null && baseLevel !== undefined ? baseLevel + lift.mean : null;\n level.set(v.id, value);\n const at = harnessTime(v.adoptedAt);\n if (at === null) continue;\n const detail = v.status === 'canary' ? 'canary' : v.status === 'rolled-back' ? 'adopted, later rolled back' : 'adopted';\n events.push({\n at,\n step: {\n id: `${v.id}@adopt`,\n at,\n value,\n low: value !== null && lift ? baseLevel! + lift.ciLow : null,\n high: value !== null && lift ? baseLevel! + lift.ciHigh : null,\n label: v.id,\n detail,\n },\n });\n if (v.rolledBackAt) {\n const back = harnessTime(v.rolledBackAt);\n if (back !== null) {\n const parentLevel = level.get(baseId) ?? null;\n const parent = byId.get(baseId);\n events.push({ at: back, marker: { id: `${v.id}@rb`, at: back, kind: 'rollback', label: `${v.id}: ${v.rollbackReason ?? 'rolled back'}` } });\n events.push({ at: back + 1, step: { id: `${v.id}@rb-step`, at: back + 1, value: parentLevel, low: null, high: null, label: parent?.id ?? baseId, detail: `restored after ${v.id} rolled back` } });\n }\n }\n }\n events.sort((a, b) => a.at - b.at);\n return {\n steps: events.flatMap((e) => (e.step ? [e.step] : [])),\n markers: events.flatMap((e) => (e.marker ? [e.marker] : [])),\n };\n}\n\nconst VERDICT_WORD: Record<string, string> = { adopt: 'passed the gate', reject: 'rejected', inconclusive: 'inconclusive' };\n\nexport function forestRows(learning: LearningStateV1 | null): ForestRow[] {\n if (!learning) return [];\n return learning.experiments.map((e) => ({\n id: e.id,\n label: `${e.candidateVersionId} vs ${e.baseVersionId}`,\n estimate: e.lift?.mean ?? null,\n low: e.lift?.ciLow ?? null,\n high: e.lift?.ciHigh ?? null,\n n: e.pairs,\n detail:\n e.status === 'running' || e.status === 'queued'\n ? `${e.status} · ${e.pairs}/${HARNESS_ADOPTION_GATE.minPairs} pairs`\n : e.verdict\n ? VERDICT_WORD[e.verdict] ?? e.verdict\n : e.status,\n }));\n}\n","/**\n * routes/verse/sections/GrowthSection.tsx — ⌘3 Growth: is the output\n * compounding? (SPEC-310B §6, SPEC-310C §5; unit C7)\n *\n * Merges / week (8) | Cost per merge (4)\n * Pipeline funnel (4) | Model outcomes (4) | Merges by day (4)\n * Harness level with 95% band + ▼ rollbacks (8) | Experiments forest plot (4)\n *\n * Sources: fleet history (A8), per-model economics (/api/models), learning\n * (B-U9). Each can be missing on its own; its cards say so. History and\n * learning change daily, so the surface refreshes every 5 minutes while\n * visible — never faster.\n *\n * Dormant fleet: when autonomy is off (or on but quiet) the shared\n * AutonomyOffState leads the grid. When history is also quiet (nothing\n * produced for 48 h), every history card would repeat the same \"since\" date,\n * so those five are left out, and the learning / model cards stay only if\n * they have something real to draw — one clear state instead of six\n * identical empty cards.\n */\nimport { useMemo } from 'react';\nimport { AreaTrend } from '../../../components/charts/AreaTrend.js';\nimport { BarStack } from '../../../components/charts/BarStack.js';\nimport { CalendarHeatmap } from '../../../components/charts/CalendarHeatmap.js';\nimport type { ChartStatus } from '../../../components/charts/ChartFrame.js';\nimport { CHART_SEQUENTIAL } from '../../../components/charts/colors.js';\nimport { ForestPlot } from '../../../components/charts/ForestPlot.js';\nimport { Funnel } from '../../../components/charts/Funnel.js';\nimport { StepBand } from '../../../components/charts/StepBand.js';\nimport { dailyValues, historyStatus, pipelineFunnel, sourceCaveat } from '../../../components/charts/fleet-history-view.js';\nimport { formatTimeLabel, formatUsd } from '../../../components/charts/format.js';\nimport { RefreshIndicator } from '../../../components/primitives/RefreshIndicator.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { AutonomyOffState, useAutonomyOff } from '../autonomy/AutonomyOffState.js';\nimport { modelsQuery } from '../../../data/queries.js';\nimport { useNow } from '../autonomy/use-ticker.js';\nimport { Cell, Surface } from '../command/Surface.js';\nimport { fleetHistoryQuery, learningQuery } from '../command/surface-data.js';\nimport { quietSinceStatus } from '../fleet/dark-since.js';\nimport { usePollWhileVisible } from '../shell/section-visibility.js';\nimport { OUTCOME_SEGMENTS, costPerMerge, forestRows, harnessSteps, modelOutcomes, weeklyBins } from '../growth/growth-model.js';\nimport { HARNESS_ADOPTION_GATE } from '../../../../core/learn/harness-types.js';\n\nexport const GROWTH_POLL_MS = 300_000;\n\nconst models30 = modelsQuery('30d');\n\nfunction unknownFrom(reason: string | null | undefined, fallback: string): ChartStatus {\n return { kind: 'unknown', reason: reason ?? fallback };\n}\n\nexport function GrowthSection() {\n const history = useQuery(fleetHistoryQuery, { freshMs: 60_000 });\n const learning = useQuery(learningQuery, { freshMs: 60_000 });\n const models = useQuery(models30, { freshMs: 60_000 });\n const refetchHistory = useRefetch(fleetHistoryQuery);\n const refetchLearning = useRefetch(learningQuery);\n const refetchModels = useRefetch(models30);\n usePollWhileVisible(() => {\n refetchHistory();\n refetchLearning();\n refetchModels();\n }, GROWTH_POLL_MS);\n const now = useNow(60_000);\n\n const hist = history.data?.value ?? null;\n const learn = learning.data?.value ?? null;\n\n const bins = useMemo(() => (hist ? weeklyBins(hist.days) : []), [hist]);\n const histStatus: ChartStatus = !history.data ? { kind: 'loading' } : !hist ? unknownFrom(history.data.reason, 'fleet history did not answer.') : quietSinceStatus(historyStatus(hist, hist.sources.runs));\n const weeklyStatus: ChartStatus = histStatus.kind !== 'ready' ? histStatus : bins.length === 0 ? { kind: 'empty', message: 'Less than a week of history.' } : { kind: 'ready' };\n const mergesCaveat = hist ? sourceCaveat('Merge counts', hist.sources.decisions) : undefined;\n const funnel = hist ? pipelineFunnel(hist) : null;\n\n const outcomes = useMemo(() => modelOutcomes(models.data?.models ?? []), [models.data]);\n const modelStatus: ChartStatus = models.status === 'loading'\n ? { kind: 'loading' }\n : models.status === 'error' || !models.data\n ? { kind: 'unknown', reason: 'per-model economics could not be read.' }\n : outcomes.categories.length === 0\n ? { kind: 'empty', message: 'No fleet dispatches in 30 days.' }\n : { kind: 'ready' };\n\n const harness = useMemo(() => harnessSteps(learn), [learn]);\n const forest = useMemo(() => forestRows(learn), [learn]);\n const learnStatus = (emptyMessage: string, hasData: boolean): ChartStatus =>\n !learning.data ? { kind: 'loading' } : !learn ? unknownFrom(learning.data.reason, 'self-improvement did not answer.') : hasData ? { kind: 'ready' } : { kind: 'empty', message: emptyMessage };\n\n // History's \"quiet since\" (48 h without a run or proposal). The shared\n // state decides what is off and why; undefined until its reads answer.\n const quietSince = hist?.darkSince ?? null;\n const off = useAutonomyOff(quietSince);\n // Collapse only once the state can explain it — never six blank cells.\n const dormant = quietSince !== null && off != null;\n // A defaults-only harness is a flat line at 0: nothing to show while dormant.\n const harnessMoved = harness.steps.length > 1 || harness.markers.length > 0;\n const keepModels = !dormant || modelStatus.kind === 'ready';\n const keepHarness = !dormant || harnessMoved;\n const keepExperiments = !dormant || forest.length > 0;\n // Nothing left to draw: the state is the whole surface, and says so first.\n const onlyState = dormant && modelStatus.kind !== 'ready' && !harnessMoved && forest.length === 0;\n\n // A week bin sits at its last day's LOCAL midnight (growth-model\n // `weeklyBins`), so this label and the chart's own fallback rung (the\n // local `formatTimeLabel`) name the same calendar day in every zone.\n const weekLabel = (ms: number) => `wk to ${formatTimeLabel(ms)}`;\n\n return (\n <Surface title=\"Growth\" actions={[history, learning].some((q) => q.status === 'refreshing') ? <RefreshIndicator /> : null}>\n {off ? (\n <Cell span={12}>\n <AutonomyOffState state={off} here=\"growth\" title={onlyState ? 'Growth starts with the first fleet run.' : undefined} />\n </Cell>\n ) : null}\n {dormant ? null : (\n <Cell span={8}>\n <AreaTrend\n title=\"Merges per week\"\n description=\"Rolling 7-day windows ending today\"\n caveat={mergesCaveat}\n status={weeklyStatus}\n series={[{ id: 'merges', label: 'Merges', color: CHART_SEQUENTIAL, points: bins.map((b) => ({ x: b.end, y: b.merges })) }]}\n formatX={weekLabel}\n />\n </Cell>\n )}\n {dormant ? null : (\n <Cell span={4}>\n <AreaTrend\n title=\"Cost per merge\"\n description=\"Estimated run spend ÷ merges, per week\"\n status={weeklyStatus}\n series={[{ id: 'cpm', label: 'Cost per merge', color: CHART_SEQUENTIAL, points: bins.map((b) => ({ x: b.end, y: costPerMerge(b) })) }]}\n formatX={weekLabel}\n formatY={formatUsd}\n height={200}\n />\n </Cell>\n )}\n {dormant ? null : (\n <Cell span={4}>\n <Funnel\n title=\"Pipeline · 90d\"\n description=\"Filed → verified → passed → judged ship → merged\"\n caveat={funnel?.caveat}\n status={!funnel ? histStatus : quietSinceStatus(funnel.status)}\n stages={funnel?.stages ?? []}\n />\n </Cell>\n )}\n {keepModels ? (\n <Cell span={4}>\n <BarStack\n title=\"Model outcomes · 30d\"\n description=\"What each model's dispatches became\"\n status={modelStatus}\n categories={outcomes.categories}\n segments={OUTCOME_SEGMENTS}\n values={outcomes.values}\n height={200}\n />\n </Cell>\n ) : null}\n {dormant ? null : (\n <Cell span={4}>\n <CalendarHeatmap\n title=\"Merges by day\"\n description=\"Last 90 days\"\n status={histStatus}\n days={hist ? dailyValues(hist, (d) => d.merges.realized) : []}\n unit=\"merges\"\n />\n </Cell>\n )}\n {keepHarness ? (\n <Cell span={8}>\n {/* The rules live in the tooltip; the card says what it plots. */}\n <div title={`Band = each step's own 95% interval. A new harness runs as a canary for ${HARNESS_ADOPTION_GATE.canaryHours} h first.`}>\n <StepBand\n title=\"Harness level\"\n description=\"Pass-rate lift vs defaults\"\n status={learnStatus('Compiled defaults in force.', harness.steps.length > 0)}\n steps={harness.steps}\n markers={harness.markers}\n now={now}\n baseline={{ value: 0, label: 'Compiled defaults' }}\n unit=\"pts\"\n />\n </div>\n </Cell>\n ) : null}\n {keepExperiments ? (\n <Cell span={4}>\n <div title={`Adopted only when the interval's low end is above ${HARNESS_ADOPTION_GATE.minLiftCiLow}, over at least ${HARNESS_ADOPTION_GATE.minPairs} pairs.`}>\n <ForestPlot\n title=\"Experiments\"\n description=\"Paired lift, 95% interval\"\n status={learnStatus('No experiments yet.', forest.length > 0)}\n rows={forest}\n unit=\"pts\"\n unknownText={`under ${HARNESS_ADOPTION_GATE.minPairs} pairs`}\n />\n </div>\n </Cell>\n ) : null}\n </Surface>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"GrowthSection-P9EUfGeA.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/fleet-history-view.ts","../../../../../../src/core/learn/harness-types.ts","../../../../../../src/web-ui/routes/verse/growth/growth-model.ts","../../../../../../src/web-ui/routes/verse/sections/GrowthSection.tsx"],"sourcesContent":["/**\n * components/charts/fleet-history-view.ts — maps the `GET /api/verse/fleet/history`\n * payload (core/verse/fleet-history-types.ts) onto the chart kit's props, so\n * every surface that charts fleet history (Command, Fleet, Growth) makes the\n * same honesty decisions:\n *\n * - the fleet is DARK → every chart shows \"Fleet dark since <date>\", not\n * empty axes;\n * - a source could not be read at all → \"unknown\", not zeros;\n * - a source was only partly read → a caveat naming why (lower bounds);\n * - claim-check → always the not-recorded state, never a fabricated series.\n *\n * Pure functions over the wire type; no fetching here.\n */\nimport type {\n FleetHistoryDay,\n FleetHistoryResponse,\n FleetHistorySource,\n} from '../../../core/verse/fleet-history-types.js';\nimport type { ChartStatus } from './ChartFrame.js';\nimport type { BarStackProps } from './BarStack.js';\nimport type { FunnelStage } from './Funnel.js';\nimport type { SwimlaneLane } from './Swimlane.js';\nimport type { CalendarDatum } from './CalendarHeatmap.js';\nimport type { AreaTrendSeries } from './AreaTrend.js';\nimport { toneColor } from './colors.js';\nimport { formatDayLabel } from './format.js';\n\nconst REASON_TEXT: Record<string, string> = {\n 'oversized-file': 'some records are over the size bound',\n 'invalid-file': 'some records are malformed',\n 'unsafe-file': 'some records were refused (symlink, shared or foreign-owned)',\n 'unsafe-directory': 'the store directory is not private',\n 'io-error': 'some records could not be read',\n 'file-limit': 'the store has more records than one read covers',\n 'invalid-row': 'some ledger rows are malformed',\n 'oversized-row': 'some ledger rows are over the size bound',\n 'duplicate-canonical-realized-merge-identity': 'two proposals claim the same merge, so merges are unknown',\n 'claim-integrity-verdicts-not-persisted': 'claim-check verdicts are not recorded per proposal yet',\n 'scorecard-trend-pending': 'the scorecard trend is still being collected',\n 'scorecard-worker-unavailable': 'the scorecard trend could not be read this time',\n};\n\nfunction reasonText(reason: string): string {\n return REASON_TEXT[reason] ?? reason.replace(/-/g, ' ');\n}\n\n/** A caveat sentence for a partly-read source, or undefined when it is complete. */\nexport function sourceCaveat(label: string, source: FleetHistorySource): string | undefined {\n if (source.complete || source.state === 'not-recorded') return undefined;\n if (source.reasons.length === 0) return undefined;\n const skipped = source.recordsSkipped > 0 ? ` (${source.recordsSkipped} skipped)` : '';\n return `${label} are lower bounds: ${source.reasons.map(reasonText).join('; ')}${skipped}.`;\n}\n\n/**\n * The shared status for a chart over one source. Order matters: unreadable\n * beats dark (we cannot claim darkness from a store we cannot read), and dark\n * beats an all-zero window (the designed \"since\" message is more useful).\n */\nexport function historyStatus(history: FleetHistoryResponse, source: FleetHistorySource): ChartStatus {\n if (source.state === 'not-recorded') return { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'not recorded')}.` };\n if (source.state === 'degraded' && source.recordsRead === 0) {\n return { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'io-error')}.` };\n }\n if (history.darkSince) return { kind: 'dark', since: history.darkSince };\n return { kind: 'ready' };\n}\n\n/** \"Sep 3\" for a day row (the wire's days are already in the caller's zone). */\nexport function dayLabel(day: FleetHistoryDay): string {\n return formatDayLabel(day.day);\n}\n\n/** Runs per day as done / failed / aborted / unfinished — status tones, legend-labelled. */\nexport function runsByDay(history: FleetHistoryResponse): Pick<BarStackProps, 'categories' | 'segments' | 'values' | 'status' | 'caveat'> {\n return {\n categories: history.days.map(dayLabel),\n segments: [\n { id: 'done', label: 'Done', color: toneColor('success') },\n { id: 'failed', label: 'Failed', color: toneColor('danger') },\n { id: 'aborted', label: 'Aborted', color: toneColor('neutral') },\n { id: 'unfinished', label: 'Unfinished', color: toneColor('running') },\n ],\n values: history.days.map((d) => [d.runs.done, d.runs.failed, d.runs.aborted, d.runs.unfinished]),\n status: historyStatus(history, history.sources.runs),\n caveat: sourceCaveat('Run counts', history.sources.runs),\n };\n}\n\n/** Judge verdicts per day (the considered ones, plus failed judge calls). */\nexport function verdictsByDay(history: FleetHistoryResponse): Pick<BarStackProps, 'categories' | 'segments' | 'values' | 'status' | 'caveat'> {\n return {\n categories: history.days.map(dayLabel),\n segments: [\n { id: 'ship', label: 'Ship', color: toneColor('success') },\n { id: 'review', label: 'Review', color: toneColor('warning') },\n { id: 'noise', label: 'Noise', color: toneColor('neutral') },\n { id: 'harmful', label: 'Harmful', color: toneColor('danger') },\n { id: 'failed', label: 'Judge failed', color: toneColor('unknown') },\n ],\n values: history.days.map((d) => [d.judged.ship, d.judged.review, d.judged.noise, d.judged.harmful, d.judged.failed]),\n status: historyStatus(history, history.sources.decisions),\n caveat: sourceCaveat('Verdict counts', history.sources.decisions),\n };\n}\n\n/** Proposal pipeline for the window (cumulative stages — see FleetHistoryFunnel). */\nexport function pipelineFunnel(history: FleetHistoryResponse): { stages: FunnelStage[]; status: ChartStatus; caveat?: string } {\n const f = history.funnel;\n const caveat = sourceCaveat('Pipeline counts', history.sources.proposals) ?? sourceCaveat('Pipeline counts', history.sources.decisions);\n return {\n stages: [\n { id: 'filed', label: 'Filed', value: f.filed },\n { id: 'verified', label: 'Verified', value: f.verified },\n { id: 'passed', label: 'Verification passed', value: f.verificationPassed },\n { id: 'ship', label: 'Judged ship', value: f.judgedShip },\n { id: 'merged', label: 'Merged', value: f.merged },\n ],\n status: historyStatus(history, history.sources.proposals),\n ...(caveat ? { caveat } : {}),\n };\n}\n\n/** Swimlane lanes straight from the projection (runs → bars, engine as detail). */\nexport function runLanes(history: FleetHistoryResponse): { lanes: SwimlaneLane[]; from: number; to: number; status: ChartStatus; caveat?: string } {\n const truncated = history.swimlanesTruncated ? 'Showing the newest runs only; the full list is longer.' : undefined;\n const caveat = [sourceCaveat('Runs', history.sources.runs), truncated].filter(Boolean).join(' ') || undefined;\n return {\n lanes: history.swimlanes.map((lane) => ({\n id: lane.id,\n label: lane.label,\n items: lane.items.map((item) => ({\n id: item.id,\n start: item.startMs,\n end: item.endMs,\n status: item.status,\n detail: item.engine,\n stale: item.stale,\n })),\n })),\n from: Date.parse(history.window.from),\n to: Date.parse(history.window.to),\n status: historyStatus(history, history.sources.runs),\n ...(caveat ? { caveat } : {}),\n };\n}\n\n/** One number per day for the calendar heatmap. */\nexport function dailyValues(history: FleetHistoryResponse, pick: (day: FleetHistoryDay) => number | null): CalendarDatum[] {\n return history.days.map((d) => ({ day: d.day, value: pick(d) }));\n}\n\n/** Scorecard trend (daily snapshots of the trailing window) as AreaTrend series. */\nexport function scorecardSeries(history: FleetHistoryResponse, window: '7d' | '30d' = '7d'): { series: AreaTrendSeries[]; status: ChartStatus; caveat?: string } {\n const points = window === '7d' ? history.scorecard.trend7d : history.scorecard.trend30d;\n const source = history.scorecard.source;\n const status: ChartStatus = points.length === 0\n ? source.state === 'degraded'\n ? { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'io-error')}.` }\n : { kind: 'empty', message: 'No scorecard snapshots yet — the first is taken today, then one a day.' }\n : { kind: 'ready' };\n const caveat = points.length > 0 ? sourceCaveat('Scorecard points', source) : undefined;\n return {\n series: [\n { id: 'merges', label: 'Merges', points: points.map((p) => ({ x: Date.parse(p.ts), y: p.merges.realized })) },\n { id: 'filed', label: 'Proposals filed', points: points.map((p) => ({ x: Date.parse(p.ts), y: p.proposalsFiled })) },\n ],\n status,\n ...(caveat ? { caveat } : {}),\n };\n}\n","/**\n * Harness registry + experiments — V3.10 Track B contract (unit B-U1, frozen day 0).\n *\n * A HARNESS is the config-only envelope around the fleet's models: prompt\n * overlays, effort, sampling, routing weights and enabled skills. The\n * self-improvement loop (unit U9) versions harnesses, A/B-tests a candidate\n * against the active version on free local slots (paired runs, 95% CI,\n * ≥ 8 pairs, held-out tasks), and adopts a winner only through the Leader's\n * class-B action, behind a 48 h canary with automatic rollback.\n *\n * WHY config-only: a harness can never carry code, so adopting one can never\n * change authority (SPEC-310B I2). Code self-improvement arrives as ordinary\n * fleet PRs that pass every merge gate and only run after Mason deploys them.\n *\n * Honesty rule: `null` = unknown / not measured, never zero.\n *\n * BROWSER-SAFE: the Growth surface imports this — type-only imports, plain consts.\n */\nimport type { RoutingDifficulty } from '../routing/types.js';\nimport type { FleetEngine } from '../fleet/fleet-types.js';\n\nexport const VERSE_LEARNING_PATH = '/api/verse/learning';\n\n// ---------------------------------------------------------------------------\n// Harness config (what a version pins)\n// ---------------------------------------------------------------------------\n\nexport type HarnessEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\n/** Roles a prompt overlay can target. */\nexport type HarnessRole = 'producer' | 'judge' | 'leader' | 'planner';\n\nexport interface HarnessSampling {\n /** null = the engine's own default. */\n temperature: number | null;\n topP: number | null;\n maxOutputTokens: number | null;\n}\n\n/**\n * The dispatch router's tunables. Precedence at dispatch (U5): a Leader\n * `router.tune` override (LeaderDirectivesV1) › the active harness › the\n * router's compiled defaults. All λ are ≥ 0.\n */\nexport interface HarnessRoutingWeights {\n lambdaCost: number;\n lambdaPressure: number;\n lambdaLatency: number;\n /** Best-of-N runs at and above this difficulty. */\n bonThreshold: RoutingDifficulty;\n}\n\nexport interface HarnessConfigV1 {\n v: 1;\n /** Text appended to a role's system prompt; absent role = no overlay. Scrubbed, ≤ 4 KB each. */\n prompts: Partial<Record<HarnessRole, string>>;\n /** Effort per fleet engine; absent = engine default. */\n effort: Partial<Record<FleetEngine, HarnessEffort>>;\n /** Sampling per fleet engine; absent = engine default. */\n sampling: Partial<Record<FleetEngine, HarnessSampling>>;\n routing: HarnessRoutingWeights;\n /** Enabled skill ids, sorted. */\n skills: string[];\n}\n\n/** A config change. Top-level fields present here REPLACE the base's field wholesale (no deep merge). */\nexport type HarnessConfigPatch = Partial<Omit<HarnessConfigV1, 'v'>>;\n\n// ---------------------------------------------------------------------------\n// Versions\n// ---------------------------------------------------------------------------\n\n/**\n * - `baseline` — version 0: the compiled defaults.\n * - `candidate` — under experiment.\n * - `canary` — adopted, inside its 48 h canary.\n * - `adopted` — canary passed; the active version.\n * - `rolled-back` — canary fell below baseline − 1 SE (or vetoed).\n * - `rejected` — failed the adoption gate.\n */\nexport type HarnessVersionStatus = 'baseline' | 'candidate' | 'canary' | 'adopted' | 'rolled-back' | 'rejected';\n\nexport interface HarnessVersion {\n v: 1;\n /** Stable id, e.g. `h-0007`. */\n id: string;\n /** Monotonic; baseline = 0. */\n seq: number;\n parentId: string | null;\n createdAt: string;\n status: HarnessVersionStatus;\n config: HarnessConfigV1;\n /** sha256 hex of the canonical config — what experiments and ledger rows bind to. */\n configDigest: string;\n source: { kind: 'baseline' | 'hypothesis' | 'manual'; hypothesisId: string | null };\n /** The experiment whose verdict justified adoption; null for baseline / manual. */\n experimentId: string | null;\n adoptedAt: string | null;\n /** End of the 48 h canary; null when not in canary. */\n canaryUntil: string | null;\n rolledBackAt: string | null;\n rollbackReason: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Hypotheses and experiments\n// ---------------------------------------------------------------------------\n\nexport type HarnessTarget = 'prompt' | 'effort' | 'sampling' | 'routing' | 'skill';\n\n/** A typed, testable claim about a config change (the Leader emits ≤ 3 per memo; A7 insights may too). */\nexport interface HarnessHypothesis {\n v: 1;\n id: string;\n source: { kind: 'leader' | 'insight' | 'manual'; ref: string | null };\n target: HarnessTarget;\n /** Config only — never code. */\n patch: HarnessConfigPatch;\n /** The claim in one sentence. Untrusted model text: scrubbed, rendered as text. */\n statement: string;\n /** Metric it should move, e.g. `local-eval.pass-rate`. */\n metric: string;\n /** Predicted change, in the metric's units. */\n predictedDelta: number;\n createdAt: string;\n}\n\nexport type ExperimentVerdict = 'adopt' | 'reject' | 'inconclusive';\n\nexport type ExperimentStatus = 'queued' | 'running' | 'done' | 'cancelled' | 'failed';\n\nexport interface ExperimentLift {\n /** Paired pass-rate lift of candidate over base, in percentage points. */\n mean: number;\n ciLow: number;\n ciHigh: number;\n level: 0.95;\n}\n\nexport interface ExperimentResultV1 {\n v: 1;\n id: string;\n hypothesisId: string | null;\n baseVersionId: string;\n candidateVersionId: string;\n /** The held-out task set the pairs were drawn from. */\n taskSet: { id: string; digest: string };\n status: ExperimentStatus;\n /** Complete pairs so far. */\n pairs: number;\n wins: number;\n losses: number;\n ties: number;\n /** null until pairs ≥ HARNESS_ADOPTION_GATE.minPairs. */\n lift: ExperimentLift | null;\n /** Any `refuse`-class task regressed (blocks adoption). null = not measured yet. */\n refuseRegression: boolean | null;\n /** candidate − base count of `claimed-change-none-made` failures; must be ≤ 0 to adopt. */\n claimedChangeNoneMadeDelta: number | null;\n /** Wall-time / cost change in percent; must be ≤ +20 to adopt. */\n costDeltaPct: number | null;\n /** null while running. */\n verdict: ExperimentVerdict | null;\n /** Specific sentences behind the verdict. */\n reasons: string[];\n startedAt: string | null;\n finishedAt: string | null;\n}\n\n/**\n * The adoption gate (SPEC-310B §5) — frozen numbers. Adoption is a Leader\n * class-B action and requires ALL of: pairs ≥ minPairs, lift.ciLow >\n * minLiftCiLow, no refuse regression, claimedChangeNoneMadeDelta ≤ 0, and\n * costDeltaPct ≤ maxCostIncreasePct.\n */\nexport const HARNESS_ADOPTION_GATE = Object.freeze({\n minPairs: 8,\n ciLevel: 0.95,\n minLiftCiLow: 0,\n maxCostIncreasePct: 20,\n canaryHours: 48,\n /** Roll back when the canary pass rate falls below baseline − this many standard errors. */\n rollbackStandardErrors: 1,\n /** local-eval/tasks-heldout.ts must hold at least this many tasks (20 of 22 current tasks are saturated). */\n minHeldOutTasks: 12,\n} as const);\n\n/** Ledger payload for harness:adopted / harness:rolled-back / harness:rejected. */\nexport interface HarnessTransition {\n versionId: string;\n /** The version active before; null when none. */\n fromVersionId: string | null;\n configDigest: string;\n experimentId: string | null;\n reason: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cross-unit request / result shapes (learn/{experiments,harness-registry}.ts)\n// ---------------------------------------------------------------------------\n\nexport type HarnessActor = 'mason' | 'leader' | 'daemon';\n\nexport interface StartExperimentRequest {\n hypothesis: HarnessHypothesis;\n requestedBy: HarnessActor;\n}\n\nexport type StartExperimentResult = { ok: true; experimentId: string } | { ok: false; reason: string };\n\nexport interface CancelExperimentRequest {\n experimentId: string;\n reason: string;\n actor: HarnessActor;\n}\n\n/** A finished experiment cannot be cancelled (ok: false). */\nexport type CancelExperimentResult = { ok: true } | { ok: false; reason: string };\n\nexport interface AdoptHarnessRequest {\n versionId: string;\n /** The experiment whose verdict passed the gate. */\n experimentId: string;\n actor: HarnessActor;\n}\n\nexport interface RollbackHarnessRequest {\n /** The version to make active again; null = back to the baseline defaults. */\n toVersionId: string | null;\n reason: string;\n actor: HarnessActor;\n}\n\n/** `before` is the version active before the call, so a veto can restore it exactly. */\nexport type HarnessChangeResult =\n | { ok: true; before: HarnessVersion | null; after: HarnessVersion | null }\n | { ok: false; reason: string };\n\n// ---------------------------------------------------------------------------\n// Learning API (U9) — GET /api/verse/learning\n// ---------------------------------------------------------------------------\n\nexport interface HarnessCanaryState {\n versionId: string;\n startedAt: string;\n until: string;\n baselinePassRate: number | null;\n baselineStandardError: number | null;\n currentPassRate: number | null;\n runs: number;\n}\n\nexport interface LearningStateV1 {\n v: 1;\n generatedAt: string;\n /** null = nothing adopted; the baseline defaults are in force. */\n active: HarnessVersion | null;\n canary: HarnessCanaryState | null;\n /** Oldest → newest (Growth step chart with CI band and rollback markers). */\n versions: HarnessVersion[];\n /** Newest first (ForestPlot). */\n experiments: ExperimentResultV1[];\n /** Open hypotheses not yet tested. */\n hypotheses: HarnessHypothesis[];\n}\n","/**\n * routes/verse/growth/growth-model.ts — \"is the output compounding?\" as pure\n * data (unit C7; SPEC-310B §6 Growth, SPEC-310C §5).\n *\n * weeklyBins rolling 7-day windows ENDING TODAY, so every point is a\n * complete week (a calendar week-to-date would dip every\n * Monday and read as a regression);\n * costPerMerge spend ÷ merges per window — undefined (null) for a week\n * with no merges, never $0 or ∞;\n * modelOutcomes what each model's dispatches became (ROI composition);\n * harnessSteps the active harness's level over time: each adoption\n * steps up by its experiment's lift, a rollback steps back\n * down with a ▼ marker; only real timestamps, never the\n * baseline's epoch stamp;\n * forestRows one row per experiment, newest first.\n *\n * Framework-free; tested directly.\n */\nimport type { FleetHistoryDay } from '../../../../core/verse/fleet-history-types.js';\nimport type { ExperimentResultV1, HarnessVersion, LearningStateV1 } from '../../../../core/learn/harness-types.js';\nimport { HARNESS_ADOPTION_GATE } from '../../../../core/learn/harness-types.js';\nimport type { ModelStats } from '../../../data/api-types.js';\nimport type { BarStackSegment } from '../../../components/charts/BarStack.js';\nimport { toneColor } from '../../../components/charts/colors.js';\nimport type { ForestRow } from '../../../components/charts/ForestPlot.js';\nimport type { StepMarker, StepPoint } from '../../../components/charts/StepBand.js';\nimport { calendarDayStart } from './calendar-day.js';\n\nexport interface WeekBin {\n /**\n * Epoch ms of the window's last day at the viewer's LOCAL midnight\n * (`calendarDayStart`), so every local time label names that day.\n */\n end: number;\n /** YYYY-MM-DD of the last day. */\n endDay: string;\n merges: number | null;\n costUsd: number | null;\n}\n\n/** Complete 7-day windows ending on the last day of `days`, oldest first. */\nexport function weeklyBins(days: readonly FleetHistoryDay[]): WeekBin[] {\n const bins: WeekBin[] = [];\n for (let end = days.length; end - 7 >= 0; end -= 7) {\n const week = days.slice(end - 7, end);\n const sum = (pick: (d: FleetHistoryDay) => number | null): number | null => {\n let total = 0;\n for (const d of week) {\n const v = pick(d);\n if (v === null || !Number.isFinite(v)) return null;\n total += v;\n }\n return total;\n };\n const lastDay = week[week.length - 1]!.day;\n bins.unshift({ end: calendarDayStart(lastDay), endDay: lastDay, merges: sum((d) => d.merges.realized), costUsd: sum((d) => d.estCostUsd) });\n }\n return bins;\n}\n\n/** Dollars per merge; null when either side is unknown or nothing merged. */\nexport function costPerMerge(bin: WeekBin): number | null {\n if (bin.merges === null || bin.costUsd === null || bin.merges === 0) return null;\n return bin.costUsd / bin.merges;\n}\n\n// ---------------------------------------------------------------------------\n// Model outcomes (ROI)\n// ---------------------------------------------------------------------------\n\nexport const OUTCOME_SEGMENTS: BarStackSegment[] = [\n { id: 'merged', label: 'Merged', color: toneColor('success') },\n { id: 'ship', label: 'Judged ship, not merged', color: toneColor('info') },\n { id: 'rejected', label: 'Judged not worth shipping', color: toneColor('warning') },\n { id: 'unjudged', label: 'Not judged', color: toneColor('neutral') },\n];\n\nexport interface ModelOutcomes {\n categories: string[];\n values: (number | null)[][];\n /** Per category, for the caption / table: dollars per merge. */\n costPerMerged: (number | null)[];\n models: ModelStats[];\n}\n\n/** The longest model name an axis category keeps before it is shortened. */\nexport const MODEL_LABEL_MAX = 18;\n\n/** A snapshot date at the end of a model id: `-20251001`, `-2025-10-01`, `@20251001`. */\nconst DATE_SUFFIX = /[-@](?:\\d{8}|\\d{4}-\\d{2}-\\d{2})$/;\n\n/**\n * `name` shortened to at most `max` characters by cutting at a word boundary\n * (a space, `-` or `:`) and closing with \"…\" — never mid-word\n * (`grok-4.7-fast-reasoning` → `grok-4.7-fast…`). A name with no boundary\n * early enough stays whole: a long label beats a broken word.\n */\nfunction cutAtBoundary(name: string, max = MODEL_LABEL_MAX): string {\n if (name.length <= max) return name;\n const head = name.slice(0, max);\n const at = Math.max(head.lastIndexOf(' '), head.lastIndexOf('-'), head.lastIndexOf(':'));\n return at > 0 ? `${name.slice(0, at)}…` : name;\n}\n\n/**\n * Each model's axis name, UNIQUE across the chart. A model reads as its id\n * without a vendor path or snapshot date (`claude-haiku-4-5`), shortened only\n * at a word boundary. Names that would read the same — two dated snapshots of\n * one model, two long ids sharing a prefix, one tag on two engines — step\n * down TOGETHER through the same fuller forms until they differ: the whole\n * name, the id with its date, the id with its vendor path, `engine:model`\n * (so `claude-haiku-4-5-20251001` and `claude-haiku-4-5` both keep plain\n * ids). An ordinal (\"#2\") is the last resort: two columns never share a label.\n */\nexport function modelLabels(models: readonly Pick<ModelStats, 'engine' | 'model'>[]): string[] {\n // One rung per form, the same rungs for every model (a form that adds\n // nothing for this model simply repeats), so a group steps in lockstep.\n const ladders = models.map((m) => {\n const id = m.model.includes('/') ? m.model.split('/').pop()! : m.model;\n const name = id.replace(DATE_SUFFIX, '') || id;\n return [cutAtBoundary(name), name, id, m.model, `${m.engine}:${m.model}`];\n });\n const level = models.map(() => 0);\n const current = () => ladders.map((l, i) => l[level[i]!]!);\n const rungs = ladders[0]?.length ?? 0;\n for (let rung = 1; rung < rungs; rung++) {\n const labels = current();\n const seen = new Map<string, number>();\n for (const l of labels) seen.set(l, (seen.get(l) ?? 0) + 1);\n const clashing = labels.map((l) => seen.get(l)! > 1);\n if (!clashing.includes(true)) break;\n clashing.forEach((clash, i) => {\n if (clash) level[i] = rung;\n });\n }\n const taken = new Set<string>();\n return current().map((l) => {\n let label = l;\n for (let n = 2; taken.has(label); n++) label = `${l} #${n}`;\n taken.add(label);\n return label;\n });\n}\n\n/** Top `limit` models by dispatches, each split into what its dispatches became. */\nexport function modelOutcomes(models: readonly ModelStats[], limit = 6): ModelOutcomes {\n const top = [...models].filter((m) => m.dispatches > 0).sort((a, b) => b.dispatches - a.dispatches).slice(0, limit);\n return {\n categories: modelLabels(top),\n values: top.map((m) => {\n const merged = Math.max(0, m.merged);\n const ship = Math.max(0, m.shipVerdicts - merged);\n const rejected = Math.max(0, m.judged - m.shipVerdicts);\n const unjudged = Math.max(0, m.dispatches - m.judged);\n return [merged, ship, rejected, unjudged];\n }),\n costPerMerged: top.map((m) => m.costPerMergedUsd),\n models: top,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Harness steps + experiments\n// ---------------------------------------------------------------------------\n\nexport interface HarnessSeries {\n steps: StepPoint[];\n markers: StepMarker[];\n}\n\n/**\n * Anything stamped before this is not a real harness event. The registry\n * stamps the compiled-defaults baseline `1970-01-01T00:00:00.000Z` (it has no\n * creation time — core/learn/harness-registry.ts `baselineVersion`), and a\n * step drawn there stretched the x-axis from \"Dec 31\" to today. No Ashlr\n * harness predates 2020, so the floor also catches any other zero-ish stamp.\n */\nexport const HARNESS_TIME_FLOOR_MS = Date.UTC(2020, 0, 1);\n\n/** With nothing but the compiled defaults on record, the chart shows this trailing window. */\nexport const HARNESS_BASELINE_WINDOW_MS = 90 * 86_400_000;\n\n/** Epoch ms of a real harness timestamp; null for missing, unparsable or pre-floor (epoch) stamps. */\nexport function harnessTime(iso: string | null | undefined): number | null {\n if (!iso) return null;\n const t = Date.parse(iso);\n return Number.isFinite(t) && t >= HARNESS_TIME_FLOOR_MS ? t : null;\n}\n\n/**\n * When the compiled-defaults step starts: the baseline's own time when it has\n * a real one, else the first real harness event (a candidate created, an\n * experiment started, an adoption, a rollback), else — nothing but the\n * defaults on record — `HARNESS_BASELINE_WINDOW_MS` before `now`.\n */\nfunction baselineStart(learning: LearningStateV1, baseline: HarnessVersion, now: number): number {\n const own = harnessTime(baseline.createdAt);\n if (own !== null) return own;\n const times = [\n ...learning.versions.filter((v) => v.id !== baseline.id).flatMap((v) => [v.createdAt, v.adoptedAt, v.rolledBackAt]),\n ...learning.experiments.flatMap((e) => [e.startedAt, e.finishedAt]),\n ]\n .map(harnessTime)\n .filter((t): t is number => t !== null);\n return times.length > 0 ? Math.min(...times) : now - HARNESS_BASELINE_WINDOW_MS;\n}\n\n/**\n * The level of the ACTIVE harness over time, in points of paired pass-rate\n * lift over the compiled defaults. Each adoption adds its own experiment's\n * lift to the level of the version it was measured against; its band is that\n * experiment's 95% interval (the step's own uncertainty, not a compounded\n * one — the caption says so). A rollback returns to the parent's level.\n *\n * Every step and marker carries a REAL timestamp (`harnessTime`): an event\n * without one is left out rather than drawn at the epoch. `now` (default: the\n * state's own `generatedAt`) only anchors the defaults-only window.\n */\nexport function harnessSteps(learning: LearningStateV1 | null, now?: number): HarnessSeries {\n if (!learning || learning.versions.length === 0) return { steps: [], markers: [] };\n const byId = new Map(learning.versions.map((v) => [v.id, v]));\n const exps = new Map(learning.experiments.map((e) => [e.id, e]));\n const level = new Map<string, number | null>();\n const events: { at: number; step?: StepPoint; marker?: StepMarker }[] = [];\n\n const baseline = [...learning.versions].sort((a, b) => a.seq - b.seq)[0]!;\n level.set(baseline.id, 0);\n const t0 = baselineStart(learning, baseline, now ?? harnessTime(learning.generatedAt) ?? Date.now());\n events.push({ at: t0, step: { id: `${baseline.id}@base`, at: t0, value: 0, low: 0, high: 0, label: baseline.status === 'baseline' ? 'Compiled defaults' : baseline.id, detail: 'baseline' } });\n\n const adopted = learning.versions\n .filter((v) => v.adoptedAt && v.id !== baseline.id)\n .sort((a, b) => Date.parse(a.adoptedAt!) - Date.parse(b.adoptedAt!));\n for (const v of adopted) {\n const exp: ExperimentResultV1 | undefined = v.experimentId ? exps.get(v.experimentId) : undefined;\n const baseId = exp?.baseVersionId ?? v.parentId ?? baseline.id;\n const baseLevel = level.get(baseId) ?? (byId.has(baseId) ? null : 0);\n const lift = exp?.lift ?? null;\n const value = lift && baseLevel !== null && baseLevel !== undefined ? baseLevel + lift.mean : null;\n level.set(v.id, value);\n const at = harnessTime(v.adoptedAt);\n if (at === null) continue;\n const detail = v.status === 'canary' ? 'canary' : v.status === 'rolled-back' ? 'adopted, later rolled back' : 'adopted';\n events.push({\n at,\n step: {\n id: `${v.id}@adopt`,\n at,\n value,\n low: value !== null && lift ? baseLevel! + lift.ciLow : null,\n high: value !== null && lift ? baseLevel! + lift.ciHigh : null,\n label: v.id,\n detail,\n },\n });\n if (v.rolledBackAt) {\n const back = harnessTime(v.rolledBackAt);\n if (back !== null) {\n const parentLevel = level.get(baseId) ?? null;\n const parent = byId.get(baseId);\n events.push({ at: back, marker: { id: `${v.id}@rb`, at: back, kind: 'rollback', label: `${v.id}: ${v.rollbackReason ?? 'rolled back'}` } });\n events.push({ at: back + 1, step: { id: `${v.id}@rb-step`, at: back + 1, value: parentLevel, low: null, high: null, label: parent?.id ?? baseId, detail: `restored after ${v.id} rolled back` } });\n }\n }\n }\n events.sort((a, b) => a.at - b.at);\n return {\n steps: events.flatMap((e) => (e.step ? [e.step] : [])),\n markers: events.flatMap((e) => (e.marker ? [e.marker] : [])),\n };\n}\n\nconst VERDICT_WORD: Record<string, string> = { adopt: 'passed the gate', reject: 'rejected', inconclusive: 'inconclusive' };\n\nexport function forestRows(learning: LearningStateV1 | null): ForestRow[] {\n if (!learning) return [];\n return learning.experiments.map((e) => ({\n id: e.id,\n label: `${e.candidateVersionId} vs ${e.baseVersionId}`,\n estimate: e.lift?.mean ?? null,\n low: e.lift?.ciLow ?? null,\n high: e.lift?.ciHigh ?? null,\n n: e.pairs,\n detail:\n e.status === 'running' || e.status === 'queued'\n ? `${e.status} · ${e.pairs}/${HARNESS_ADOPTION_GATE.minPairs} pairs`\n : e.verdict\n ? VERDICT_WORD[e.verdict] ?? e.verdict\n : e.status,\n }));\n}\n","/**\n * routes/verse/sections/GrowthSection.tsx — ⌘3 Growth: is the output\n * compounding? (SPEC-310B §6, SPEC-310C §5; unit C7)\n *\n * Merges / week (8) | Cost per merge (4)\n * Pipeline funnel (4) | Model outcomes (4) | Merges by day (4)\n * Harness level with 95% band + ▼ rollbacks (8) | Experiments forest plot (4)\n *\n * Sources: fleet history (A8), per-model economics (/api/models), learning\n * (B-U9). Each can be missing on its own; its cards say so. History and\n * learning change daily, so the surface refreshes every 5 minutes while\n * visible — never faster.\n *\n * Dormant fleet: when autonomy is off (or on but quiet) the shared\n * AutonomyOffState leads the grid. When history is also quiet (nothing\n * produced for 48 h), every history card would repeat the same \"since\" date,\n * so those five are left out, and the learning / model cards stay only if\n * they have something real to draw — one clear state instead of six\n * identical empty cards.\n */\nimport { useMemo } from 'react';\nimport { AreaTrend } from '../../../components/charts/AreaTrend.js';\nimport { BarStack } from '../../../components/charts/BarStack.js';\nimport { CalendarHeatmap } from '../../../components/charts/CalendarHeatmap.js';\nimport type { ChartStatus } from '../../../components/charts/ChartFrame.js';\nimport { CHART_SEQUENTIAL } from '../../../components/charts/colors.js';\nimport { ForestPlot } from '../../../components/charts/ForestPlot.js';\nimport { Funnel } from '../../../components/charts/Funnel.js';\nimport { StepBand } from '../../../components/charts/StepBand.js';\nimport { dailyValues, historyStatus, pipelineFunnel, sourceCaveat } from '../../../components/charts/fleet-history-view.js';\nimport { formatTimeLabel, formatUsd } from '../../../components/charts/format.js';\nimport { RefreshIndicator } from '../../../components/primitives/RefreshIndicator.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { AutonomyOffState, useAutonomyOff } from '../autonomy/AutonomyOffState.js';\nimport { modelsQuery } from '../../../data/queries.js';\nimport { useNow } from '../autonomy/use-ticker.js';\nimport { Cell, Surface } from '../command/Surface.js';\nimport { fleetHistoryQuery, learningQuery } from '../command/surface-data.js';\nimport { quietSinceStatus } from '../fleet/dark-since.js';\nimport { usePollWhileVisible } from '../shell/section-visibility.js';\nimport { OUTCOME_SEGMENTS, costPerMerge, forestRows, harnessSteps, modelOutcomes, weeklyBins } from '../growth/growth-model.js';\nimport { HARNESS_ADOPTION_GATE } from '../../../../core/learn/harness-types.js';\n\nexport const GROWTH_POLL_MS = 300_000;\n\nconst models30 = modelsQuery('30d');\n\n/** One series of weekly merge counts: the quantity ink, no legend needed. */\nconst MERGE_SEGMENTS = [{ id: 'merges', label: 'Merges', color: CHART_SEQUENTIAL }];\n\nfunction unknownFrom(reason: string | null | undefined, fallback: string): ChartStatus {\n return { kind: 'unknown', reason: reason ?? fallback };\n}\n\nexport function GrowthSection() {\n const history = useQuery(fleetHistoryQuery, { freshMs: 60_000 });\n const learning = useQuery(learningQuery, { freshMs: 60_000 });\n const models = useQuery(models30, { freshMs: 60_000 });\n const refetchHistory = useRefetch(fleetHistoryQuery);\n const refetchLearning = useRefetch(learningQuery);\n const refetchModels = useRefetch(models30);\n usePollWhileVisible(() => {\n refetchHistory();\n refetchLearning();\n refetchModels();\n }, GROWTH_POLL_MS);\n const now = useNow(60_000);\n\n const hist = history.data?.value ?? null;\n const learn = learning.data?.value ?? null;\n\n const bins = useMemo(() => (hist ? weeklyBins(hist.days) : []), [hist]);\n const histStatus: ChartStatus = !history.data ? { kind: 'loading' } : !hist ? unknownFrom(history.data.reason, 'fleet history did not answer.') : quietSinceStatus(historyStatus(hist, hist.sources.runs));\n const weeklyStatus: ChartStatus = histStatus.kind !== 'ready' ? histStatus : bins.length === 0 ? { kind: 'empty', message: 'Less than a week of history.' } : { kind: 'ready' };\n const mergesCaveat = hist ? sourceCaveat('Merge counts', hist.sources.decisions) : undefined;\n const funnel = hist ? pipelineFunnel(hist) : null;\n\n const outcomes = useMemo(() => modelOutcomes(models.data?.models ?? []), [models.data]);\n const modelStatus: ChartStatus = models.status === 'loading'\n ? { kind: 'loading' }\n : models.status === 'error' || !models.data\n ? { kind: 'unknown', reason: 'per-model economics could not be read.' }\n : outcomes.categories.length === 0\n ? { kind: 'empty', message: 'No fleet dispatches in 30 days.' }\n : { kind: 'ready' };\n\n const harness = useMemo(() => harnessSteps(learn), [learn]);\n const forest = useMemo(() => forestRows(learn), [learn]);\n const learnStatus = (emptyMessage: string, hasData: boolean): ChartStatus =>\n !learning.data ? { kind: 'loading' } : !learn ? unknownFrom(learning.data.reason, 'self-improvement did not answer.') : hasData ? { kind: 'ready' } : { kind: 'empty', message: emptyMessage };\n\n // History's \"quiet since\" (48 h without a run or proposal). The shared\n // state decides what is off and why; undefined until its reads answer.\n const quietSince = hist?.darkSince ?? null;\n const off = useAutonomyOff(quietSince);\n // Collapse only once the state can explain it — never six blank cells.\n const dormant = quietSince !== null && off != null;\n // A defaults-only harness is a flat line at 0: nothing to show while dormant.\n const harnessMoved = harness.steps.length > 1 || harness.markers.length > 0;\n const keepModels = !dormant || modelStatus.kind === 'ready';\n const keepHarness = !dormant || harnessMoved;\n const keepExperiments = !dormant || forest.length > 0;\n // Nothing left to draw: the state is the whole surface, and says so first.\n const onlyState = dormant && modelStatus.kind !== 'ready' && !harnessMoved && forest.length === 0;\n\n // A week bin sits at its last day's LOCAL midnight (growth-model\n // `weeklyBins`), so this label and the chart's own fallback rung (the\n // local `formatTimeLabel`) name the same calendar day in every zone.\n const weekLabel = (ms: number) => `wk to ${formatTimeLabel(ms)}`;\n\n return (\n <Surface title=\"Growth\" actions={[history, learning].some((q) => q.status === 'refreshing') ? <RefreshIndicator /> : null}>\n {off ? (\n <Cell span={12}>\n <AutonomyOffState state={off} here=\"growth\" title={onlyState ? 'Growth starts with the first fleet run.' : undefined} />\n </Cell>\n ) : null}\n {dormant ? null : (\n <Cell span={8}>\n {/* Columns, not an area: each week is a separate count, and a\n line between two weekly totals would draw merges that happened\n on no particular day. An unknown week is the kit's hatch. */}\n <BarStack\n title=\"Merges per week\"\n description=\"Rolling 7-day windows ending today\"\n caveat={mergesCaveat}\n status={weeklyStatus}\n categories={bins.map((b) => weekLabel(b.end))}\n segments={MERGE_SEGMENTS}\n values={bins.map((b) => [b.merges])}\n height={200}\n />\n </Cell>\n )}\n {dormant ? null : (\n <Cell span={4}>\n <AreaTrend\n title=\"Cost per merge\"\n description=\"Estimated run spend ÷ merges, per week\"\n status={weeklyStatus}\n series={[{ id: 'cpm', label: 'Cost per merge', color: CHART_SEQUENTIAL, points: bins.map((b) => ({ x: b.end, y: costPerMerge(b) })) }]}\n formatX={weekLabel}\n formatY={formatUsd}\n height={200}\n />\n </Cell>\n )}\n {dormant ? null : (\n <Cell span={4}>\n <Funnel\n title=\"Pipeline · 90d\"\n description=\"Filed → verified → passed → judged ship → merged\"\n caveat={funnel?.caveat}\n status={!funnel ? histStatus : quietSinceStatus(funnel.status)}\n stages={funnel?.stages ?? []}\n />\n </Cell>\n )}\n {keepModels ? (\n <Cell span={4}>\n <BarStack\n title=\"Model outcomes · 30d\"\n description=\"What each model's dispatches became\"\n status={modelStatus}\n categories={outcomes.categories}\n segments={OUTCOME_SEGMENTS}\n values={outcomes.values}\n height={200}\n />\n </Cell>\n ) : null}\n {dormant ? null : (\n <Cell span={4}>\n <CalendarHeatmap\n title=\"Merges by day\"\n description=\"Last 90 days\"\n status={histStatus}\n days={hist ? dailyValues(hist, (d) => d.merges.realized) : []}\n unit=\"merges\"\n />\n </Cell>\n )}\n {keepHarness ? (\n <Cell span={8}>\n {/* The rules live in the tooltip; the card says what it plots. */}\n <div title={`Band = each step's own 95% interval. A new harness runs as a canary for ${HARNESS_ADOPTION_GATE.canaryHours} h first.`}>\n <StepBand\n title=\"Harness level\"\n description=\"Pass-rate lift vs defaults\"\n status={learnStatus('Compiled defaults in force.', harness.steps.length > 0)}\n steps={harness.steps}\n markers={harness.markers}\n now={now}\n baseline={{ value: 0, label: 'Compiled defaults' }}\n unit=\"pts\"\n />\n </div>\n </Cell>\n ) : null}\n {keepExperiments ? (\n <Cell span={4}>\n <div title={`Adopted only when the interval's low end is above ${HARNESS_ADOPTION_GATE.minLiftCiLow}, over at least ${HARNESS_ADOPTION_GATE.minPairs} pairs.`}>\n <ForestPlot\n title=\"Experiments\"\n description=\"Paired lift, 95% interval\"\n status={learnStatus('No experiments yet.', forest.length > 0)}\n rows={forest}\n unit=\"pts\"\n unknownText={`under ${HARNESS_ADOPTION_GATE.minPairs} pairs`}\n />\n </div>\n </Cell>\n ) : null}\n </Surface>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{a as e,c as t,n}from"./index-CyK31YRm.js";import{k as r,m as i}from"./global-y_exIyAP.js";import{t as a}from"./Dialog-BRd_B9OE.js";import{t as ee}from"./MutationTokenDialog-Bm34BNVV.js";import{a as te,h as ne,it as re,u as ie}from"./VerseConsoleApp-DXDv1aOi.js";import{n as ae,v as o}from"./verse-model-JTuvRBVK.js";import{t as oe}from"./Segmented-Wt1ATod9.js";import{a as s,l as c,p as se,s as ce,u as l}from"./verse-store-DNVRuiJL.js";import{t as le,y as ue}from"./format-BmH2yWL6.js";import{l as de,r as fe,t as pe}from"./context-queries-_9bFWb9v.js";import{o as me,s as he}from"./context-model-CDeyP0cA.js";import{t as ge}from"./SeatSelector-DpwNiX8F.js";import{C as _e,D as ve,E as u,S as ye,c as d,d as be,f as xe,g as Se,h as Ce,m as we,o as f,s as Te,w as Ee,y as p}from"./context-model-Bb15chFt.js";import{o as De}from"./workspace-model-D-SLfads.js";import{n as Oe,t as m}from"./use-token-gate-DSNIIpI6.js";import{t as h}from"./context.module-BijAfoJw.js";var g=t(e(),1),_=n();function v(e,t,n){if(!n)return d(e,t);if(e.length===0)return null;let r=e.find(e=>e.id===n.seatId);if(!r)return d(e,t);let i=Ce(r,n.model);if(i)return{seatId:r.id,model:i.id};let a=r.models.find(e=>!e.unavailableReason);return{seatId:r.id,model:a?a.id:n.model}}var ke=4e3,Ae="Building the handoff reads this chat’s log and runs `git diff --stat` on its folders. It spends nothing.",je=`Asking for a summary sends one turn to this chat’s seat.`,Me=`Stopping the summary turn.`,Ne=`Creating the chat records a new session on this machine. Nothing is sent to a model until you press Send in it.`;function Pe(e,t){let n=null,r=!1;for(let i of e)if(`turnId`in i&&i.turnId===t){if(i.type===`error`)n=i.message;else if(i.type===`assistant-message`||i.type===`text-delta`&&i.text.trim().length>0)r=!0;else if(i.type===`cancelled`)return{kind:`cancelled`};else if(i.type===`turn-done`)return i.ok?r?{kind:`ok`}:{kind:`empty`}:{kind:`failed`,message:n}}return null}function y(e){return e.open?(0,_.jsx)(b,{...e}):null}function b({session:e,seats:t,onClose:n,onCreated:d,initialTarget:y}){let b=(0,g.useId)(),x=(0,g.useId)(),S=(0,g.useId)(),C=(0,g.useId)(),Fe=(0,g.useId)(),w=(0,g.useId)(),T=(0,g.useId)(),E=(0,g.useRef)(null),D=Oe(),Ie=i(de),[O,Le]=(0,g.useState)(null),[k,A]=(0,g.useState)(`idle`),[j,Re]=(0,g.useState)(null),[M,ze]=(0,g.useState)(``),[N,Be]=(0,g.useState)(``),[Ve,He]=(0,g.useState)(!1),P=(0,g.useRef)(0),F=(0,g.useRef)(!0);(0,g.useEffect)(()=>(F.current=!0,()=>{F.current=!1}),[]);let Ue=(0,g.useRef)(null);Ue.current=O;let We=D.run,I=(0,g.useCallback)(async t=>{let n=P.current+=1;A(`loading`),Re(null);try{let r=await We(Ae,()=>fe(e.id,t));if(!F.current||n!==P.current)return;if(r===null){A(Ue.current?`ready`:`locked`);return}Le(r),ze(r.text),A(`ready`)}catch(e){if(!F.current||n!==P.current)return;Re(m(e)),A(`error`)}},[We,e.id]);(0,g.useEffect)(()=>{r()?I({includeLastAssistant:!1,focus:``}):A(`locked`)},[]);let L=O!==null&&M!==O.text,Ge=(0,g.useMemo)(()=>Ee(M)>65536||we({text:M})>65536,[M]),Ke=M.length>u,[R,qe]=(0,g.useState)(()=>v(t,e,y));(0,g.useEffect)(()=>{R===null&&t.length>0&&qe(v(t,e,y))},[R,t,e,y]);let z=R?o(t,R.seatId)??null:null,B=R?Ce(z,R.model):null,[V,Je]=(0,g.useState)(null),Ye=Te({option:B,target:R,source:e,preferences:Ie.data}),H=V!==null&&p(B,V)!==void 0?V:Ye,Xe=Se(B),U=ye(z,B),W=be(M.length,B,H,z?.engine??null),Ze=[he(B),me(z?.engine)].filter(Boolean).join(` `),Qe=1+(e.extraRoots?.filter(t=>t&&t!==e.projectPath).length??0),$e=De(z?.engine??null,Qe);function et(e){qe({seatId:e.seatId,model:e.model}),Je(null)}let[tt,nt]=(0,g.useState)(()=>xe(e.title)),[G,K]=(0,g.useState)({phase:`idle`}),q=o(t,e.seatId)?.label??ae[e.engine],J=G.phase===`sending`||G.phase===`waiting`||G.phase===`cancelling`,Y=e.status===`running`?`A turn is running in this chat. Wait for it to finish first.`:e.turnCount===0?`This chat has no turns yet, so there is nothing to summarize.`:null;async function rt(){K({phase:`sending`});try{let t=await D.run(je,async()=>{l(e.id,`running`);try{let t=await ne(e.id,ve);return c(e.id,t.session,t.turnId),t.turnId}catch(t){throw l(e.id,`idle`),t}});if(!F.current)return;K(t===null?{phase:`idle`}:{phase:`waiting`,turnId:t})}catch(e){F.current&&K({phase:`failed`,message:m(e)})}}async function it(){if(G.phase!==`waiting`)return;let t=G.turnId;K({phase:`cancelling`,turnId:t});try{await D.run(Me,()=>te(e.id))===null&&F.current&&K({phase:`waiting`,turnId:t})}catch(e){F.current&&K({phase:`failed`,message:m(e)})}}let at=(0,g.useRef)(N);at.current=N,(0,g.useEffect)(()=>{if(G.phase!==`waiting`&&G.phase!==`cancelling`)return;let t=G.turnId,n=!1,r=()=>{if(n)return;let r=Pe(s(e.id).events,t);if(r!==null)switch(n=!0,r.kind){case`ok`:K({phase:`done`}),He(!0),I({includeLastAssistant:!0,focus:at.current});break;case`cancelled`:K({phase:`failed`,message:`Summary stopped. The automatic preview is unchanged.`});break;case`empty`:K({phase:`failed`,message:`${q} finished without writing a summary. The automatic preview is unchanged.`});break;default:K({phase:`failed`,message:`The summary turn failed${r.message?`: ${le(ue(r.message))}`:``}. The automatic preview is unchanged.`})}};r();let i=se(r),a=setInterval(()=>{let t=s(e.id).stream;t!==`open`&&t!==`connecting`&&t!==`reconnecting`&&ie(e.id).then(t=>ce(e.id,t.session,t.events)).catch(()=>{})},ke);return()=>{n=!0,i(),clearInterval(a)}},[G,e.id]);let[X,ot]=(0,g.useState)(!1),[Z,st]=(0,g.useState)(null),ct=M.trim().length>0,Q=U??(O?null:`Build the handoff first.`)??(ct?null:`The handoff is empty — rebuild it or write one.`)??(Ge?`The handoff is over the 64 KB limit for one message. Trim it first.`:null)??(J?`Wait for the summary to finish, or stop it.`:null);async function lt(){if(!R||Q!==null||X)return;ot(!0),st(null);let t=M;try{let r=await D.run(Ne,()=>pe({source:e,seatId:R.seatId,model:R.model,contextMode:p(B,H),title:tt.trim()||void 0}));if(r===null)return;c(r.id,r),re(r.projectPath,{seatId:r.seatId,model:r.model}),d(r,t),n()}catch(e){F.current&&st(m(e))}finally{F.current&&ot(!1)}}let ut=()=>{D.dialog.open||n()},dt=Math.ceil(M.length/4),$=()=>void I({includeLastAssistant:Ve,focus:N});return(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(a,{open:!0,onClose:ut,titleId:b,title:`Continue in a fresh chat`,initialFocusRef:E,widthClassName:h.dialogWidth,description:(0,_.jsxs)(_.Fragment,{children:[`Start a new chat from a written handoff of “`,e.title||`Untitled chat`,`” instead of its full history.`]}),children:(0,_.jsxs)(`form`,{className:h.form,noValidate:!0,onSubmit:e=>{e.preventDefault(),lt()},children:[(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsxs)(`label`,{className:h.label,htmlFor:x,children:[`Focus for the next chat `,(0,_.jsx)(`span`,{className:h.optional,children:`optional`})]}),(0,_.jsxs)(`div`,{className:h.row,children:[(0,_.jsx)(`input`,{id:x,ref:E,className:h.input,value:N,maxLength:500,placeholder:`e.g. finish the migration, then run the full test suite`,autoComplete:`off`,onChange:e=>Be(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),k!==`loading`&&$())}}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:$,disabled:k===`loading`||J,children:L?`Rebuild (replaces your edits)`:`Rebuild`})]})]}),(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(`label`,{className:h.label,htmlFor:S,children:`Handoff — becomes the new chat’s first message`}),k===`locked`&&!O?(0,_.jsxs)(`div`,{className:h.locked,role:`status`,children:[(0,_.jsxs)(`p`,{children:[`Building the handoff needs the mutation token: it reads this chat’s log and runs `,(0,_.jsx)(`code`,{children:`git diff --stat`}),`. It spends nothing.`]}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:$,children:`Unlock and build the handoff`})]}):(0,_.jsx)(`textarea`,{id:S,className:h.textarea,value:M,rows:12,spellCheck:!1,"aria-describedby":C,"aria-busy":k===`loading`||void 0,disabled:!O,placeholder:k===`loading`?`Building the handoff from this chat’s log…`:``,onChange:e=>ze(e.target.value)}),(0,_.jsx)(`p`,{id:C,className:h.hint,"aria-live":`polite`,children:k===`loading`?O?`Rebuilding…`:`Reading this chat’s log…`:O?(0,_.jsxs)(_.Fragment,{children:[M.length.toLocaleString(),` chars · ~`,dt.toLocaleString(),` tokens`,` · `,O.stats.turnsCovered,` `,O.stats.turnsCovered===1?`turn`:`turns`,` · `,O.stats.filesTouched,` `,O.stats.filesTouched===1?`file`:`files`,` touched`,L?` · edited`:``,Ve?` · includes ${q}’s own summary`:``]}):null}),O&&O.stats.truncated.length>0?(0,_.jsxs)(`p`,{className:h.hint,children:[`To stay under `,u.toLocaleString(),` characters these sections were left out: `,O.stats.truncated.join(`, `),`.`]}):null,Ge?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:`Over the 64 KB limit for one message (counted as it is sent, line breaks and quotes encoded) — the new chat could not send it. Trim it first.`}):Ke?(0,_.jsxs)(`p`,{className:h.warn,children:[`Longer than the `,u.toLocaleString(),`-character handoff budget. It can still be sent; the new chat just starts bigger.`]}):null,k===`error`&&j?(0,_.jsxs)(`p`,{className:h.error,role:`alert`,children:[`Could not build the handoff: `,j,` `,(0,_.jsx)(`button`,{type:`button`,className:h.link,onClick:$,children:`Try again`})]}):null]}),(0,_.jsxs)(`section`,{className:h.aside,"aria-labelledby":`${b}-summary`,children:[(0,_.jsxs)(`h3`,{id:`${b}-summary`,className:h.label,children:[`Better summary `,(0,_.jsx)(`span`,{className:h.optional,children:`optional, spends`})]}),(0,_.jsxs)(`p`,{className:h.hint,children:[`The handoff above is assembled from this chat’s log. For one in the agent’s own words, ask `,q,` to write it first — its reply is added to the handoff. `,_e(e.engine,q)]}),G.phase===`waiting`||G.phase===`cancelling`?(0,_.jsxs)(`div`,{className:h.row,role:`status`,children:[(0,_.jsx)(`span`,{className:h.pending,"aria-hidden":`true`}),(0,_.jsx)(`span`,{className:h.hint,children:G.phase===`cancelling`?`Stopping the summary…`:`Waiting for ${q} to finish its summary…`}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:()=>void it(),disabled:G.phase===`cancelling`,children:`Stop the summary`})]}):(0,_.jsxs)(`div`,{className:h.row,children:[(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:()=>void rt(),disabled:Y!==null||G.phase===`sending`,children:G.phase===`sending`?`Sending…`:G.phase===`done`?`Ask ${q} again`:`Ask ${q} to summarize first`}),G.phase===`done`?(0,_.jsx)(`span`,{className:h.hint,role:`status`,children:`Summary added.`}):null]}),Y!==null&&!J?(0,_.jsx)(`p`,{className:h.hint,children:Y}):null,Y===null&&G.phase===`idle`&&L?(0,_.jsx)(`p`,{className:h.hint,children:`The handoff is rebuilt with the summary, which replaces your edits above.`}):null,G.phase===`failed`?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:G.message}):null]}),(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(ge,{id:Fe,seats:t,value:R,onChange:et,label:`Continue on`,modeFor:(e,t)=>R&&e.id===R.seatId&&t.id===R.model?H:`standard`}),U?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:U}):null,$e?(0,_.jsx)(`p`,{className:h.hint,children:$e}):null]}),B&&!U?(0,_.jsxs)(`div`,{className:h.field,children:[Xe?(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(`span`,{id:T,className:h.label,children:`Context mode`}),(0,_.jsx)(oe,{"aria-labelledby":T,size:`sm`,value:H,onChange:e=>Je(e),options:[{value:`standard`,label:`Standard`},{value:`expansive`,label:`Expansive`}]}),(0,_.jsxs)(`p`,{className:h.hint,children:[f(B,H),`.`,` `,H===`expansive`?`Expansive keeps far more of the conversation before compacting, but every turn re-sends all of it — each turn costs more usage.${Ze?` ${Ze}`:``}`:`Standard compacts sooner and keeps each turn cheaper. Expansive is one click away if the work needs it.`]})]}):f(B,`standard`)?(0,_.jsxs)(`p`,{className:h.hint,children:[f(B,`standard`),`.`]}):null,(0,_.jsx)(`p`,{className:`${h.fit} ${h[`fit-${W.tone}`]??``}`,"data-verdict":W.verdict??`unknown`,children:W.text})]}):null,(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(`label`,{className:h.label,htmlFor:w,children:`Title`}),(0,_.jsx)(`input`,{id:w,className:h.input,value:tt,maxLength:120,autoComplete:`off`,onChange:e=>nt(e.target.value)})]}),Z?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:Z}):null,(0,_.jsx)(`p`,{className:h.cost,children:`Creating the chat is free — nothing is sent to a model. The handoff goes into the new chat’s composer; read it, then press Send. That first turn is the first thing spent.`}),(0,_.jsxs)(`div`,{className:h.actions,children:[Q&&O?(0,_.jsx)(`span`,{className:h.blocked,children:Q}):null,(0,_.jsx)(`button`,{type:`button`,className:h.cancel,onClick:n,children:`Cancel`}),(0,_.jsx)(`button`,{type:`submit`,className:h.primary,disabled:Q!==null||X,children:X?`Creating…`:`Create chat`})]})]})}),(0,_.jsx)(ee,{open:D.dialog.open,reason:D.dialog.reason,tokenLabel:`Mutation token`,tokenHelp:`the mutation token ashlr verse printed`,onClose:D.dialog.onClose,onUnlocked:D.dialog.onUnlocked})]})}export{y as HandoffDialog};
2
- //# sourceMappingURL=HandoffDialog-B1G6gQyk.js.map
1
+ import{a as e,c as t,n}from"./index-DZ-UQ7v8.js";import{A as r,h as i}from"./global-CMNW_dqn.js";import{t as a}from"./Dialog-D3msQlCj.js";import{t as ee}from"./MutationTokenDialog-DbnO8aYi.js";import{a as te,h as ne,it as re,u as ie}from"./VerseConsoleApp-CWU6R3By.js";import{n as ae,y as o}from"./verse-model-DAVevkNe.js";import{t as oe}from"./Segmented-CGh_-tBb.js";import{a as s,l as c,p as se,s as ce,u as l}from"./verse-store-DNVRuiJL.js";import{t as le,y as ue}from"./format-CH4g_sl1.js";import{l as de,r as fe,t as pe}from"./context-queries-eL3caKVG.js";import{o as me,s as he}from"./context-model-Br8t9jgG.js";import{t as ge}from"./SeatSelector-J5R3zDkB.js";import{C as _e,D as ve,E as u,S as ye,c as d,d as be,f as xe,g as Se,h as Ce,m as we,o as f,s as Te,w as Ee,y as p}from"./context-model-CokrgEUq.js";import{o as De}from"./workspace-model-dji5-Al3.js";import{n as Oe,t as m}from"./use-token-gate-CbXVYQYI.js";import{t as h}from"./context.module-BijAfoJw.js";var g=t(e(),1),_=n();function v(e,t,n){if(!n)return d(e,t);if(e.length===0)return null;let r=e.find(e=>e.id===n.seatId);if(!r)return d(e,t);let i=Ce(r,n.model);if(i)return{seatId:r.id,model:i.id};let a=r.models.find(e=>!e.unavailableReason);return{seatId:r.id,model:a?a.id:n.model}}var ke=4e3,Ae="Building the handoff reads this chat’s log and runs `git diff --stat` on its folders. It spends nothing.",je=`Asking for a summary sends one turn to this chat’s seat.`,Me=`Stopping the summary turn.`,Ne=`Creating the chat records a new session on this machine. Nothing is sent to a model until you press Send in it.`;function Pe(e,t){let n=null,r=!1;for(let i of e)if(`turnId`in i&&i.turnId===t){if(i.type===`error`)n=i.message;else if(i.type===`assistant-message`||i.type===`text-delta`&&i.text.trim().length>0)r=!0;else if(i.type===`cancelled`)return{kind:`cancelled`};else if(i.type===`turn-done`)return i.ok?r?{kind:`ok`}:{kind:`empty`}:{kind:`failed`,message:n}}return null}function y(e){return e.open?(0,_.jsx)(b,{...e}):null}function b({session:e,seats:t,onClose:n,onCreated:d,initialTarget:y}){let b=(0,g.useId)(),x=(0,g.useId)(),S=(0,g.useId)(),C=(0,g.useId)(),Fe=(0,g.useId)(),w=(0,g.useId)(),T=(0,g.useId)(),E=(0,g.useRef)(null),D=Oe(),Ie=i(de),[O,Le]=(0,g.useState)(null),[k,A]=(0,g.useState)(`idle`),[j,Re]=(0,g.useState)(null),[M,ze]=(0,g.useState)(``),[N,Be]=(0,g.useState)(``),[Ve,He]=(0,g.useState)(!1),P=(0,g.useRef)(0),F=(0,g.useRef)(!0);(0,g.useEffect)(()=>(F.current=!0,()=>{F.current=!1}),[]);let Ue=(0,g.useRef)(null);Ue.current=O;let We=D.run,I=(0,g.useCallback)(async t=>{let n=P.current+=1;A(`loading`),Re(null);try{let r=await We(Ae,()=>fe(e.id,t));if(!F.current||n!==P.current)return;if(r===null){A(Ue.current?`ready`:`locked`);return}Le(r),ze(r.text),A(`ready`)}catch(e){if(!F.current||n!==P.current)return;Re(m(e)),A(`error`)}},[We,e.id]);(0,g.useEffect)(()=>{r()?I({includeLastAssistant:!1,focus:``}):A(`locked`)},[]);let L=O!==null&&M!==O.text,Ge=(0,g.useMemo)(()=>Ee(M)>65536||we({text:M})>65536,[M]),Ke=M.length>u,[R,qe]=(0,g.useState)(()=>v(t,e,y));(0,g.useEffect)(()=>{R===null&&t.length>0&&qe(v(t,e,y))},[R,t,e,y]);let z=R?o(t,R.seatId)??null:null,B=R?Ce(z,R.model):null,[V,Je]=(0,g.useState)(null),Ye=Te({option:B,target:R,source:e,preferences:Ie.data}),H=V!==null&&p(B,V)!==void 0?V:Ye,Xe=Se(B),U=ye(z,B),W=be(M.length,B,H,z?.engine??null),Ze=[he(B),me(z?.engine)].filter(Boolean).join(` `),Qe=1+(e.extraRoots?.filter(t=>t&&t!==e.projectPath).length??0),$e=De(z?.engine??null,Qe);function et(e){qe({seatId:e.seatId,model:e.model}),Je(null)}let[tt,nt]=(0,g.useState)(()=>xe(e.title)),[G,K]=(0,g.useState)({phase:`idle`}),q=o(t,e.seatId)?.label??ae[e.engine],J=G.phase===`sending`||G.phase===`waiting`||G.phase===`cancelling`,Y=e.status===`running`?`A turn is running in this chat. Wait for it to finish first.`:e.turnCount===0?`This chat has no turns yet, so there is nothing to summarize.`:null;async function rt(){K({phase:`sending`});try{let t=await D.run(je,async()=>{l(e.id,`running`);try{let t=await ne(e.id,ve);return c(e.id,t.session,t.turnId),t.turnId}catch(t){throw l(e.id,`idle`),t}});if(!F.current)return;K(t===null?{phase:`idle`}:{phase:`waiting`,turnId:t})}catch(e){F.current&&K({phase:`failed`,message:m(e)})}}async function it(){if(G.phase!==`waiting`)return;let t=G.turnId;K({phase:`cancelling`,turnId:t});try{await D.run(Me,()=>te(e.id))===null&&F.current&&K({phase:`waiting`,turnId:t})}catch(e){F.current&&K({phase:`failed`,message:m(e)})}}let at=(0,g.useRef)(N);at.current=N,(0,g.useEffect)(()=>{if(G.phase!==`waiting`&&G.phase!==`cancelling`)return;let t=G.turnId,n=!1,r=()=>{if(n)return;let r=Pe(s(e.id).events,t);if(r!==null)switch(n=!0,r.kind){case`ok`:K({phase:`done`}),He(!0),I({includeLastAssistant:!0,focus:at.current});break;case`cancelled`:K({phase:`failed`,message:`Summary stopped. The automatic preview is unchanged.`});break;case`empty`:K({phase:`failed`,message:`${q} finished without writing a summary. The automatic preview is unchanged.`});break;default:K({phase:`failed`,message:`The summary turn failed${r.message?`: ${le(ue(r.message))}`:``}. The automatic preview is unchanged.`})}};r();let i=se(r),a=setInterval(()=>{let t=s(e.id).stream;t!==`open`&&t!==`connecting`&&t!==`reconnecting`&&ie(e.id).then(t=>ce(e.id,t.session,t.events)).catch(()=>{})},ke);return()=>{n=!0,i(),clearInterval(a)}},[G,e.id]);let[X,ot]=(0,g.useState)(!1),[Z,st]=(0,g.useState)(null),ct=M.trim().length>0,Q=U??(O?null:`Build the handoff first.`)??(ct?null:`The handoff is empty — rebuild it or write one.`)??(Ge?`The handoff is over the 64 KB limit for one message. Trim it first.`:null)??(J?`Wait for the summary to finish, or stop it.`:null);async function lt(){if(!R||Q!==null||X)return;ot(!0),st(null);let t=M;try{let r=await D.run(Ne,()=>pe({source:e,seatId:R.seatId,model:R.model,contextMode:p(B,H),title:tt.trim()||void 0}));if(r===null)return;c(r.id,r),re(r.projectPath,{seatId:r.seatId,model:r.model}),d(r,t),n()}catch(e){F.current&&st(m(e))}finally{F.current&&ot(!1)}}let ut=()=>{D.dialog.open||n()},dt=Math.ceil(M.length/4),$=()=>void I({includeLastAssistant:Ve,focus:N});return(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(a,{open:!0,onClose:ut,titleId:b,title:`Continue in a fresh chat`,initialFocusRef:E,widthClassName:h.dialogWidth,description:(0,_.jsxs)(_.Fragment,{children:[`Start a new chat from a written handoff of “`,e.title||`Untitled chat`,`” instead of its full history.`]}),children:(0,_.jsxs)(`form`,{className:h.form,noValidate:!0,onSubmit:e=>{e.preventDefault(),lt()},children:[(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsxs)(`label`,{className:h.label,htmlFor:x,children:[`Focus for the next chat `,(0,_.jsx)(`span`,{className:h.optional,children:`optional`})]}),(0,_.jsxs)(`div`,{className:h.row,children:[(0,_.jsx)(`input`,{id:x,ref:E,className:h.input,value:N,maxLength:500,placeholder:`e.g. finish the migration, then run the full test suite`,autoComplete:`off`,onChange:e=>Be(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),k!==`loading`&&$())}}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:$,disabled:k===`loading`||J,children:L?`Rebuild (replaces your edits)`:`Rebuild`})]})]}),(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(`label`,{className:h.label,htmlFor:S,children:`Handoff — becomes the new chat’s first message`}),k===`locked`&&!O?(0,_.jsxs)(`div`,{className:h.locked,role:`status`,children:[(0,_.jsxs)(`p`,{children:[`Building the handoff needs the mutation token: it reads this chat’s log and runs `,(0,_.jsx)(`code`,{children:`git diff --stat`}),`. It spends nothing.`]}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:$,children:`Unlock and build the handoff`})]}):(0,_.jsx)(`textarea`,{id:S,className:h.textarea,value:M,rows:12,spellCheck:!1,"aria-describedby":C,"aria-busy":k===`loading`||void 0,disabled:!O,placeholder:k===`loading`?`Building the handoff from this chat’s log…`:``,onChange:e=>ze(e.target.value)}),(0,_.jsx)(`p`,{id:C,className:h.hint,"aria-live":`polite`,children:k===`loading`?O?`Rebuilding…`:`Reading this chat’s log…`:O?(0,_.jsxs)(_.Fragment,{children:[M.length.toLocaleString(),` chars · ~`,dt.toLocaleString(),` tokens`,` · `,O.stats.turnsCovered,` `,O.stats.turnsCovered===1?`turn`:`turns`,` · `,O.stats.filesTouched,` `,O.stats.filesTouched===1?`file`:`files`,` touched`,L?` · edited`:``,Ve?` · includes ${q}’s own summary`:``]}):null}),O&&O.stats.truncated.length>0?(0,_.jsxs)(`p`,{className:h.hint,children:[`To stay under `,u.toLocaleString(),` characters these sections were left out: `,O.stats.truncated.join(`, `),`.`]}):null,Ge?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:`Over the 64 KB limit for one message (counted as it is sent, line breaks and quotes encoded) — the new chat could not send it. Trim it first.`}):Ke?(0,_.jsxs)(`p`,{className:h.warn,children:[`Longer than the `,u.toLocaleString(),`-character handoff budget. It can still be sent; the new chat just starts bigger.`]}):null,k===`error`&&j?(0,_.jsxs)(`p`,{className:h.error,role:`alert`,children:[`Could not build the handoff: `,j,` `,(0,_.jsx)(`button`,{type:`button`,className:h.link,onClick:$,children:`Try again`})]}):null]}),(0,_.jsxs)(`section`,{className:h.aside,"aria-labelledby":`${b}-summary`,children:[(0,_.jsxs)(`h3`,{id:`${b}-summary`,className:h.label,children:[`Better summary `,(0,_.jsx)(`span`,{className:h.optional,children:`optional, spends`})]}),(0,_.jsxs)(`p`,{className:h.hint,children:[`The handoff above is assembled from this chat’s log. For one in the agent’s own words, ask `,q,` to write it first — its reply is added to the handoff. `,_e(e.engine,q)]}),G.phase===`waiting`||G.phase===`cancelling`?(0,_.jsxs)(`div`,{className:h.row,role:`status`,children:[(0,_.jsx)(`span`,{className:h.pending,"aria-hidden":`true`}),(0,_.jsx)(`span`,{className:h.hint,children:G.phase===`cancelling`?`Stopping the summary…`:`Waiting for ${q} to finish its summary…`}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:()=>void it(),disabled:G.phase===`cancelling`,children:`Stop the summary`})]}):(0,_.jsxs)(`div`,{className:h.row,children:[(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:()=>void rt(),disabled:Y!==null||G.phase===`sending`,children:G.phase===`sending`?`Sending…`:G.phase===`done`?`Ask ${q} again`:`Ask ${q} to summarize first`}),G.phase===`done`?(0,_.jsx)(`span`,{className:h.hint,role:`status`,children:`Summary added.`}):null]}),Y!==null&&!J?(0,_.jsx)(`p`,{className:h.hint,children:Y}):null,Y===null&&G.phase===`idle`&&L?(0,_.jsx)(`p`,{className:h.hint,children:`The handoff is rebuilt with the summary, which replaces your edits above.`}):null,G.phase===`failed`?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:G.message}):null]}),(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(ge,{id:Fe,seats:t,value:R,onChange:et,label:`Continue on`,modeFor:(e,t)=>R&&e.id===R.seatId&&t.id===R.model?H:`standard`}),U?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:U}):null,$e?(0,_.jsx)(`p`,{className:h.hint,children:$e}):null]}),B&&!U?(0,_.jsxs)(`div`,{className:h.field,children:[Xe?(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(`span`,{id:T,className:h.label,children:`Context mode`}),(0,_.jsx)(oe,{"aria-labelledby":T,size:`sm`,value:H,onChange:e=>Je(e),options:[{value:`standard`,label:`Standard`},{value:`expansive`,label:`Expansive`}]}),(0,_.jsxs)(`p`,{className:h.hint,children:[f(B,H),`.`,` `,H===`expansive`?`Expansive keeps far more of the conversation before compacting, but every turn re-sends all of it — each turn costs more usage.${Ze?` ${Ze}`:``}`:`Standard compacts sooner and keeps each turn cheaper. Expansive is one click away if the work needs it.`]})]}):f(B,`standard`)?(0,_.jsxs)(`p`,{className:h.hint,children:[f(B,`standard`),`.`]}):null,(0,_.jsx)(`p`,{className:`${h.fit} ${h[`fit-${W.tone}`]??``}`,"data-verdict":W.verdict??`unknown`,children:W.text})]}):null,(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(`label`,{className:h.label,htmlFor:w,children:`Title`}),(0,_.jsx)(`input`,{id:w,className:h.input,value:tt,maxLength:120,autoComplete:`off`,onChange:e=>nt(e.target.value)})]}),Z?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:Z}):null,(0,_.jsx)(`p`,{className:h.cost,children:`Creating the chat is free — nothing is sent to a model. The handoff goes into the new chat’s composer; read it, then press Send. That first turn is the first thing spent.`}),(0,_.jsxs)(`div`,{className:h.actions,children:[Q&&O?(0,_.jsx)(`span`,{className:h.blocked,children:Q}):null,(0,_.jsx)(`button`,{type:`button`,className:h.cancel,onClick:n,children:`Cancel`}),(0,_.jsx)(`button`,{type:`submit`,className:h.primary,disabled:Q!==null||X,children:X?`Creating…`:`Create chat`})]})]})}),(0,_.jsx)(ee,{open:D.dialog.open,reason:D.dialog.reason,tokenLabel:`Mutation token`,tokenHelp:`the mutation token ashlr verse printed`,onClose:D.dialog.onClose,onUnlocked:D.dialog.onUnlocked})]})}export{y as HandoffDialog};
2
+ //# sourceMappingURL=HandoffDialog-CLJQLe7M.js.map