@tangle-network/agent-app 0.45.53 → 0.45.55

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 (480) hide show
  1. package/README.md +1 -1
  2. package/dist/alerting/index.d.ts +5 -175
  3. package/dist/alerting/slack.d.ts +176 -0
  4. package/dist/app-auth/index.d.ts +14 -17
  5. package/dist/assets/index.d.ts +2 -504
  6. package/dist/assets/schema.d.ts +264 -0
  7. package/dist/assets/types.d.ts +237 -0
  8. package/dist/assistant/AssistantDock.d.ts +56 -0
  9. package/dist/assistant/AssistantHistory.d.ts +41 -0
  10. package/dist/assistant/AssistantPanel.d.ts +84 -0
  11. package/dist/assistant/ProposalCard.d.ts +41 -0
  12. package/dist/assistant/ResizeHandle.d.ts +19 -0
  13. package/dist/assistant/client-context.d.ts +20 -0
  14. package/dist/assistant/client.d.ts +117 -0
  15. package/dist/assistant/index.d.ts +19 -848
  16. package/dist/assistant/launcher.d.ts +23 -0
  17. package/dist/assistant/persistence.d.ts +26 -0
  18. package/dist/assistant/presentation.d.ts +99 -0
  19. package/dist/assistant/provider-label.d.ts +7 -0
  20. package/dist/assistant/reducer.d.ts +130 -0
  21. package/dist/assistant/sse.d.ts +24 -0
  22. package/dist/assistant/time-ago.d.ts +6 -0
  23. package/dist/assistant/transcript.d.ts +97 -0
  24. package/dist/assistant/types.d.ts +291 -0
  25. package/dist/assistant/use-stick-to-bottom.d.ts +28 -0
  26. package/dist/assistant/useAssistantChat.d.ts +63 -0
  27. package/dist/assistant/useAssistantModels.d.ts +22 -0
  28. package/dist/assistant/useAssistantThreads.d.ts +47 -0
  29. package/dist/assistant/usePanelPrefs.d.ts +55 -0
  30. package/dist/billing/index.d.ts +19 -21
  31. package/dist/brand/index.d.ts +16 -10
  32. package/dist/brand-extraction/extract.d.ts +34 -0
  33. package/dist/brand-extraction/index.d.ts +12 -214
  34. package/dist/brand-extraction/map.d.ts +58 -0
  35. package/dist/brand-extraction/types.d.ts +119 -0
  36. package/dist/catalog/index.d.ts +11 -101
  37. package/dist/chat-react/composer-mode-controls.d.ts +14 -0
  38. package/dist/chat-react/entry-composer.d.ts +92 -0
  39. package/dist/chat-react/index.d.ts +22 -118
  40. package/dist/chat-react/types.d.ts +11 -0
  41. package/dist/chat-routes/attachment-store.d.ts +84 -0
  42. package/dist/chat-routes/attachment-upload.d.ts +84 -0
  43. package/dist/chat-routes/attachment-validation.d.ts +95 -0
  44. package/dist/chat-routes/binary-sniff.d.ts +45 -0
  45. package/dist/chat-routes/completed-sandbox-turn.d.ts +25 -0
  46. package/dist/chat-routes/detached-turn.d.ts +197 -0
  47. package/dist/chat-routes/dispatch-parts.d.ts +101 -0
  48. package/dist/chat-routes/draft-persistence.d.ts +189 -0
  49. package/dist/chat-routes/durable-projection.d.ts +18 -0
  50. package/dist/chat-routes/file-index.d.ts +115 -0
  51. package/dist/chat-routes/index.d.ts +25 -1840
  52. package/dist/chat-routes/model-failover-stream.d.ts +206 -0
  53. package/dist/chat-routes/promote-file-part.d.ts +84 -0
  54. package/dist/chat-routes/resolve-attachments.d.ts +72 -0
  55. package/dist/chat-routes/sandbox-producer.d.ts +146 -0
  56. package/dist/chat-routes/sandbox-turn-usage.d.ts +4 -0
  57. package/dist/{stale-turn-lock-DucQzvXu.d.ts → chat-routes/stale-turn-lock.d.ts} +7 -9
  58. package/dist/chat-routes/turn-routes.d.ts +540 -0
  59. package/dist/chat-routes/upload.d.ts +84 -0
  60. package/dist/{wire-DOZ-O6hD.d.ts → chat-routes/wire.d.ts} +41 -44
  61. package/dist/chat-store/core.d.ts +19 -0
  62. package/dist/chat-store/index.d.ts +22 -322
  63. package/dist/{parts-BqIHMdyu.d.ts → chat-store/parts.d.ts} +49 -47
  64. package/dist/chat-store/schema.d.ts +157 -0
  65. package/dist/chat-store/store.d.ts +177 -0
  66. package/dist/config/index.d.ts +13 -18
  67. package/dist/crypto/index.d.ts +10 -12
  68. package/dist/crypto/web-token.d.ts +22 -0
  69. package/dist/design-canvas/apply.d.ts +70 -0
  70. package/dist/design-canvas/drizzle-store.d.ts +29 -0
  71. package/dist/design-canvas/drizzle.d.ts +7 -575
  72. package/dist/{export-presets-mgVulRaV.d.ts → design-canvas/export-presets.d.ts} +18 -22
  73. package/dist/design-canvas/index.d.ts +22 -268
  74. package/dist/design-canvas/mcp-entry.d.ts +15 -0
  75. package/dist/design-canvas/mcp-handler.d.ts +34 -0
  76. package/dist/design-canvas/mcp-tools.d.ts +30 -0
  77. package/dist/{model-DnfO_PdJ.d.ts → design-canvas/model.d.ts} +33 -35
  78. package/dist/{operations-ByJ6yXOW.d.ts → design-canvas/operations.d.ts} +21 -25
  79. package/dist/design-canvas/schema.d.ts +558 -0
  80. package/dist/{store-CqfDtnPQ.d.ts → design-canvas/store.d.ts} +8 -12
  81. package/dist/design-canvas/templates.d.ts +72 -0
  82. package/dist/design-canvas/validate.d.ts +32 -0
  83. package/dist/design-canvas-react/components/BleedTrimOverlay.d.ts +22 -0
  84. package/dist/design-canvas-react/components/BrandKnot.d.ts +11 -0
  85. package/dist/design-canvas-react/components/CanvasEmptyState.d.ts +32 -0
  86. package/dist/design-canvas-react/components/CanvasInsertPanel.d.ts +53 -0
  87. package/dist/{lazy-DrkVyDpe.d.ts → design-canvas-react/components/DesignCanvas.d.ts} +27 -20
  88. package/dist/design-canvas-react/components/DesignCanvasEditor.d.ts +23 -0
  89. package/dist/design-canvas-react/components/ElementNode.d.ts +51 -0
  90. package/dist/design-canvas-react/components/ExportControl.d.ts +21 -0
  91. package/dist/design-canvas-react/components/GridLayer.d.ts +47 -0
  92. package/dist/design-canvas-react/components/InlineTextEditor.d.ts +25 -0
  93. package/dist/design-canvas-react/components/LayersPanel.d.ts +20 -0
  94. package/dist/design-canvas-react/components/PagesStrip.d.ts +34 -0
  95. package/dist/design-canvas-react/components/Rulers.d.ts +31 -0
  96. package/dist/design-canvas-react/components/SelectionLayer.d.ts +51 -0
  97. package/dist/design-canvas-react/components/SnapGuidesOverlay.d.ts +25 -0
  98. package/dist/design-canvas-react/components/Toolbar.d.ts +64 -0
  99. package/dist/design-canvas-react/components/Workspace.d.ts +92 -0
  100. package/dist/design-canvas-react/components/ZoomControls.d.ts +14 -0
  101. package/dist/design-canvas-react/components/glyphs.d.ts +46 -0
  102. package/dist/design-canvas-react/components/icon-button.d.ts +22 -0
  103. package/dist/design-canvas-react/components/index.d.ts +27 -0
  104. package/dist/design-canvas-react/components/layer-tree.d.ts +34 -0
  105. package/dist/design-canvas-react/components/ruler-math.d.ts +78 -0
  106. package/dist/design-canvas-react/components/transform-math.d.ts +168 -0
  107. package/dist/{command-stack-TNPWJCzW.d.ts → design-canvas-react/contracts.d.ts} +16 -63
  108. package/dist/design-canvas-react/engine/command-stack.d.ts +43 -0
  109. package/dist/design-canvas-react/engine/commands.d.ts +154 -0
  110. package/dist/design-canvas-react/engine/selection.d.ts +48 -0
  111. package/dist/design-canvas-react/engine/snap.d.ts +24 -0
  112. package/dist/design-canvas-react/engine/zoom-pan.d.ts +18 -0
  113. package/dist/design-canvas-react/engine.d.ts +21 -399
  114. package/dist/design-canvas-react/export-math.d.ts +104 -0
  115. package/dist/design-canvas-react/export.d.ts +89 -0
  116. package/dist/design-canvas-react/index.d.ts +16 -586
  117. package/dist/design-canvas-react/insert-builders.d.ts +61 -0
  118. package/dist/design-canvas-react/lazy.d.ts +21 -6
  119. package/dist/documents/docx.d.ts +50 -0
  120. package/dist/documents/extract.d.ts +87 -0
  121. package/dist/documents/index.d.ts +26 -232
  122. package/dist/documents/media-type.d.ts +33 -0
  123. package/dist/documents/pdf-inspector.d.ts +5 -9
  124. package/dist/{types-DrBidf3O.d.ts → documents/types.d.ts} +13 -15
  125. package/dist/documents/zip.d.ts +56 -0
  126. package/dist/eval/calibration.d.ts +106 -0
  127. package/dist/eval/index.d.ts +8 -116
  128. package/dist/eval-campaign/index.d.ts +11 -12
  129. package/dist/{trust-gate-Dcm5xSva.d.ts → eval-campaign/trust-gate.d.ts} +5 -9
  130. package/dist/forms/blank.d.ts +48 -0
  131. package/dist/forms/fill.d.ts +105 -0
  132. package/dist/forms/index.d.ts +58 -332
  133. package/dist/forms/registry.d.ts +115 -0
  134. package/dist/forms/verify.d.ts +58 -0
  135. package/dist/harness/index.d.ts +21 -19
  136. package/dist/intakes/api.d.ts +5 -11
  137. package/dist/{completion-CvcNUz07.d.ts → intakes/completion.d.ts} +7 -11
  138. package/dist/intakes/context-sufficiency.d.ts +113 -0
  139. package/dist/intakes/drizzle/schema.d.ts +338 -0
  140. package/dist/intakes/drizzle/store.d.ts +75 -0
  141. package/dist/intakes/drizzle.d.ts +12 -391
  142. package/dist/intakes/index.d.ts +23 -113
  143. package/dist/{model-C8U0HZxL.d.ts → intakes/model.d.ts} +15 -17
  144. package/dist/intakes-react/components/BrandMark.d.ts +10 -0
  145. package/dist/intakes-react/components/IntakeInterview.d.ts +15 -0
  146. package/dist/intakes-react/components/index.d.ts +1 -0
  147. package/dist/intakes-react/contracts.d.ts +42 -0
  148. package/dist/intakes-react/index.d.ts +12 -47
  149. package/dist/intakes-react/lazy.d.ts +9 -8
  150. package/dist/integrations/index.d.ts +10 -12
  151. package/dist/{contract-OxG_jVMx.d.ts → interactions/contract.d.ts} +40 -42
  152. package/dist/interactions/index.d.ts +16 -256
  153. package/dist/interactions/route.d.ts +151 -0
  154. package/dist/interactions/sidecar.d.ts +100 -0
  155. package/dist/knowledge/index.d.ts +7 -11
  156. package/dist/knowledge-loop/index.d.ts +13 -20
  157. package/dist/legibility/checks/empty-state.d.ts +59 -0
  158. package/dist/legibility/checks/reachability.d.ts +103 -0
  159. package/dist/legibility/checks/silent-failure.d.ts +57 -0
  160. package/dist/legibility/checks/success.d.ts +38 -0
  161. package/dist/legibility/checks/vocabulary.d.ts +65 -0
  162. package/dist/legibility/cli-args.d.ts +30 -0
  163. package/dist/legibility/cli.d.ts +25 -0
  164. package/dist/legibility/index.d.ts +10 -530
  165. package/dist/legibility/report.d.ts +22 -0
  166. package/dist/legibility/scan.d.ts +29 -0
  167. package/dist/legibility/source.d.ts +132 -0
  168. package/dist/legibility/suppress.d.ts +36 -0
  169. package/dist/legibility/types.d.ts +168 -0
  170. package/dist/legibility/walk-sources.d.ts +21 -0
  171. package/dist/{agent-activity-C8ZG0F0M.d.ts → missions/agent-activity.d.ts} +3 -5
  172. package/dist/missions/engine.d.ts +251 -0
  173. package/dist/missions/events.d.ts +195 -0
  174. package/dist/missions/index.d.ts +12 -765
  175. package/dist/missions/plan-parse.d.ts +50 -0
  176. package/dist/missions/service.d.ts +265 -0
  177. package/dist/{failover-D-3UXXTb.d.ts → model-resolution/failover.d.ts} +10 -12
  178. package/dist/model-resolution/index.d.ts +15 -18
  179. package/dist/object-store/index.d.ts +15 -17
  180. package/dist/openui/action.d.ts +54 -0
  181. package/dist/openui/authoring.d.ts +25 -0
  182. package/dist/openui/index.d.ts +24 -206
  183. package/dist/openui/route.d.ts +124 -0
  184. package/dist/openui/segments.d.ts +71 -0
  185. package/dist/openui/values.d.ts +82 -0
  186. package/dist/openui-react/index.d.ts +9 -13
  187. package/dist/peer-floors/check.d.ts +9 -190
  188. package/dist/peer-floors/cli.d.ts +2 -3
  189. package/dist/peer-floors/dependency-source.d.ts +178 -0
  190. package/dist/plans/index.d.ts +13 -14
  191. package/dist/{billing-BuNlaKlE.d.ts → platform/billing.d.ts} +28 -32
  192. package/dist/platform/guards.d.ts +79 -0
  193. package/dist/platform/hub.d.ts +107 -0
  194. package/dist/platform/index.d.ts +7 -112
  195. package/dist/{sso-Cm00S61u.d.ts → platform/sso.d.ts} +15 -97
  196. package/dist/preflight/cli.d.ts +3 -6
  197. package/dist/preflight/index.d.ts +16 -18
  198. package/dist/preset-cloudflare/headers.d.ts +12 -0
  199. package/dist/preset-cloudflare/index.d.ts +22 -74
  200. package/dist/preset-cloudflare/workflow-instance.d.ts +35 -0
  201. package/dist/profile/budget.d.ts +72 -0
  202. package/dist/profile/fingerprint.d.ts +65 -0
  203. package/dist/profile/index.d.ts +27 -19
  204. package/dist/prompt/index.d.ts +3 -5
  205. package/dist/record/drizzle/schema.d.ts +488 -0
  206. package/dist/record/drizzle/store.d.ts +224 -0
  207. package/dist/record/drizzle.d.ts +10 -679
  208. package/dist/record/fold.d.ts +99 -0
  209. package/dist/record/index.d.ts +13 -13
  210. package/dist/{fold-DACU7gtf.d.ts → record/model.d.ts} +22 -124
  211. package/dist/record/ulid.d.ts +12 -0
  212. package/dist/redact/index.d.ts +14 -16
  213. package/dist/run/index.d.ts +11 -16
  214. package/dist/runtime/agent.d.ts +23 -0
  215. package/dist/runtime/certified-delivery.d.ts +57 -0
  216. package/dist/runtime/index.d.ts +17 -367
  217. package/dist/runtime/loop.d.ts +58 -0
  218. package/dist/runtime/model-catalog.d.ts +103 -0
  219. package/dist/{model-CdCDfBA9.d.ts → runtime/model.d.ts} +25 -27
  220. package/dist/runtime/openai-stream.d.ts +126 -0
  221. package/dist/runtime/surface-profile.d.ts +115 -0
  222. package/dist/sandbox/binary-read.d.ts +63 -0
  223. package/dist/sandbox/diagnostics.d.ts +69 -0
  224. package/dist/sandbox/index.d.ts +103 -1085
  225. package/dist/sandbox/model.d.ts +179 -0
  226. package/dist/sandbox/outcome.d.ts +10 -0
  227. package/dist/sandbox/prewarm-claim-d1.d.ts +80 -0
  228. package/dist/sandbox/prewarm.d.ts +193 -0
  229. package/dist/sandbox/recovery.d.ts +216 -0
  230. package/dist/sandbox/terminal-connection.d.ts +145 -0
  231. package/dist/sandbox/workspace-sandbox-manager.d.ts +44 -0
  232. package/dist/sequences/apply.d.ts +54 -0
  233. package/dist/sequences/captions.d.ts +91 -0
  234. package/dist/sequences/drizzle-store.d.ts +36 -0
  235. package/dist/sequences/drizzle.d.ts +7 -1252
  236. package/dist/sequences/exports.d.ts +138 -0
  237. package/dist/sequences/index.d.ts +19 -340
  238. package/dist/sequences/mcp-entry.d.ts +15 -0
  239. package/dist/sequences/mcp-handler.d.ts +39 -0
  240. package/dist/sequences/mcp-tools.d.ts +47 -0
  241. package/dist/{store-B7LLlk9p.d.ts → sequences/model.d.ts} +26 -110
  242. package/dist/sequences/operations.d.ts +126 -0
  243. package/dist/sequences/schema.d.ts +1231 -0
  244. package/dist/sequences/store.d.ts +81 -0
  245. package/dist/sequences/validate.d.ts +98 -0
  246. package/dist/sequences-react/components/BrandMark.d.ts +10 -0
  247. package/dist/sequences-react/components/PreviewCanvas.d.ts +26 -0
  248. package/dist/sequences-react/components/SnapIndicatorLine.d.ts +11 -0
  249. package/dist/sequences-react/components/TimelineClipChip.d.ts +80 -0
  250. package/dist/sequences-react/components/TimelineEditor.d.ts +44 -0
  251. package/dist/sequences-react/components/TimelineEmptyState.d.ts +21 -0
  252. package/dist/sequences-react/components/TimelineGhostLanes.d.ts +14 -0
  253. package/dist/sequences-react/components/TimelinePlayhead.d.ts +11 -0
  254. package/dist/sequences-react/components/TimelineRuler.d.ts +16 -0
  255. package/dist/sequences-react/components/TimelineSmallScreenGate.d.ts +12 -0
  256. package/dist/sequences-react/components/TimelineTrackRow.d.ts +51 -0
  257. package/dist/sequences-react/components/ZoomControl.d.ts +15 -0
  258. package/dist/sequences-react/components/composite-command.d.ts +8 -0
  259. package/dist/sequences-react/components/glyphs.d.ts +26 -0
  260. package/dist/sequences-react/components/index.d.ts +31 -0
  261. package/dist/sequences-react/components/interaction-math.d.ts +103 -0
  262. package/dist/sequences-react/contracts.d.ts +187 -0
  263. package/dist/sequences-react/engine/command-stack.d.ts +18 -0
  264. package/dist/sequences-react/engine/commands.d.ts +146 -0
  265. package/dist/sequences-react/engine/playback.d.ts +18 -0
  266. package/dist/sequences-react/engine/snap.d.ts +29 -0
  267. package/dist/sequences-react/engine/zoom.d.ts +29 -0
  268. package/dist/sequences-react/index.d.ts +20 -880
  269. package/dist/sequences-react/lazy.d.ts +8 -0
  270. package/dist/sequences-react/media/frame-provider.d.ts +70 -0
  271. package/dist/sequences-react/media/transcription.d.ts +33 -0
  272. package/dist/sequences-react/media/waveform.d.ts +34 -0
  273. package/dist/session-shell/index.d.ts +31 -204
  274. package/dist/session-shell/nav-guard.d.ts +170 -0
  275. package/dist/session-shell/path.d.ts +19 -0
  276. package/dist/signoff/cli.d.ts +4 -7
  277. package/dist/signoff/config.d.ts +12 -0
  278. package/dist/signoff/exec.d.ts +44 -0
  279. package/dist/signoff/index.d.ts +56 -14
  280. package/dist/signoff/invoked-as-script.d.ts +25 -0
  281. package/dist/signoff/node-version.d.ts +50 -0
  282. package/dist/signoff/proof-attach.d.ts +88 -0
  283. package/dist/signoff/proof-cli.d.ts +1 -0
  284. package/dist/signoff/proof-fixture.d.ts +13 -0
  285. package/dist/signoff/proof-from-report.d.ts +22 -0
  286. package/dist/signoff/proof-git.d.ts +57 -0
  287. package/dist/signoff/proof-record.d.ts +202 -0
  288. package/dist/signoff/proof-verify.d.ts +103 -0
  289. package/dist/signoff/proof.d.ts +35 -310
  290. package/dist/signoff/report.d.ts +7 -0
  291. package/dist/{run-D80hoLKh.d.ts → signoff/run.d.ts} +3 -6
  292. package/dist/signoff/schedule.d.ts +55 -0
  293. package/dist/signoff/seeds.d.ts +50 -0
  294. package/dist/signoff/store.d.ts +22 -0
  295. package/dist/{types-Bd6uW9vQ.d.ts → signoff/types.d.ts} +15 -17
  296. package/dist/signoff/workflow-pin.d.ts +56 -0
  297. package/dist/signoff/workspace.d.ts +40 -0
  298. package/dist/skills/index.d.ts +28 -32
  299. package/dist/skills-placement/index.d.ts +7 -11
  300. package/dist/spend/budget.d.ts +123 -0
  301. package/dist/spend/ceiling.d.ts +51 -0
  302. package/dist/spend/cli-args.d.ts +20 -0
  303. package/dist/spend/cli.d.ts +1 -0
  304. package/dist/spend/fixtures/incident-parked-time.d.ts +55 -0
  305. package/dist/spend/index.d.ts +38 -1144
  306. package/dist/spend/liveness.d.ts +131 -0
  307. package/dist/spend/ownership.d.ts +87 -0
  308. package/dist/spend/reconcile.d.ts +109 -0
  309. package/dist/spend/reference.d.ts +42 -0
  310. package/dist/spend/report.d.ts +12 -0
  311. package/dist/spend/store.d.ts +123 -0
  312. package/dist/spend/types.d.ts +466 -0
  313. package/dist/store/index.d.ts +10 -12
  314. package/dist/stories/app-shell/fixtures.d.ts +43 -0
  315. package/dist/stories/app-shell/shell.d.ts +81 -0
  316. package/dist/stories/assistant/fixtures.d.ts +73 -0
  317. package/dist/stories/chat/fixtures.d.ts +70 -0
  318. package/dist/stories/chat/markdown.d.ts +11 -0
  319. package/dist/stories/chat/run-drill-in.d.ts +19 -0
  320. package/dist/stories/chat-controls/fixtures.d.ts +116 -0
  321. package/dist/stories/design-canvas/fixtures.d.ts +57 -0
  322. package/dist/stories/fixtures/canvas.d.ts +10 -0
  323. package/dist/stories/fixtures/catalog.d.ts +7 -0
  324. package/dist/stories/fixtures/chat.d.ts +39 -0
  325. package/dist/stories/fixtures/index.d.ts +4 -0
  326. package/dist/stories/fixtures/sequences.d.ts +17 -0
  327. package/dist/stories/panels/fixtures.d.ts +63 -0
  328. package/dist/stories/sequences/fixtures.d.ts +30 -0
  329. package/dist/stories/studio/fixtures.d.ts +22 -0
  330. package/dist/stream/index.d.ts +10 -56
  331. package/dist/{stream-normalizer-DKRxyVlZ.d.ts → stream/stream-normalizer.d.ts} +23 -26
  332. package/dist/{turn-buffer-COMQUwO2.d.ts → stream/turn-buffer.d.ts} +21 -23
  333. package/dist/stream/turn-identity.d.ts +49 -0
  334. package/dist/studio/generation.d.ts +179 -0
  335. package/dist/studio/index.d.ts +12 -181
  336. package/dist/studio-react/avatar-composer.d.ts +8 -0
  337. package/dist/studio-react/composer-hero.d.ts +12 -0
  338. package/dist/studio-react/composer-shell.d.ts +18 -0
  339. package/dist/studio-react/generation-card.d.ts +9 -0
  340. package/dist/studio-react/generation-detail-modal.d.ts +11 -0
  341. package/dist/studio-react/generation-detail.d.ts +6 -0
  342. package/dist/studio-react/generation-grid.d.ts +15 -0
  343. package/dist/studio-react/image-composer.d.ts +8 -0
  344. package/dist/studio-react/index.d.ts +32 -245
  345. package/dist/studio-react/library-drawer.d.ts +12 -0
  346. package/dist/studio-react/library-panel.d.ts +15 -0
  347. package/dist/studio-react/publish-package-composer.d.ts +18 -0
  348. package/dist/studio-react/result-canvas.d.ts +6 -0
  349. package/dist/studio-react/speech-composer.d.ts +4 -0
  350. package/dist/studio-react/studio-header.d.ts +5 -0
  351. package/dist/studio-react/studio-sheet.d.ts +12 -0
  352. package/dist/studio-react/studio-workspace.d.ts +23 -0
  353. package/dist/studio-react/transcription-composer.d.ts +12 -0
  354. package/dist/studio-react/type-config.d.ts +11 -0
  355. package/dist/studio-react/use-studio-generations.d.ts +20 -0
  356. package/dist/studio-react/video-composer.d.ts +10 -0
  357. package/dist/tangle/index.d.ts +7 -9
  358. package/dist/teams/drizzle/access.d.ts +82 -0
  359. package/dist/{invitations-schema-_fI7HkJP.d.ts → teams/drizzle/invitations-schema.d.ts} +39 -27
  360. package/dist/teams/drizzle/personal-organization.d.ts +41 -0
  361. package/dist/{access-490O6aOU.d.ts → teams/drizzle/schema.d.ts} +57 -122
  362. package/dist/teams/drizzle.d.ts +12 -44
  363. package/dist/teams/index.d.ts +20 -44
  364. package/dist/teams/invitations-api.d.ts +17 -21
  365. package/dist/{invitations-DoYMvXea.d.ts → teams/invitations.d.ts} +14 -18
  366. package/dist/teams/invite.d.ts +42 -0
  367. package/dist/teams/members-api.d.ts +12 -16
  368. package/dist/teams/resend.d.ts +3 -13
  369. package/dist/{roles-B4nU3jDi.d.ts → teams/roles.d.ts} +18 -20
  370. package/dist/teams-react/components/BrandMark.d.ts +10 -0
  371. package/dist/teams-react/components/InvitationsPanel.d.ts +13 -0
  372. package/dist/teams-react/components/InviteAcceptPage.d.ts +10 -0
  373. package/dist/teams-react/components/MembersPanel.d.ts +14 -0
  374. package/dist/teams-react/components/RoleSelect.d.ts +17 -0
  375. package/dist/teams-react/components/index.d.ts +3 -0
  376. package/dist/teams-react/contracts.d.ts +134 -0
  377. package/dist/teams-react/index.d.ts +12 -143
  378. package/dist/teams-react/lazy.d.ts +11 -11
  379. package/dist/test-setup.d.ts +1 -0
  380. package/dist/theme/index.d.ts +6 -104
  381. package/dist/theme/tailwind-preset.d.ts +1 -2
  382. package/dist/theme/theme.d.ts +106 -0
  383. package/dist/theme-contract/cli.d.ts +21 -0
  384. package/dist/theme-contract/index.d.ts +4 -6
  385. package/dist/{auth-BYtiazA4.d.ts → tools/auth.d.ts} +8 -11
  386. package/dist/tools/capability.d.ts +54 -0
  387. package/dist/tools/dispatch.d.ts +37 -0
  388. package/dist/tools/errors.d.ts +8 -0
  389. package/dist/tools/gating.d.ts +62 -0
  390. package/dist/tools/http.d.ts +27 -0
  391. package/dist/tools/index.d.ts +12 -217
  392. package/dist/{mcp-rpc-DYwPlYbZ.d.ts → tools/mcp-rpc.d.ts} +7 -9
  393. package/dist/{mcp-xxoZZfor.d.ts → tools/mcp.d.ts} +14 -16
  394. package/dist/tools/openai.d.ts +28 -0
  395. package/dist/tools/registry.d.ts +39 -0
  396. package/dist/tools/runtime.d.ts +22 -0
  397. package/dist/{types-B25Mib1r.d.ts → tools/types.d.ts} +15 -83
  398. package/dist/{flow-types-CJxEmaRy.d.ts → trace/flow-types.d.ts} +2 -4
  399. package/dist/trace/index.d.ts +11 -148
  400. package/dist/trace/mission-flow.d.ts +82 -0
  401. package/dist/trace/mission-trace.d.ts +52 -0
  402. package/dist/turn-health/classify.d.ts +207 -0
  403. package/dist/turn-health/index.d.ts +29 -637
  404. package/dist/turn-health/lifecycle.d.ts +75 -0
  405. package/dist/turn-health/sink.d.ts +122 -0
  406. package/dist/turn-health/sweep.d.ts +245 -0
  407. package/dist/turn-stream/adapters.d.ts +257 -0
  408. package/dist/turn-stream/core.d.ts +293 -0
  409. package/dist/turn-stream/do.d.ts +144 -0
  410. package/dist/turn-stream/index.d.ts +62 -738
  411. package/dist/turn-stream/memory.d.ts +41 -0
  412. package/dist/vault/ConfirmDialog.d.ts +22 -0
  413. package/dist/vault/VaultPane.d.ts +15 -0
  414. package/dist/{VaultPane-BDP6SB_K.d.ts → vault/contracts.d.ts} +15 -22
  415. package/dist/vault/index.d.ts +15 -22
  416. package/dist/vault/lazy.d.ts +9 -7
  417. package/dist/vault/server.d.ts +8 -10
  418. package/dist/web/free-route-limit.d.ts +187 -0
  419. package/dist/web/index.d.ts +15 -207
  420. package/dist/{rate-limit-BOVmJRXZ.d.ts → web/rate-limit.d.ts} +3 -5
  421. package/dist/web-react/agent-session-controls.d.ts +105 -0
  422. package/dist/web-react/async/async-view.d.ts +69 -0
  423. package/dist/web-react/async/index.d.ts +13 -305
  424. package/dist/web-react/async/state.d.ts +107 -0
  425. package/dist/web-react/async/use-async-resource.d.ts +41 -0
  426. package/dist/web-react/async/use-confirmed-mutation.d.ts +90 -0
  427. package/dist/web-react/brand-mark.d.ts +11 -0
  428. package/dist/web-react/chat-attachments.d.ts +21 -0
  429. package/dist/web-react/chat-composer.d.ts +174 -0
  430. package/dist/web-react/chat-interactions.d.ts +1 -0
  431. package/dist/web-react/chat-mentions.d.ts +48 -0
  432. package/dist/web-react/chat-stream.d.ts +106 -0
  433. package/dist/web-react/class-names.d.ts +10 -0
  434. package/dist/web-react/controls.d.ts +265 -0
  435. package/dist/web-react/durable-chat-cards.d.ts +40 -0
  436. package/dist/web-react/durable-interaction-submit.d.ts +22 -0
  437. package/dist/web-react/durable-plan-card.d.ts +13 -0
  438. package/dist/web-react/durable-plan-flow.d.ts +77 -0
  439. package/dist/web-react/harness-glyphs.d.ts +28 -0
  440. package/dist/web-react/index.d.ts +80 -2347
  441. package/dist/web-react/inert.d.ts +39 -0
  442. package/dist/web-react/insight-card.d.ts +203 -0
  443. package/dist/web-react/interaction-card-support.d.ts +115 -0
  444. package/dist/web-react/interaction-plan-card.d.ts +39 -0
  445. package/dist/web-react/interaction-question-card.d.ts +100 -0
  446. package/dist/web-react/message-attachments.d.ts +56 -0
  447. package/dist/web-react/mission-activity.d.ts +96 -0
  448. package/dist/web-react/motion.d.ts +43 -0
  449. package/dist/web-react/provenance-model.d.ts +195 -0
  450. package/dist/web-react/provenance.d.ts +82 -0
  451. package/dist/web-react/provider-logo.d.ts +14 -0
  452. package/dist/web-react/record-grid-model.d.ts +257 -0
  453. package/dist/web-react/record-grid.d.ts +108 -0
  454. package/dist/web-react/sandbox-terminal.d.ts +90 -0
  455. package/dist/web-react/seat-paywall.d.ts +47 -0
  456. package/dist/web-react/session-history.d.ts +196 -0
  457. package/dist/web-react/smooth-text.d.ts +29 -0
  458. package/dist/web-react/sparkline.d.ts +150 -0
  459. package/dist/web-react/terminal.d.ts +1 -92
  460. package/dist/web-react/use-chat-interactions.d.ts +78 -0
  461. package/dist/web-react/use-composer-attachments.d.ts +111 -0
  462. package/dist/web-react/use-file-mentions.d.ts +94 -0
  463. package/dist/web-react/work-product.d.ts +105 -0
  464. package/dist/work-product/claim-support.d.ts +288 -0
  465. package/dist/work-product/index.d.ts +16 -849
  466. package/dist/work-product/provenance.d.ts +61 -0
  467. package/dist/{queue-VTBA5ONX.d.ts → work-product/queue.d.ts} +10 -12
  468. package/dist/work-product/quote.d.ts +139 -0
  469. package/dist/work-product/route.d.ts +88 -0
  470. package/dist/work-product/service.d.ts +123 -0
  471. package/dist/work-product/tools.d.ts +144 -0
  472. package/dist/{types-CCeYywdS.d.ts → work-product/types.d.ts} +29 -31
  473. package/dist/work-product-react/index.d.ts +19 -8
  474. package/dist/workspace-react/index.d.ts +8 -11
  475. package/package.json +5 -4
  476. package/dist/agent-session-controls-CmlXwp_H.d.ts +0 -384
  477. package/dist/apply-6wlMOLf8.d.ts +0 -280
  478. package/dist/attachment-validation-BfJDBU1g.d.ts +0 -261
  479. package/dist/budget-BOucfcb_.d.ts +0 -142
  480. package/dist/values-C7RidJuI.d.ts +0 -156
@@ -1,1145 +1,39 @@
1
1
  /**
2
- * The vocabulary of consumer-side spend verification.
3
- *
4
- * Kept in its own module with ZERO imports so a product can type its storage
5
- * rows and its reconciliation config without pulling in `node:fs` through the
6
- * CLI half.
7
- *
8
- * The model in one paragraph: the platform's ledger is authoritative about what
9
- * was CHARGED. A product knows something the ledger does not — what it ASKED
10
- * for. Recording that second view, and diffing it against the first, is what
11
- * turns a platform billing defect from silent money into an alert. Nothing here
12
- * lets a product self-certify a charge away; the output is a discrepancy a human
13
- * disputes.
14
- */
15
- /**
16
- * One box, as the PRODUCT understands it. Folded, not an append-only log: a
17
- * product runs one row per sandbox, and every field below is derived by a
18
- * monotonic fold (see `foldSpendBoxRecord`) so two concurrent writers cannot
19
- * produce a wrong answer, only a stale one.
20
- *
21
- * Timestamps are epoch ms throughout, matching the platform's own
22
- * `sandbox_meta.last_started_at`.
23
- */
24
- interface SpendBoxRecord {
25
- /** The platform's sandbox id the join key to every settlement row. */
26
- readonly sandboxId: string;
27
- /** The product's own tenancy unit, which the platform does not model. */
28
- readonly workspaceId: string;
29
- /** First moment the product knew this box existed. */
30
- readonly createdAt: number;
31
- /**
32
- * The idle timeout the product ASKED the platform for, seconds. This is the
33
- * width of the grace window between the last thing the product saw and the
34
- * moment the platform should have stopped billing.
35
- */
36
- readonly idleTimeoutSeconds: number;
37
- /**
38
- * The maximum lifetime the product asked for, seconds, when it asked for one.
39
- * This is the strongest bound a product holds: the platform destroys the box
40
- * at `createdAt + maxLifetimeSeconds` regardless of what the product observed,
41
- * so it caps the ceiling even when nothing else can (see `computeExpectedCeiling`).
42
- */
43
- readonly maxLifetimeSeconds: number | null;
44
- /** Latest moment the product OBSERVED the box doing work. */
45
- readonly lastActivityAt: number;
46
- /**
47
- * Detached runs dispatched but never observed to finish, by run id.
48
- *
49
- * Non-empty means the product genuinely cannot bound this box from its own
50
- * observations: it handed the platform work and disconnected. The ceiling
51
- * degrades accordingly rather than pretending to a tightness it did not earn.
52
- */
53
- readonly openDetachedRunIds: readonly string[];
54
- /** When the product knows the box stopped. Cleared by later activity. */
55
- readonly stoppedAt: number | null;
56
- /** When the product knows the box was deleted. Set once — a deleted id never returns. */
57
- readonly deletedAt: number | null;
58
- /** Opaque product-column values, written verbatim and never read here. */
59
- readonly extras?: Record<string, unknown>;
60
- }
61
- /**
62
- * A fold step. Every field states its own merge rule, so a SQL implementation
63
- * can apply it in one statement and reach the same record an in-memory
64
- * read-modify-write reaches.
65
- */
66
- interface SpendBoxPatch {
67
- /** Advance `lastActivityAt` to the max of stored and this. Never moves backward. */
68
- readonly observedActivityAt?: number;
69
- /** Add a run id to `openDetachedRunIds` (set semantics — re-adding is a no-op). */
70
- readonly openDetachedRunAdd?: string;
71
- /** Remove a run id from `openDetachedRunIds`. Removing an absent id is a no-op. */
72
- readonly openDetachedRunRemove?: string;
73
- /**
74
- * Latest-wins. Activity observed AFTER a recorded stop clears it: a box that
75
- * worked after we thought it stopped is running again, and a stale stop would
76
- * make the ceiling too tight.
77
- */
78
- readonly stoppedAt?: number;
79
- /** Set-once. A later delete observation does not move the first one. */
80
- readonly deletedAt?: number;
81
- }
82
- /** Which fact bounds a box's billable time, weakest last. */
83
- type CeilingBasis =
84
- /** The product observed deletion. Billing cannot run past a box that is gone. */
85
- 'deleted'
86
- /** The product observed a stop. Billing should have closed there. */
87
- | 'stopped'
88
- /** No stop seen, but the platform destroys the box at its max lifetime. */
89
- | 'max-lifetime'
90
- /** No stop seen; the platform's idle timer is what should have closed billing. */
91
- | 'idle-timeout'
92
- /**
93
- * An unfinished detached run and no max lifetime — the product cannot bound
94
- * this box at all, so the ceiling degrades to the reconciliation instant.
95
- * A finding on this basis is weak evidence and says so.
96
- */
97
- | 'open-detached-run';
98
- /** The upper bound on one box's billable duration, and what earned it. */
99
- interface ExpectedCeiling {
100
- readonly sandboxId: string;
101
- readonly basis: CeilingBasis;
102
- /** The latest instant this box could still have been billable, epoch ms. */
103
- readonly horizonAt: number;
104
- /** `horizonAt - createdAt + toleranceMs`. The upper bound on billable ms. */
105
- readonly ceilingMs: number;
106
- readonly toleranceMs: number;
107
- /**
108
- * False when the basis is `open-detached-run` — the ceiling then rests on the
109
- * reconciliation instant rather than on anything the product observed, so an
110
- * overage means the platform billed outside the box's own lifetime, not merely
111
- * longer than expected.
112
- */
113
- readonly bounded: boolean;
114
- }
115
- /**
116
- * One settled ledger row, in the shape the platform's `credit_transactions`
117
- * table stores it. The product supplies these through its own fetch (the
118
- * platform's credit-history API, an export, a mirror) — this package never
119
- * reaches for them, because the ledger is the counterparty's record and reading
120
- * it is the product's authenticated business.
121
- *
122
- * The rows a product can fetch are scoped to the BILLING OWNER, not to the
123
- * product: `product: 'sandbox'` is the platform's service taxonomy and every
124
- * consumer app's compute wears it. So a wallet running two of our products
125
- * returns both products' settlements, and telling them apart is
126
- * {@link SpendOwnershipRule}'s job.
127
- */
128
- interface SettlementRow {
129
- /** The ledger row id, for the dispute. */
130
- readonly id: string;
131
- /**
132
- * `sandbox:<kind>:<sandboxId>:<intervalStartMs>` — the platform's idempotency
133
- * key, and the only place the billed interval's START is recorded.
134
- */
135
- readonly referenceId: string | null;
136
- /**
137
- * Signed nanodollars, exactly as the ledger stores it: negative is a charge,
138
- * positive is a credit or refund.
139
- */
140
- readonly amountNanoUsd: number;
141
- /** `compute` | `refund` | `inference` | … */
142
- readonly type: string;
143
- /** `sandbox` | `router` | … */
144
- readonly product: string | null;
145
- /** `sandbox:<sandboxId>` — the platform's aggregation unit. */
146
- readonly groupKey: string | null;
147
- /** Settlement instant, epoch ms. The product normalizes the stored text. */
148
- readonly createdAt: number;
149
- readonly description: string | null;
150
- /** Provider at-cost basis, unsigned nanodollars. Null when unattributed. */
151
- readonly costBasisNanoUsd: number | null;
152
- /**
153
- * The billed duration, when the product's ledger view exposes it directly.
154
- * Null is the common case: the platform does not store duration on the row.
155
- */
156
- readonly billedMs: number | null;
157
- /**
158
- * The platform API key the charge was triggered by — `credit_transactions.key_id`,
159
- * stamped from the box's own creation metadata at settlement time and exposed
160
- * by `/v1/billing/transactions` (which also filters on it).
161
- *
162
- * This is the ONLY field on a settlement row that can be attributed back to a
163
- * PRODUCT rather than to a wallet or to the platform's service taxonomy, which
164
- * is why {@link SpendOwnershipRule}'s shipped constructor is built on it. The
165
- * sandbox id cannot do the job: the platform mints it as `sandbox-<12 hex>`
166
- * from a hash of (owner, idempotency key), so a product's own box naming never
167
- * reaches the ledger row.
168
- *
169
- * Optional, and `null` is a real answer: the platform leaves it null on legacy
170
- * rows and an export may not carry the column at all. A missing key is
171
- * `undecidable`, never `foreign` — see {@link SpendOwnershipVerdict}.
172
- */
173
- readonly keyId?: string | null;
174
- }
175
- /**
176
- * What one settlement is attributable to, from inside ONE product.
177
- *
178
- * The distinction this type exists for: a sibling product's box and a charge
179
- * that is not ours at all look identical from inside a single product, because
180
- * both arrive as a settlement naming a sandbox this product's expectation ledger
181
- * has never heard of. Dropping both loses the check's whole purpose; reporting
182
- * both makes it noise. Only a platform-stamped attribution field separates them.
183
- */
184
- type SpendOwnershipVerdict =
185
- /** Attributable to THIS product. An unrecorded one is a phantom-charge candidate. */
186
- 'mine'
187
- /** Attributable to a DIFFERENT product on the same wallet. Reported, never a finding. */
188
- | 'foreign'
189
- /**
190
- * The row carries nothing that decides it. Counted as `mine` — FAIL CLOSED.
191
- * An unattributable charge on a shared wallet is precisely the shape of the
192
- * thing this module exists to catch, so the ambiguous case costs a human five
193
- * minutes rather than costing the product the detection.
194
- */
195
- | 'undecidable';
196
- /** One settlement, presented to an ownership rule. */
197
- interface SpendOwnershipCandidate {
198
- readonly row: SettlementRow;
199
- /** The sandbox the row is attributable to, or null for a row naming none. */
200
- readonly sandboxId: string | null;
201
- }
202
- /**
203
- * The product's declaration of which settlements are its own.
204
- *
205
- * The one hard constraint on `decide`: it must answer from PROPERTIES OF THE
206
- * ROW. A rule that answers by looking the sandbox up in the product's own
207
- * expectation ledger deletes `unknown-box` entirely — every unrecorded box would
208
- * be `foreign` by construction, and "we were billed for a box we never asked
209
- * for" would become unrepresentable. The ledger already decides recorded-ness;
210
- * this decides ATTRIBUTION, and the two must stay independent.
211
- *
212
- * `decide` must not throw. If it does, the throw propagates and the whole pass
213
- * fails — a reconciliation whose ownership rule is broken has no verdict worth
214
- * printing, and swallowing it would turn a broken rule into a clean bill.
215
- */
216
- interface SpendOwnershipRule {
217
- /** Named in the report and on every finding, so a reader knows what was excluded. */
218
- readonly label: string;
219
- decide(candidate: SpendOwnershipCandidate): SpendOwnershipVerdict;
220
- }
221
- /**
222
- * What this pass scoped itself to — present on every report, including a clean
223
- * one, because "nothing fired" and "nothing was looked at" are different
224
- * answers and a report that cannot tell them apart is the failure this closes.
225
- */
226
- interface SpendOwnershipSummary {
227
- /**
228
- * False when the caller declared no rule. The pass then treats every box as
229
- * its own — today's behaviour, which over-reports rather than under-reports —
230
- * and every `unknown-box` finding says on its face that a sibling product's
231
- * box is indistinguishable from a charge that is not ours.
232
- */
233
- readonly declared: boolean;
234
- /** The rule's label, or null when none was declared. */
235
- readonly label: string | null;
236
- /** Boxes this pass treated as this product's, and what they were charged. */
237
- readonly ownedBoxes: number;
238
- readonly ownedNanoUsd: number;
239
- /**
240
- * Of those, the boxes no rule could decide. Counted as owned (fail-closed) and
241
- * reported separately so a product can see how much of its own verdict rests
242
- * on rows that carried no attribution.
243
- */
244
- readonly undecidableBoxes: number;
245
- /** Boxes attributed to another product on the same wallet. Never findings. */
246
- readonly foreignBoxes: number;
247
- readonly foreignNanoUsd: number;
248
- /**
249
- * Their ids, in full — an exclusion a reader cannot audit is an exclusion
250
- * they have to trust, and this module's whole posture is that nothing about
251
- * money is taken on trust.
252
- */
253
- readonly foreignSandboxIds: readonly string[];
254
- }
255
- /**
256
- * The stretch of time a reconciliation pass covers — the same window the
257
- * product's own ledger fetch was scoped to.
258
- *
259
- * Declared by the caller rather than derived from the rows, because deriving it
260
- * from the rows is circular: a feed that returns nothing would produce a
261
- * zero-width window that expects nothing and certifies itself.
262
- */
263
- interface SpendWindow {
264
- /** Inclusive start, epoch ms. */
265
- readonly startAt: number;
266
- /** Inclusive end, epoch ms. */
267
- readonly endAt: number;
268
- }
269
- /**
270
- * One box's life, measured against a reconciliation window.
271
- *
272
- * The live interval is `[createdAt, horizon]`, where the horizon is the SAME one
273
- * `computeExpectedCeiling` derives — so a box cannot count as live for the
274
- * expectation check and dead for the ceiling check.
275
- */
276
- interface SpendBoxLiveness {
277
- readonly sandboxId: string;
278
- readonly workspaceId: string;
279
- /** First instant the box could have been billable. */
280
- readonly liveFrom: number;
281
- /** Last instant it could have been, evaluated at the window's end. */
282
- readonly liveUntil: number;
283
- /** Which fact closed the interval — the ceiling's own vocabulary. */
284
- readonly basis: CeilingBasis;
285
- /** True when any of that life fell inside the window. */
286
- readonly overlaps: boolean;
287
- /** How much of it did, in ms. Zero for a box that did not overlap. */
288
- readonly liveMsInWindow: number;
289
- /**
290
- * True when the overlap is long enough that a settlement should have landed.
291
- * A box that came up moments before the window closed is live but not yet
292
- * expected — settlement lags provisioning, and demanding a row inside that lag
293
- * would report the platform's ordinary queue as a defect.
294
- */
295
- readonly expectSettlement: boolean;
296
- }
297
- /**
298
- * What this pass EXPECTED to be billed for — present on every report, including
299
- * a clean one, for the same reason {@link SpendOwnershipSummary} is: "nothing
300
- * fired" and "nothing was expected" and "nothing could be expected" are three
301
- * different answers and a report that cannot tell them apart is the failure this
302
- * closes.
303
- */
304
- interface SpendExpectationSummary {
305
- /**
306
- * False when the caller declared no window, or the store cannot list its
307
- * boxes. The pass then cannot say what it expected — which is reported, never
308
- * rounded down to a clean bill.
309
- */
310
- readonly declared: boolean;
311
- readonly window: SpendWindow | null;
312
- /** Live ms inside the window before a settlement is expected of a box. */
313
- readonly graceMs: number;
314
- /** Boxes whose life overlapped the window at all. */
315
- readonly liveBoxes: number;
316
- /** Of those, the ones live long enough that a settlement should have landed. */
317
- readonly expectedBoxes: number;
318
- /** Of those, the ones at least one settlement this pass claimed did land against. */
319
- readonly settledBoxes: number;
320
- /**
321
- * The expected boxes nothing settled against, in full — the exhibit list for
322
- * "the check stopped checking", and an expectation a reader cannot audit is
323
- * one they have to take on trust.
324
- */
325
- readonly unsettledSandboxIds: readonly string[];
326
- }
327
- /**
328
- * How much this pass is entitled to claim about the bill.
329
- *
330
- * `ok` is gated on this, which is what makes an examined-nobody pass
331
- * structurally incapable of rendering as a clean bill.
332
- */
333
- type SpendCoverage =
334
- /** The pass examined this product's settlements, or knows what it expected. */
335
- 'verified'
336
- /**
337
- * Expectation was declared and no box was live long enough to expect a bill.
338
- * Zero settlements is the RIGHT answer — an idle product, not a defect, and
339
- * the one case in which a pass that examined nobody is still clean.
340
- */
341
- | 'nothing-expected'
342
- /**
343
- * The pass examined none of this product's settlements and cannot say what it
344
- * expected. The CHECK is suspect, not the bill.
345
- */
346
- | 'unverified';
347
- /** The parts of a settlement reference id, once parsed. */
348
- interface SettlementReference {
349
- /** `stop` | `compute` | `egress` | `gpu-lease` | anything the platform adds. */
350
- readonly kind: string;
351
- /** For compute kinds, the sandbox id. For `gpu-lease`, the lease id. */
352
- readonly resourceId: string;
353
- /** The interval's start, epoch ms. Null for kinds that carry no interval. */
354
- readonly intervalStartMs: number | null;
355
- }
356
- /** How a settled duration was arrived at — every duration finding carries one. */
357
- type BilledDurationBasis =
358
- /** The ledger row carried the duration. Exact. */
359
- 'reported'
360
- /** `amount ÷ the product's stated hourly rate`. Exact when the rate is right. */
361
- | 'rate'
362
- /**
363
- * `settledAt - intervalStart`. An UPPER bound, not the billed duration: a
364
- * correct settlement posted late by the platform's durable settlement queue
365
- * reads longer here than it billed. Findings on this basis say so.
366
- */
367
- | 'reference-span'
368
- /** No basis available — duration rules are skipped for this row. */
369
- | 'unknown';
370
- /** The checks this reconciler runs. Each is individually skippable, by name. */
371
- type SpendCheckId =
372
- /** A settlement against a box the product has no record of ever asking for. */
373
- 'unknown-box'
374
- /** A settled duration longer than the product's own upper bound allows. */
375
- | 'over-ceiling'
376
- /** A spend window far above the trailing median — the burst shape of a defect. */
377
- | 'velocity'
378
- /** The balance the product observes has gone below its floor. */
379
- | 'negative-balance'
380
- /**
381
- * The product expected settlements and saw none — the only check whose
382
- * subject is the CHECK rather than the bill.
383
- *
384
- * Every other rule is driven by a settlement row, so all of them go quiet
385
- * together when the rows stop arriving: an empty ledger fetch, a stale
386
- * ownership rule that excludes every box, an expectation ledger naming
387
- * nobody. This is the rule that fires when the others cannot, and it reads as
388
- * "do not trust this report" rather than "dispute this charge".
389
- */
390
- | 'silent-ledger';
391
- declare const SPEND_CHECKS: readonly SpendCheckId[];
392
- /**
393
- * One discrepancy, with every number the rule compared.
394
- *
395
- * Nullable fields are per-check and deliberately present-but-null rather than
396
- * absent: a reader scanning a JSON dump can tell "this rule does not measure
397
- * that" from "that measurement is missing".
398
- */
399
- interface SpendFinding {
400
- readonly check: SpendCheckId;
401
- /** What is wrong, in one sentence, with the numbers in it. */
402
- readonly message: string;
403
- /** What to do about it. A finding without a remedy is a complaint. */
404
- readonly remedy: string;
405
- readonly sandboxId: string | null;
406
- readonly workspaceId: string | null;
407
- /** The ledger rows that evidence this finding — the dispute's exhibit list. */
408
- readonly referenceIds: readonly string[];
409
- /** Nanodollars this finding puts in question, unsigned. */
410
- readonly settledNanoUsd: number;
411
- /** `over-ceiling` — the duration actually settled, and how that was derived. */
412
- readonly settledMs: number | null;
413
- readonly durationBasis: BilledDurationBasis | null;
414
- /** `over-ceiling` — the bound it broke, and what earned that bound. */
415
- readonly ceilingMs: number | null;
416
- readonly overageMs: number | null;
417
- readonly ceilingBasis: CeilingBasis | null;
418
- /** `velocity` — the window, its trailing median, and the ratio between them. */
419
- readonly windowNanoUsd: number | null;
420
- readonly trailingMedianNanoUsd: number | null;
421
- readonly velocityRatio: number | null;
422
- /** `velocity` and `silent-ledger` — the window the finding is about. */
423
- readonly windowStartAt: number | null;
424
- readonly windowEndAt: number | null;
425
- /** `negative-balance` — the observed balance and the floor it broke. */
426
- readonly balanceNanoUsd: number | null;
427
- readonly balanceFloorNanoUsd: number | null;
428
- /** `silent-ledger` — how many boxes were expected to settle, and how many did. */
429
- readonly expectedBoxes: number | null;
430
- readonly settledBoxes: number | null;
431
- /** `silent-ledger`, per-box form — how long that box was live inside the window. */
432
- readonly liveMsInWindow: number | null;
433
- }
434
- /** What one reconciliation pass concluded. */
435
- interface SpendReport {
436
- /**
437
- * True when nothing fired AND the pass earned the right to say so:
438
- * `findings.length === 0 && coverage !== 'unverified'`.
439
- *
440
- * The second half is not decoration. Every rule but `silent-ledger` is driven
441
- * by a settlement row, so a pass that read no rows — an empty ledger fetch, a
442
- * stale ownership rule excluding every box, an expectation ledger naming
443
- * nobody — fires nothing and used to report a clean bill. `coverage` is what
444
- * makes that shape unrepresentable, and it holds even when a caller skips the
445
- * `silent-ledger` check: the skip removes the finding, never the verdict.
446
- */
447
- readonly ok: boolean;
448
- /** How much this pass is entitled to claim. See {@link SpendCoverage}. */
449
- readonly coverage: SpendCoverage;
450
- readonly findings: readonly SpendFinding[];
451
- readonly checksRun: readonly SpendCheckId[];
452
- /** Rows the pass read, including the ones no rule looked at. */
453
- readonly rowsExamined: number;
454
- /** Distinct boxes those rows settled against. */
455
- readonly boxesExamined: number;
456
- /** Total charged across every examined row, unsigned nanodollars. */
457
- readonly settledNanoUsd: number;
458
- /** Total credited back across every examined row, unsigned nanodollars. */
459
- readonly creditedNanoUsd: number;
460
- /** What this pass claimed as its own, and what it excluded as another product's. */
461
- readonly ownership: SpendOwnershipSummary;
462
- /** What this pass expected to be billed for, and what did not arrive. */
463
- readonly expectation: SpendExpectationSummary;
464
- /** The instant the pass treated as "now". */
465
- readonly asOf: number;
466
- }
467
-
468
- /**
469
- * Which settlements belong to the product running the reconciliation.
470
- *
471
- * ## The problem this module is the answer to
472
- *
473
- * A product fetches its settled rows from `/v1/billing/transactions`, scoped to
474
- * the BILLING OWNER — the wallet whose key paid. `product: 'sandbox'` narrows
475
- * that to compute, but `sandbox` is the PLATFORM's service taxonomy: every
476
- * consumer app's box compute wears it. So a Tangle account running two of our
477
- * products hands each product's reconciliation the other product's boxes, and
478
- * `unknown-box` — correctly, by its own rule — reports one finding per sibling
479
- * box. Two products on one wallet make each other's spend check useless.
480
- *
481
- * ## Why the obvious fix is the wrong fix
482
- *
483
- * The obvious fix is to reconcile only the boxes already in the product's
484
- * expectation ledger. That removes the false findings and removes the check:
485
- * `unknown-box` exists to catch "we were billed for a box we never asked for",
486
- * which is the 2026-08-05 incident's day-one signature and the ONLY thing a
487
- * product with no lifecycle bookkeeping can catch at all. Filtering to the
488
- * ledger makes a phantom charge unrepresentable — the ledger's own contents
489
- * would define the answer.
490
- *
491
- * So the residue — settlements against boxes with no ledger record — has to be
492
- * SPLIT, not dropped. A sibling's box and a phantom charge are indistinguishable
493
- * unless something outside the product's own bookkeeping tells them apart.
494
- *
495
- * ## What can tell them apart
496
- *
497
- * Exactly one field on a settlement row, and it is not the sandbox id. The
498
- * platform mints that id as `sandbox-<12 hex>` — a hash of (owner, idempotency
499
- * key) — so a product's own box naming never reaches the ledger row, and the
500
- * charge's `description` carries only the resource spec. What does survive is
501
- * `credit_transactions.key_id`: the platform API key the box was created under,
502
- * stamped from the box's own creation metadata at settlement and filterable on
503
- * the transactions endpoint. Each product deploys with its own key, so the key
504
- * is the product's billing identity as the PLATFORM recorded it — not as the
505
- * product asserts it after the fact.
506
- *
507
- * That asymmetry is what makes the split safe. A product cannot widen its own
508
- * claim by claiming; it can only recognise a stamp the platform already wrote.
509
- *
510
- * ## The three rules that keep the detection intact
511
- *
512
- * 1. **A recorded box is never excluded.** Ownership is consulted only for
513
- * boxes with no ledger record. A rule that is wrong or over-narrow therefore
514
- * cannot hide an `over-ceiling` finding on a box the product recorded — the
515
- * incident's own 23 findings survive any rule at all.
516
- * 2. **Undecidable fails closed.** A row with no key attribution is `mine`, so
517
- * an unattributable charge on a shared wallet is reported. Silence is never
518
- * the answer to "I don't know."
519
- * 3. **A box is claimed if ANY of its rows claims it.** The fold is
520
- * `mine > undecidable > foreign`, which is the module's standing asymmetry:
521
- * every derivation error pushes toward a false alarm, never toward a missed
522
- * charge.
523
- */
524
- /**
525
- * Claim every settlement the platform stamped with one of these API keys.
526
- *
527
- * The shipped rule, because it is the only one built on a field the PLATFORM
528
- * writes. Give each product its own platform key and this separates them
529
- * exactly; give two products the same key and no consumer-side rule can tell
530
- * them apart, because after settlement there is nothing left that differs — the
531
- * fix then is a second key, not a cleverer predicate.
532
- *
533
- * A row with no `keyId` (a legacy row, or an export that drops the column) is
534
- * `undecidable`, never `foreign`: the absence of an attribution is not evidence
535
- * that the charge is someone else's.
536
- *
537
- * @param keyIds The product's own platform API key ids. Must be non-empty — a
538
- * rule that owns nothing would classify every settlement as another product's
539
- * and report a clean bill for an account nobody is checking.
540
- */
541
- declare function ownedByBillingKeys(keyIds: readonly string[]): SpendOwnershipRule;
542
- /**
543
- * One box's verdict, folded over every row that settled against it.
544
- *
545
- * `mine` wins over `undecidable`, which wins over `foreign`: it takes one row
546
- * attributable to this product to make the box this product's problem, and one
547
- * unattributable row to stop the box being excluded. Both directions push
548
- * toward reporting, which is the only direction that cannot lose money.
549
- *
550
- * Exported because a product auditing its own scoping wants the same answer the
551
- * reconciler reached, not a re-derivation of it.
552
- */
553
- declare function decideBoxOwnership(rule: SpendOwnershipRule, sandboxId: string, rows: readonly SettlementRow[]): SpendOwnershipVerdict;
554
-
555
- /**
556
- * Expectation liveness: what the product BELIEVES it should have been billed for.
557
- *
558
- * ## The hole this closes
559
- *
560
- * `reconcileSpend` compares settlements against expectations, and every one of
561
- * its rules is driven by a settlement row. That makes it able to answer exactly
562
- * one direction of the question:
563
- *
564
- * > were we billed for something we did not ask for, or for more than allowed?
565
- *
566
- * It cannot answer the other direction — *were we NOT billed for something we
567
- * DID ask for* — because with no row there is nothing to iterate. Three real
568
- * shapes fall straight through that hole and every one of them renders as a
569
- * clean bill:
570
- *
571
- * - the expectation ledger names no box, so the pass examines nobody → `ok:true`;
572
- * - the billing endpoint quietly starts returning zero rows → `ok:true`,
573
- * `rowsExamined:0`;
574
- * - a stale or rotated key list excludes every box → `ok:true` with everything
575
- * `foreign`.
576
- *
577
- * In all three the check stopped checking while looking green. That is the exact
578
- * failure class the module exists to prevent, reproduced inside the module.
579
- *
580
- * ## The discriminator, and why it is not a new store
581
- *
582
- * The expectation ledger already records the only fact needed: when the product
583
- * first saw a box (`createdAt`), the last work it observed (`lastActivityAt`),
584
- * and any stop or delete it knows about. Those are precisely the inputs
585
- * {@link computeExpectedCeiling} already folds into a horizon — the latest
586
- * instant a box could still have been billable. So a box's LIVE INTERVAL is
587
- * `[createdAt, horizon]`, derived from the same fold the ceiling uses rather
588
- * than from a second, drift-prone definition of "running".
589
- *
590
- * A box whose live interval overlaps the reconciliation window is a box the
591
- * product expected to be billed for. The absence of a settlement against it is
592
- * then a first-class outcome, not silence.
593
- *
594
- * ## Why the grace period is load-bearing
595
- *
596
- * Settlement lags provisioning. A box that came up ninety seconds before the
597
- * window closed has no settlement yet and never should have — expecting one
598
- * would manufacture a finding out of the platform's ordinary queue behaviour.
599
- * So expectation is asserted only for boxes with at least
600
- * {@link DEFAULT_EXPECTATION_GRACE_MS} of live time INSIDE the window, which is
601
- * the platform's own declared-normal settlement lag (see the constant).
602
- *
603
- * The asymmetry the rest of the module runs on holds here too, but it points the
604
- * other way and that is deliberate: an over-tight liveness derivation produces a
605
- * false ALARM about the check, never a false clean bill. Nothing in this file
606
- * can make a report cleaner than it would otherwise be.
607
- */
608
- /**
609
- * How much live time a box needs inside the window before a settlement is
610
- * EXPECTED for it. 15 minutes.
611
- *
612
- * Same number and same justification as {@link DEFAULT_CEILING_TOLERANCE_MS},
613
- * arrived at from the other side: the platform's runbook clears a compute
614
- * settlement incident when `/health computeSettlement.oldestAgeSeconds` is "back
615
- * under 900", so 900 s is lag the platform has already declared normal. A box
616
- * live for less than that inside the window may legitimately have settled
617
- * nothing yet, and demanding a row for it would report the platform's own queue
618
- * as a defect.
619
- *
620
- * A caller parameter, because a product reconciling a very short window must
621
- * shrink it or the window expects nothing at all.
622
- */
623
- declare const DEFAULT_EXPECTATION_GRACE_MS = 900000;
624
- /** Options for {@link boxLivenessInWindow}. */
625
- interface BoxLivenessOptions {
626
- /** Live ms inside the window before a settlement is expected. Default {@link DEFAULT_EXPECTATION_GRACE_MS}. */
627
- readonly graceMs?: number;
628
- }
629
- /** Reject a window that cannot be reconciled, rather than examining nobody inside it. */
630
- declare function assertSpendWindow(window: SpendWindow): void;
631
- /**
632
- * One box's live interval, and whether the product should have been billed for
633
- * it inside this window.
634
- *
635
- * The live interval's end is {@link computeExpectedCeiling}'s horizon evaluated
636
- * at the window's end — the SAME derivation the ceiling check uses, so a box
637
- * cannot be considered live here and dead there. `toleranceMs` is zero because
638
- * tolerance is slack allowed to the PLATFORM's clock, and widening a box's life
639
- * by it would expect settlements for boxes that were already gone.
640
- */
641
- declare function boxLivenessInWindow(record: SpendBoxRecord, window: SpendWindow, options?: BoxLivenessOptions): SpendBoxLiveness;
642
- /** Why {@link assessAllExcluded} answered the way it did. */
643
- type AllExcludedBasis =
644
- /** Not every box was excluded — the pass examined some of this product's own. */
645
- 'not-all-excluded'
646
- /** Boxes of this product's were live in the window, so an all-foreign pass is wrong. */
647
- | 'expected-boxes-live'
648
- /** Expectation was declared and nothing was live: an idle product, not a defect. */
649
- | 'nothing-expected'
650
- /** No expectation was declared, so the question cannot be answered. Fails closed. */
651
- | 'not-declared';
652
- /** {@link assessAllExcluded}'s verdict, with the reason a pager message needs. */
653
- interface AllExcludedAssessment {
654
- /** True when the caller should raise. */
655
- readonly pathological: boolean;
656
- readonly basis: AllExcludedBasis;
657
- /** One sentence naming the numbers behind the verdict. */
658
- readonly reason: string;
659
- }
660
- /**
661
- * Should "we saw settlements but none of them were ours" page a human?
662
- *
663
- * Consumers raise this pathology on `boxesExamined > 0 && ownedBoxes === 0`.
664
- * That shape has two completely different causes and the naive test cannot tell
665
- * them apart:
666
- *
667
- * - an ownership rule that has gone stale — a rotated key, a new deployment key
668
- * nobody added — so every one of the product's OWN boxes now reads as a
669
- * sibling's. The check has stopped checking.
670
- * - a product that was legitimately idle while a sibling settled on the same
671
- * wallet. Nothing is wrong, and paging on it pages EVERY day the product is
672
- * quiet, which is how a real alert gets muted.
673
- *
674
- * The discriminator is expectation liveness: did this product have a box alive
675
- * during the window? Only then is an all-excluded pass pathological.
676
- *
677
- * Fails closed when no expectation was declared — that is today's behaviour, and
678
- * a pass that cannot answer the question must not answer it optimistically. The
679
- * `reason` says so, and the fix (declare `window`, implement `listLiveBetween`)
680
- * is in the string a human reads.
681
- */
682
- declare function assessAllExcluded(report: SpendReport): AllExcludedAssessment;
683
- /** The expectation summary a pass that declared none reports. Loud, never absent. */
684
- declare function undeclaredExpectation(graceMs: number): SpendExpectationSummary;
685
-
686
- /**
687
- * Persistence seam for the expectation ledger — the product implements it over
688
- * its own tables.
689
- *
690
- * Deliberately NOT compare-and-set, unlike `MissionStorePort`. A mission has one
691
- * serialized owner and a lost write corrupts a state machine; a box record is a
692
- * MONOTONIC FOLD (activity takes a max, a detached-run id joins or leaves a set,
693
- * delete is set-once) so concurrent writers converge no matter what order they
694
- * land in. The worst a lost race can do here is leave `lastActivityAt` behind
695
- * the truth — which makes the derived ceiling TIGHTER, so the failure mode is a
696
- * false alarm a human dismisses, never a missed charge. That asymmetry is the
697
- * whole reason the fold is shaped this way.
698
- *
699
- * `update` returns null when the row does not exist, never a throw.
700
- */
701
- interface SpendLedgerStorePort {
702
- load(sandboxId: string): Promise<SpendBoxRecord | null>;
703
- /** `extras` are the opaque product-column values — write them in the SAME
704
- * statement as the record, or ignore them if the table has no extra columns. */
705
- insert(record: SpendBoxRecord, extras?: Record<string, unknown>): Promise<SpendBoxRecord>;
706
- update(sandboxId: string, patch: SpendBoxPatch): Promise<SpendBoxRecord | null>;
707
- /**
708
- * OPTIONAL — every box that could have been live during the window.
709
- *
710
- * This is the one capability that lets a reconciliation answer "were we NOT
711
- * billed for something we DID ask for". Without it the pass is driven entirely
712
- * by settlement rows, so a feed that returns nothing fires nothing and reads
713
- * as a clean bill. Omitting it is safe and additive: the pass reports
714
- * `expectation.declared: false` and refuses to certify a bill it could not
715
- * check (see {@link SpendReport.coverage}).
716
- *
717
- * **It may over-return.** The reconciler re-derives liveness itself with
718
- * `boxLivenessInWindow`, so a store that returns every row it has is correct,
719
- * merely slower. That is deliberate: the definition of "live" must live in one
720
- * place, not once per product's SQL. The intended predicate is the coarse one
721
- * a WHERE clause can express —
722
- *
723
- * ```sql
724
- * WHERE created_at <= :endAt AND (deleted_at IS NULL OR deleted_at >= :startAt)
725
- * ```
726
- *
727
- * — and the exact answer (idle timeout, max lifetime, stop, open detached run)
728
- * is the reconciler's.
729
- */
730
- listLiveBetween?(window: SpendWindow): Promise<readonly SpendBoxRecord[]>;
731
- }
732
- /**
733
- * Apply one fold step. Exported so a SQL implementation and an in-memory one
734
- * reach the same record, and so a product can unit-test its own store against
735
- * the canonical answer.
736
- *
737
- * The two rules worth stating out loud:
738
- *
739
- * - `observedActivityAt` only ever moves `lastActivityAt` FORWARD. A replayed
740
- * or out-of-order event cannot rewind the ceiling.
741
- * - activity later than a recorded `stoppedAt` CLEARS the stop. A box that
742
- * worked after the product thought it stopped is running again, and keeping
743
- * the stale stop would make the ceiling too tight — inventing an over-ceiling
744
- * finding out of the product's own bookkeeping rather than the platform's.
745
- */
746
- declare function foldSpendBoxRecord(record: SpendBoxRecord, patch: SpendBoxPatch): SpendBoxRecord;
747
- /** An in-memory store that also lets a test inspect and force state. */
748
- interface InMemorySpendLedgerStore extends SpendLedgerStorePort {
749
- /** Every record, insertion order. */
750
- records(): SpendBoxRecord[];
751
- /** Unguarded direct write — simulates a crash-shaped or platform-seeded row. */
752
- put(record: SpendBoxRecord): void;
753
- }
754
- /** Create an in-memory expectation ledger. Production writers use the same port. */
755
- declare function createInMemorySpendLedgerStore(): InMemorySpendLedgerStore;
756
- /** What the product tells the ledger when it first sees a box. */
757
- interface ObserveSandboxInput {
758
- readonly sandboxId: string;
759
- readonly workspaceId: string;
760
- /** The idle timeout the product asked the platform for, seconds. */
761
- readonly idleTimeoutSeconds: number;
762
- /** The max lifetime the product asked for, seconds, when it asked for one. */
763
- readonly maxLifetimeSeconds?: number | null;
764
- /** Defaults to the ledger's clock. */
765
- readonly at?: number;
766
- }
767
- interface SpendLedgerOptions {
768
- readonly store: SpendLedgerStorePort;
769
- /** Injectable clock (epoch ms). Default `Date.now`. */
770
- readonly now?: () => number;
771
- /** Product columns written verbatim on every insert. */
772
- readonly extras?: Record<string, unknown>;
773
- }
774
- /**
775
- * The recording half of spend verification: the product's own account of what
776
- * it asked the platform for.
777
- *
778
- * Every method is best-effort from the caller's point of view — a product wires
779
- * these into paths that must not fail because bookkeeping failed. They still
780
- * reject on a store error rather than swallowing it, so a caller that wants
781
- * fire-and-forget says so at the call site (`/sandbox`'s hook does).
782
- */
783
- interface SpendLedger {
784
- /**
785
- * Record that a box exists and is billable from now. Inserts on first sight,
786
- * and otherwise records activity — reuse and resume are both "the platform is
787
- * charging for this box again", and the record's own existence is what
788
- * distinguishes them, so no caller has to know which happened.
789
- */
790
- observeSandbox(input: ObserveSandboxInput): Promise<SpendBoxRecord>;
791
- /** Record that the product saw this box do work. */
792
- recordActivity(sandboxId: string, at?: number): Promise<SpendBoxRecord | null>;
793
- /**
794
- * Record that the product handed the platform work it will NOT watch finish.
795
- * Until the matching end is recorded, this box's ceiling cannot rest on
796
- * observed activity — see `computeExpectedCeiling`.
797
- */
798
- recordDetachedRunStarted(sandboxId: string, runId: string, at?: number): Promise<SpendBoxRecord | null>;
799
- /** Record that a detached run was confirmed finished. */
800
- recordDetachedRunEnded(sandboxId: string, runId: string, at?: number): Promise<SpendBoxRecord | null>;
801
- /** Record that the product knows this box stopped. */
802
- recordStopped(sandboxId: string, at?: number): Promise<SpendBoxRecord | null>;
803
- /** Record that the product knows this box was deleted. */
804
- recordDeleted(sandboxId: string, at?: number): Promise<SpendBoxRecord | null>;
805
- }
806
- /** Create the recording half over a product-supplied store. */
807
- declare function createSpendLedger(options: SpendLedgerOptions): SpendLedger;
808
-
809
- /**
810
- * Slack allowed between the product's bound and what the platform settled,
811
- * before an overage is called a discrepancy. 15 minutes.
812
- *
813
- * Not a guess: it is the platform's OWN staleness threshold for compute
814
- * settlement. Its runbook clears an incident when
815
- * `/health computeSettlement.oldestAgeSeconds` is "back under 900" — so 900 s is
816
- * the age the platform itself treats as normal settlement lag, and anything
817
- * inside it is drift the platform has already declared acceptable. Below that a
818
- * product would alert on the platform's ordinary queue behaviour; far above it
819
- * the tolerance starts eating the signal, because the idle window it must stay
820
- * well under is 3600 s in every shipped product.
821
- *
822
- * It is a caller parameter because a product that asks for a shorter idle
823
- * timeout must shrink this with it.
824
- */
825
- declare const DEFAULT_CEILING_TOLERANCE_MS = 900000;
826
- interface ComputeExpectedCeilingOptions {
827
- /** The instant the reconciliation treats as "now", epoch ms. */
828
- readonly asOf: number;
829
- /** Slack before an overage counts. Default {@link DEFAULT_CEILING_TOLERANCE_MS}. */
830
- readonly toleranceMs?: number;
831
- }
832
- /**
833
- * The upper bound on how long one box could honestly have been billable.
834
- *
835
- * The whole design constraint is that this must stay an UPPER bound under
836
- * everything the product cannot see. Three such blind spots exist, and they
837
- * pull in different directions:
838
- *
839
- * - **Platform-side suspends.** The platform can park a box the product never
840
- * hears about. That only ever REDUCES real billable time, so an upper bound
841
- * is unaffected and nothing here widens for it.
842
- * - **Detached runs.** The product dispatches work and disconnects. The box
843
- * keeps working — and billing — after the last activity the product saw, so
844
- * `lastActivityAt` understates the truth. An unfinished detached run
845
- * therefore abandons the activity-based bound entirely rather than reporting
846
- * a bound it cannot support.
847
- * - **Reconnects.** A browser or worker re-attaches and work resumes. This
848
- * needs no special case: a reconnect is recorded as activity, the fold takes
849
- * the max, and the horizon moves out on its own.
850
- *
851
- * The bound that rescues the detached case is `maxLifetimeSeconds`. The platform
852
- * destroys the box at `createdAt + maxLifetimeSeconds` no matter what anyone
853
- * observed, so a product that asks for one holds a hard bound that survives
854
- * every blind spot above. Both shipped products ask for 86 400 s, which is why
855
- * the incident — 124 to 268 hours settled against boxes with a 24-hour
856
- * lifetime — is detectable with no lifecycle bookkeeping at all.
857
- */
858
- declare function computeExpectedCeiling(record: SpendBoxRecord, options: ComputeExpectedCeilingOptions): ExpectedCeiling;
859
-
860
- /**
861
- * Parse the platform's settlement idempotency key.
862
- *
863
- * The platform mints it as `sandbox:<kind>:<resourceId>:<intervalStart>`
864
- * (`d1-usage-service.ts`), where `intervalStart` is the interval cursor in epoch
865
- * ms — the SAME `last_started_at` the settlement subtracts from to get its
866
- * billed duration. That makes this string the only place a consumer can read the
867
- * billed interval's start, because the ledger row itself stores no duration.
868
- *
869
- * Kinds seen in production: `stop` (an interval closing), `compute` (a heartbeat
870
- * claim), `egress`, `gpu-lease`. `stop` deliberately covers both a settle and a
871
- * late stop racing over the same claim, so the two derive one reference id and
872
- * the ledger's uniqueness constraint makes the overlap safe.
873
- *
874
- * Returns null for anything that is not a sandbox reference — a router
875
- * inference row, a grant, a refund — rather than guessing.
876
- */
877
- declare function parseSettlementReference(referenceId: string | null | undefined): SettlementReference | null;
878
- /**
879
- * Read the sandbox id out of the platform's aggregation key, `sandbox:<id>`.
880
- *
881
- * Distinct from the reference id: `groupKey` is the unit a billing statement
882
- * groups by and is deliberately NOT unique per row, while `referenceId` is
883
- * unique per interval. A null group key means "do not aggregate" (grants,
884
- * top-ups, refunds, transfers) and is not an error.
885
- */
886
- declare function parseSandboxGroupKey(groupKey: string | null | undefined): string | null;
887
- /**
888
- * The sandbox a settlement row is attributable to.
889
- *
890
- * The reference id wins over the group key because it is the field the platform
891
- * dedups on, so it is the one guaranteed present and correct on a compute
892
- * settlement; the group key is the fallback for rows written before a producer
893
- * stamped a reference, and for kinds whose reference names something else (a GPU
894
- * lease id, not a box).
895
- */
896
- declare function settlementSandboxId(row: SettlementRow): string | null;
897
- /** True when a row is a charge (the ledger stores charges as negative amounts). */
898
- declare function isCharge(row: SettlementRow): boolean;
899
- /** A charge's magnitude in unsigned nanodollars; 0 for credits. */
900
- declare function chargeNanoUsd(row: SettlementRow): number;
901
-
902
- interface VelocityOptions {
903
- /** Bucket width for a spend window, ms. Default 24 h. */
904
- readonly windowMs?: number;
905
- /** Fire when a window exceeds this multiple of the trailing median. Default 5. */
906
- readonly multiple?: number;
907
- /**
908
- * Windows of history required before a median means anything. Default 3.
909
- * Below this the rule stays silent, so a product's genuine first days of
910
- * usage are not reported as an anomaly.
911
- */
912
- readonly minTrailingWindows?: number;
913
- /**
914
- * A window under this never fires, whatever the ratio. Default $1.00.
915
- *
916
- * Without a floor the rule is useless: a trailing median of a tenth of a cent
917
- * makes every ordinary day a 5x outlier. $1.00 is set from the incident's own
918
- * distribution — the smallest of the eight affected wallets took $1.98, and
919
- * the two rows in the same window that were GENUINE were sub-cent. So the
920
- * floor sits above the noise and below every real finding.
921
- */
922
- readonly minAbsoluteNanoUsd?: number;
923
- }
924
- /** The balance the product observes, and the floor it must not cross. */
925
- interface ObservedBalance {
926
- /** Signed nanodollars, as the platform reports it. */
927
- readonly nanoUsd: number;
928
- /** Below this is a finding. Default 0. */
929
- readonly floorNanoUsd?: number;
930
- }
931
- /**
932
- * A box's price, nanodollars per hour, used to derive an EXACT billed duration
933
- * from a charge. Return null when the product does not know the box's rate; the
934
- * reconciler then falls back to the reference span.
935
- */
936
- type BoxRateResolver = (record: SpendBoxRecord | null, sandboxId: string) => number | null | undefined;
937
- interface ReconcileSpendOptions {
938
- /**
939
- * Settled ledger rows, supplied by the product's own authenticated fetch.
940
- *
941
- * The fetch can only scope to a WALLET — `product: 'sandbox'` is the
942
- * platform's service taxonomy, not this product's — so on an account running
943
- * more than one of our products these rows carry the siblings' boxes too.
944
- * {@link ReconcileSpendOptions.ownership} is what separates them.
945
- */
946
- readonly rows: readonly SettlementRow[];
947
- /** The product's expectation ledger. */
948
- readonly store: SpendLedgerStorePort;
949
- /**
950
- * Which of those rows are THIS product's — see {@link SpendOwnershipRule} and
951
- * the shipped `ownedByBillingKeys`.
952
- *
953
- * Omitting it is safe and changes nothing: the pass claims every box, which is
954
- * the behaviour that shipped, and the direction that over-reports rather than
955
- * under-reports. It is not silent about it — `report.ownership.declared` is
956
- * `false`, `formatSpendReport` says so above the findings, and every
957
- * `unknown-box` finding states on its face that a sibling product's box is
958
- * indistinguishable from a charge that is not ours.
959
- *
960
- * Declaring it never weakens the ledger-backed checks: ownership is consulted
961
- * ONLY for boxes with no expectation record, so `over-ceiling` on a recorded
962
- * box fires whatever the rule says.
963
- */
964
- readonly ownership?: SpendOwnershipRule;
965
- /** Treated as "now". Default `Date.now()`. */
966
- readonly asOf?: number;
967
- /** Ceiling slack. Default {@link DEFAULT_CEILING_TOLERANCE_MS}. */
968
- readonly toleranceMs?: number;
969
- /** Box price, for the exact duration basis. A number applies to every box. */
970
- readonly nanoUsdPerHour?: number | BoxRateResolver;
971
- /** Velocity tuning, or `false` to skip the rule. */
972
- readonly velocity?: VelocityOptions | false;
973
- /** The workspace balance, when the product can see one. Omitted skips the rule. */
974
- readonly balance?: ObservedBalance;
975
- /** Stamped onto findings so an alert names the tenant. */
976
- readonly workspaceId?: string;
977
- /** Checks to leave out of this pass. */
978
- readonly skip?: readonly SpendCheckId[];
979
- /**
980
- * The stretch of time these `rows` were fetched for.
981
- *
982
- * Declaring it — together with a store that implements `listLiveBetween` — is
983
- * what lets the pass answer the direction every settlement-driven rule is
984
- * blind to: *were we NOT billed for something we DID ask for*. The expectation
985
- * ledger already holds the answer; nothing new is stored for it.
986
- *
987
- * Omitting it is additive and changes no existing finding. It is not silent:
988
- * `report.expectation.declared` is `false`, `formatSpendReport` prints
989
- * `expectation: NOT DECLARED` above the findings, and a pass that also
990
- * examined none of this product's settlements reports `coverage: 'unverified'`
991
- * and cannot render as a clean bill.
992
- */
993
- readonly window?: SpendWindow;
994
- /**
995
- * Live ms a box needs inside the window before a settlement is EXPECTED of it.
996
- * Default {@link DEFAULT_EXPECTATION_GRACE_MS} (15 min — the platform's own
997
- * declared-normal settlement lag). Shrink it for a short window.
998
- */
999
- readonly expectationGraceMs?: number;
1000
- }
1001
- /**
1002
- * Diff what the platform charged against what the product believes it asked for.
1003
- *
1004
- * Never disputes anything and never writes: the output is a report a human acts
1005
- * on. The platform's ledger stays authoritative — this only ever produces the
1006
- * evidence for a conversation with it.
1007
- */
1008
- declare function reconcileSpend(options: ReconcileSpendOptions): Promise<SpendReport>;
1009
-
1010
- /** Why provisioning was refused, with every number the decision used. */
1011
- interface ComputeBudgetRefusal {
1012
- readonly workspaceId: string;
1013
- /** The cap, unsigned nanodollars. */
1014
- readonly limitNanoUsd: number;
1015
- /** Cumulative settled compute spend for this workspace, unsigned nanodollars. */
1016
- readonly settledNanoUsd: number;
1017
- /** How far past the cap it already is. */
1018
- readonly overageNanoUsd: number;
1019
- readonly at: number;
1020
- }
1021
- /**
1022
- * Provisioning refused because the workspace is already past its compute cap.
1023
- *
1024
- * Correctable by design: every number the decision used is on the error, so a
1025
- * product can render "this workspace has spent $X of its $Y compute budget" and
1026
- * an operator can raise the cap or investigate without reading logs.
1027
- *
1028
- * This is the failure mode the module exists to produce. A platform billing
1029
- * defect that used to end in a silent negative balance now ends in provisioning
1030
- * stopping and something loud happening instead.
1031
- */
1032
- declare class ComputeBudgetExceededError extends Error {
1033
- readonly workspaceId: string;
1034
- readonly limitNanoUsd: number;
1035
- readonly settledNanoUsd: number;
1036
- readonly overageNanoUsd: number;
1037
- constructor(refusal: ComputeBudgetRefusal);
1038
- }
1039
- /**
1040
- * A per-workspace cap on sandbox compute.
1041
- *
1042
- * `/billing`'s budget primitive caps MODEL keys, and it works because the
1043
- * platform enforces the cap at the key it minted. Sandbox compute has no such
1044
- * key: a box bills the shared company wallet, so nothing upstream refuses. This
1045
- * carries the same shape to the one place a consumer can still act — the moment
1046
- * before it asks for another box.
1047
- *
1048
- * `settledNanoUsd` is a callback rather than a number because the authority is
1049
- * the platform ledger, not this package: the product reads the same rows it
1050
- * hands the reconciler. Cache it if the read is expensive; a cap is a
1051
- * coarse-grained control and a slightly stale total still refuses.
1052
- */
1053
- interface ComputeBudget {
1054
- /** The cap, unsigned nanodollars. */
1055
- readonly limitNanoUsd: number;
1056
- /** Cumulative settled compute spend for the workspace, unsigned nanodollars. */
1057
- readonly settledNanoUsd: (workspaceId: string) => Promise<number> | number;
1058
- /**
1059
- * Called on every refusal, before the error is thrown. This is the alert
1060
- * seam: a refusal nobody hears is a product that silently stopped working.
1061
- */
1062
- readonly onRefusal?: (refusal: ComputeBudgetRefusal) => void;
1063
- /** Injectable clock (epoch ms). Default `Date.now`. */
1064
- readonly now?: () => number;
1065
- }
1066
- /**
1067
- * Throw {@link ComputeBudgetExceededError} when the workspace is already past
1068
- * its cap. Returns normally — and reads nothing — when no budget is configured.
1069
- *
1070
- * Deliberately a pre-check against spend ALREADY SETTLED, not a reservation
1071
- * against spend about to happen: settlement lags provisioning by design (the
1072
- * platform's durable settlement queue), so there is no instant at which a
1073
- * consumer could hold an accurate running total. The cap therefore overshoots by
1074
- * at most the unsettled tail, which is bounded by the box's own idle timeout.
1075
- * A cap that refuses one box late is worth far more than one that cannot be
1076
- * implemented honestly.
1077
- */
1078
- declare function assertComputeBudget(budget: ComputeBudget | undefined, workspaceId: string): Promise<void>;
1079
- /**
1080
- * What `/sandbox` reports once a box is provisioned, reused or resumed.
1081
- *
1082
- * Structurally identical to `SandboxProvisionedObservation` in `/sandbox`, and
1083
- * deliberately re-declared rather than imported: `/spend` composes `/sandbox`,
1084
- * so a type import in the other direction would invert the dependency. The two
1085
- * are pinned together by a compile-time assignment in this module's tests.
1086
- */
1087
- interface SpendProvisionObservation {
1088
- readonly workspaceId: string;
1089
- readonly userId?: string;
1090
- readonly sandboxId: string;
1091
- readonly boxKey?: string | undefined;
1092
- readonly idleTimeoutSeconds: number;
1093
- readonly maxLifetimeSeconds?: number | undefined;
1094
- readonly at: number;
1095
- }
1096
- /**
1097
- * The optional seam `EnsureWorkspaceSandboxOptions.spend` and the turn
1098
- * primitives' `spend` option both accept. One object, wired in both places.
1099
- */
1100
- interface SandboxSpendSeam {
1101
- beforeProvision?(input: {
1102
- workspaceId: string;
1103
- userId?: string;
1104
- }): Promise<void> | void;
1105
- onProvisioned?(observation: SpendProvisionObservation): Promise<void> | void;
1106
- /** Synchronous by contract — it sits on the turn path. See `createSandboxSpendHooks`. */
1107
- onActivity?(input: {
1108
- sandboxId: string;
1109
- at: number;
1110
- }): void;
1111
- }
1112
- interface SandboxSpendHooksOptions {
1113
- /** Records box lifecycle. Omit to run the budget guard alone. */
1114
- readonly ledger?: SpendLedger;
1115
- /** Refuses provisioning past a cap. Omit to record alone. */
1116
- readonly budget?: ComputeBudget;
1117
- /**
1118
- * Called when RECORDING fails. Recording is best-effort — a bookkeeping
1119
- * failure must never take down the provisioning it is bookkeeping — so this
1120
- * is the only place such a failure is visible. A refusal is NOT routed here;
1121
- * refusals throw, by design.
1122
- */
1123
- readonly onError?: (error: unknown) => void;
1124
- }
1125
- /**
1126
- * Build the object to hand `ensureWorkspaceSandbox`'s `spend` option.
1127
- *
1128
- * Wiring it is the entire adoption cost: one field, and the product's boxes are
1129
- * both budget-capped and recorded.
1130
- */
1131
- declare function createSandboxSpendHooks(options: SandboxSpendHooksOptions): SandboxSpendSeam;
1132
-
1133
- /**
1134
- * Render a reconciliation for a human deciding whether to open a dispute.
1135
- *
1136
- * Every finding prints its numbers, not a summary of them: the reader's next
1137
- * action is a conversation with the platform about specific reference ids, and a
1138
- * report that made them re-derive the durations would just be re-read alongside
1139
- * the raw rows anyway.
1140
- */
1141
- declare function formatSpendReport(report: SpendReport): string;
1142
- /** The report as a plain JSON value, for an alerting pipeline. */
1143
- declare function spendReportToJson(report: SpendReport): string;
1144
-
1145
- export { type AllExcludedAssessment, type AllExcludedBasis, type BilledDurationBasis, type BoxLivenessOptions, type BoxRateResolver, type CeilingBasis, type ComputeBudget, ComputeBudgetExceededError, type ComputeBudgetRefusal, type ComputeExpectedCeilingOptions, DEFAULT_CEILING_TOLERANCE_MS, DEFAULT_EXPECTATION_GRACE_MS, type ExpectedCeiling, type InMemorySpendLedgerStore, type ObserveSandboxInput, type ObservedBalance, type ReconcileSpendOptions, SPEND_CHECKS, type SandboxSpendHooksOptions, type SandboxSpendSeam, type SettlementReference, type SettlementRow, type SpendBoxLiveness, type SpendBoxPatch, type SpendBoxRecord, type SpendCheckId, type SpendCoverage, type SpendExpectationSummary, type SpendFinding, type SpendLedger, type SpendLedgerOptions, type SpendLedgerStorePort, type SpendOwnershipCandidate, type SpendOwnershipRule, type SpendOwnershipSummary, type SpendOwnershipVerdict, type SpendProvisionObservation, type SpendReport, type SpendWindow, type VelocityOptions, assertComputeBudget, assertSpendWindow, assessAllExcluded, boxLivenessInWindow, chargeNanoUsd, computeExpectedCeiling, createInMemorySpendLedgerStore, createSandboxSpendHooks, createSpendLedger, decideBoxOwnership, foldSpendBoxRecord, formatSpendReport, isCharge, ownedByBillingKeys, parseSandboxGroupKey, parseSettlementReference, reconcileSpend, settlementSandboxId, spendReportToJson, undeclaredExpectation };
2
+ * Consumer-side spend verification: the product's own record of what it asked
3
+ * the platform for, diffed against what the platform charged.
4
+ *
5
+ * Three parts, in the order a product adopts them:
6
+ *
7
+ * 1. **Expectation ledger** (`store.ts`) — a storage-port-parameterized record
8
+ * of box lifecycle, and the upper bound on billable time it implies
9
+ * (`ceiling.ts`).
10
+ * 2. **Reconciler** (`reconcile.ts`) settled ledger rows against that record,
11
+ * producing typed findings a human disputes. Which of those rows are this
12
+ * product's at all is `ownership.ts`: the platform's settlement feed is
13
+ * scoped to a WALLET, and two of our products on one account otherwise
14
+ * report each other's boxes as discrepancies. What the product EXPECTED to be
15
+ * billed for is `liveness.ts`: every other rule is driven by a settlement
16
+ * row, so they all go quiet together when the rows stop arriving, and only an
17
+ * expectation derived from the ledger can tell an idle window from a check
18
+ * that stopped checking.
19
+ * 3. **Budget guard** (`budget.ts`) a per-workspace compute cap enforced at
20
+ * the one moment a consumer still can: before asking for another box.
21
+ *
22
+ * What this is NOT: a way for a product to certify its own charges. The
23
+ * platform's ledger stays authoritative. This produces evidence for a dispute
24
+ * and an alert when the numbers stop agreeing — nothing here writes to a ledger,
25
+ * refunds anything, or suppresses a charge.
26
+ *
27
+ * The threat model, the exact limits of what the ceiling can bound, and the
28
+ * adoption seams for tax-agent and legal-agent are in
29
+ * [`docs/spend-verification.md`](../../docs/spend-verification.md).
30
+ */
31
+ export { SPEND_CHECKS, type BilledDurationBasis, type CeilingBasis, type ExpectedCeiling, type SettlementReference, type SettlementRow, type SpendBoxLiveness, type SpendBoxPatch, type SpendBoxRecord, type SpendCheckId, type SpendCoverage, type SpendExpectationSummary, type SpendFinding, type SpendOwnershipCandidate, type SpendOwnershipRule, type SpendOwnershipSummary, type SpendOwnershipVerdict, type SpendReport, type SpendWindow, } from './types';
32
+ export { decideBoxOwnership, ownedByBillingKeys } from './ownership';
33
+ export { DEFAULT_EXPECTATION_GRACE_MS, assertSpendWindow, assessAllExcluded, boxLivenessInWindow, undeclaredExpectation, type AllExcludedAssessment, type AllExcludedBasis, type BoxLivenessOptions, } from './liveness';
34
+ export { createInMemorySpendLedgerStore, createSpendLedger, foldSpendBoxRecord, type InMemorySpendLedgerStore, type ObserveSandboxInput, type SpendLedger, type SpendLedgerOptions, type SpendLedgerStorePort, } from './store';
35
+ export { DEFAULT_CEILING_TOLERANCE_MS, computeExpectedCeiling, type ComputeExpectedCeilingOptions, } from './ceiling';
36
+ export { chargeNanoUsd, isCharge, parseSandboxGroupKey, parseSettlementReference, settlementSandboxId, } from './reference';
37
+ export { reconcileSpend, type BoxRateResolver, type ObservedBalance, type ReconcileSpendOptions, type VelocityOptions, } from './reconcile';
38
+ export { ComputeBudgetExceededError, assertComputeBudget, createSandboxSpendHooks, type ComputeBudget, type ComputeBudgetRefusal, type SandboxSpendHooksOptions, type SandboxSpendSeam, type SpendProvisionObservation, } from './budget';
39
+ export { formatSpendReport, spendReportToJson } from './report';