@coreplane/switchboard 1.252.0 → 1.254.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/dist/assets/config/config.example.yaml +54 -1
  2. package/dist/assets/deploy/cloudflare-memory/runMetricsSink.ts +31 -0
  3. package/dist/assets/deploy/cloudflare-memory/worker.ts +455 -32
  4. package/dist/assets/deploy/cloudflare-memory/wrangler.template.jsonc +12 -0
  5. package/dist/assets/deploy/profile.example.json +1 -1
  6. package/dist/assets/package-lock.json +3 -3
  7. package/dist/assets/package.json +1 -1
  8. package/dist/assets/source.json +3 -3
  9. package/dist/assets/src/core/authz/grants.ts +6 -0
  10. package/dist/assets/src/core/authz/policy.ts +19 -0
  11. package/dist/assets/src/core/budgets.ts +25 -0
  12. package/dist/assets/src/core/coordinator/contract.ts +51 -1
  13. package/dist/assets/src/core/coordinator/driver.ts +111 -11
  14. package/dist/assets/src/core/costs.ts +221 -2
  15. package/dist/assets/src/core/costsSnapshotStore.ts +22 -1
  16. package/dist/assets/src/core/memory/engine.ts +25 -4
  17. package/dist/assets/src/core/memory/types.ts +6 -2
  18. package/dist/assets/src/core/pipelineStanding.ts +294 -0
  19. package/dist/assets/src/core/plane/decide.ts +203 -0
  20. package/dist/assets/src/core/provider.ts +11 -0
  21. package/dist/assets/src/core/runEvents.ts +57 -1
  22. package/dist/assets/src/core/runFriction.ts +1 -0
  23. package/dist/assets/src/core/runLedger/transcript.ts +23 -3
  24. package/dist/assets/src/core/runMetrics.ts +237 -0
  25. package/dist/assets/src/core/runRecord.ts +61 -0
  26. package/dist/assets/src/core/runUsage.ts +41 -9
  27. package/dist/assets/src/core/ship/contract.ts +8 -15
  28. package/dist/assets/src/core/ship/coordinator.ts +150 -11
  29. package/dist/assets/src/deploy/profile.ts +16 -0
  30. package/dist/assets/web/dist/.vite/manifest.json +461 -427
  31. package/dist/assets/web/dist/assets/{AppShell-DAtHiuI6.js → AppShell-CSXDCV4x.js} +1 -1
  32. package/dist/assets/web/dist/assets/CostChart-DsuPS2g7.js +2 -0
  33. package/dist/assets/web/dist/assets/CostsPage-BuKjw3nv.js +1 -0
  34. package/dist/assets/web/dist/assets/{DeliveryPage-3ELQWM0r.js → DeliveryPage-ngPsO2to.js} +1 -1
  35. package/dist/assets/web/dist/assets/HomePage-DvxTHzPx.js +3 -0
  36. package/dist/assets/web/dist/assets/{InputMenu-C6aPpe30.js → InputMenu-BdZXnibG.js} +1 -1
  37. package/dist/assets/web/dist/assets/MetricsPage-o5fSaCTe.js +1 -0
  38. package/dist/assets/web/dist/assets/{NotFoundPage-DtE-GgTk.js → NotFoundPage-DHuWyjlq.js} +1 -1
  39. package/dist/assets/web/dist/assets/PendingTurnRow-ZYIRCCZ2.js +1 -0
  40. package/dist/assets/web/dist/assets/PlanePage-DpWfiX4C.js +1 -0
  41. package/dist/assets/web/dist/assets/{ResidentDetailPage-C9y3nbo8.js → ResidentDetailPage-DG86v39Y.js} +1 -1
  42. package/dist/assets/web/dist/assets/{ResidentsIndexPage-i1RG9e7g.js → ResidentsIndexPage-x6p689VH.js} +1 -1
  43. package/dist/assets/web/dist/assets/RunFoldRow-DG29LOTs.js +1 -0
  44. package/dist/assets/web/dist/assets/RunRoutePage-ysJBY8xQ.js +9 -0
  45. package/dist/assets/web/dist/assets/RunsIndexPage-CuzFchcn.js +1 -0
  46. package/dist/assets/web/dist/assets/{RunsTabs-YSbUu5py.js → RunsTabs-kHbbxVHx.js} +1 -1
  47. package/dist/assets/web/dist/assets/{ScheduledPage-DvYwM2TE.js → ScheduledPage-BuLmfcbG.js} +1 -1
  48. package/dist/assets/web/dist/assets/{SettingSelect-BIzAsLk1.js → SettingSelect-BfID5nF4.js} +1 -1
  49. package/dist/assets/web/dist/assets/{SettingsPage-Bo6yCyXZ.js → SettingsPage-BujWkdU_.js} +1 -1
  50. package/dist/assets/web/dist/assets/{StatusDot-CAfS1AUi.js → StatusDot-C8Bc0pTX.js} +1 -1
  51. package/dist/assets/web/dist/assets/{Tooltip-tZoum_T-.js → Tooltip-BWwJx27K.js} +1 -1
  52. package/dist/assets/web/dist/assets/{UnitRoutePage-BmdOHwNn.js → UnitRoutePage-B9kjA1AT.js} +1 -1
  53. package/dist/assets/web/dist/assets/{angular-html-BjeQZdCq.js → angular-html-C8b5YTHf.js} +1 -1
  54. package/dist/assets/web/dist/assets/{angular-ts-ZGdORrL2.js → angular-ts-C3f4WYNe.js} +1 -1
  55. package/dist/assets/web/dist/assets/{apl-DhvV_X93.js → apl-DSHxUJc3.js} +1 -1
  56. package/dist/assets/web/dist/assets/{astro-DiRSE4Ug.js → astro-BSGCCBP6.js} +1 -1
  57. package/dist/assets/web/dist/assets/{blade-D8Fr5Wvq.js → blade-DFeYrMKk.js} +1 -1
  58. package/dist/assets/web/dist/assets/{c-BwbC64D4.js → c-L_QOnFVv.js} +1 -1
  59. package/dist/assets/web/dist/assets/{chapel-DgmqRK97.js → chapel-DLQWUwhu.js} +1 -1
  60. package/dist/assets/web/dist/assets/{cobol-DJod2RNK.js → cobol-1DlMmrEO.js} +1 -1
  61. package/dist/assets/web/dist/assets/{coffee-D1Y2CgBY.js → coffee-BTB6os6N.js} +1 -1
  62. package/dist/assets/web/dist/assets/{cpp-CsO97YOM.js → cpp-BvJI2z3u.js} +1 -1
  63. package/dist/assets/web/dist/assets/{crystal-CJ7m2tOc.js → crystal-B11wGW_h.js} +1 -1
  64. package/dist/assets/web/dist/assets/{css-B2M-NKoj.js → css-BiIWx5Pw.js} +1 -1
  65. package/dist/assets/web/dist/assets/{dist-DfbEpHXR.js → dist-CpnyQGOb.js} +2 -2
  66. package/dist/assets/web/dist/assets/{edge-CFVW-m9B.js → edge-nSglEXaD.js} +1 -1
  67. package/dist/assets/web/dist/assets/{elixir-B2mtRgCr.js → elixir-x7o8qMl8.js} +1 -1
  68. package/dist/assets/web/dist/assets/{elm-2teVAwCi.js → elm-DGrRyqTQ.js} +1 -1
  69. package/dist/assets/web/dist/assets/{erb-LAbeNqen.js → erb--_dh58Nw.js} +1 -1
  70. package/dist/assets/web/dist/assets/{git-rebase-DnhzH_sp.js → git-rebase-DbpUXwyg.js} +1 -1
  71. package/dist/assets/web/dist/assets/{glimmer-js-DPKjXf1-.js → glimmer-js-BG0CuZG5.js} +1 -1
  72. package/dist/assets/web/dist/assets/{glimmer-ts-CABXnt5z.js → glimmer-ts-CQIl5qyR.js} +1 -1
  73. package/dist/assets/web/dist/assets/{glsl-Dz4-3-gJ.js → glsl-9PJNQTcw.js} +1 -1
  74. package/dist/assets/web/dist/assets/{graphql-ByWUD1DL.js → graphql-CzVTzjEI.js} +1 -1
  75. package/dist/assets/web/dist/assets/{hack-CdmOK2K-.js → hack-BhCmAz3Q.js} +1 -1
  76. package/dist/assets/web/dist/assets/{haml-DzegMpd2.js → haml-BmI12COR.js} +1 -1
  77. package/dist/assets/web/dist/assets/{handlebars-B5NeiP0e.js → handlebars-Cib-ISTS.js} +1 -1
  78. package/dist/assets/web/dist/assets/{html-Zg_NHLv9.js → html-D3lDapvI.js} +1 -1
  79. package/dist/assets/web/dist/assets/{html-derivative-DZf9JNzh.js → html-derivative-DRPY8vOK.js} +1 -1
  80. package/dist/assets/web/dist/assets/{http-CVFrQZeN.js → http-B9VttK6m.js} +1 -1
  81. package/dist/assets/web/dist/assets/{hurl-L5brWAJe.js → hurl-C0saNJYj.js} +1 -1
  82. package/dist/assets/web/dist/assets/indexRow-DABQtONT.js +1 -0
  83. package/dist/assets/web/dist/assets/{java-hFphyZ4R.js → java-BCFbtYAj.js} +1 -1
  84. package/dist/assets/web/dist/assets/{javascript-CAJO1WKX.js → javascript-nwBjnrhh.js} +1 -1
  85. package/dist/assets/web/dist/assets/{jinja-N4A4srXI.js → jinja-CMYO9byN.js} +1 -1
  86. package/dist/assets/web/dist/assets/{jison-D3BZa_iU.js → jison-Cko8HnE_.js} +1 -1
  87. package/dist/assets/web/dist/assets/{json-DxD1Qh8W.js → json-Dzv__YsX.js} +1 -1
  88. package/dist/assets/web/dist/assets/{jsx-CHhag69S.js → jsx-CTFxagih.js} +1 -1
  89. package/dist/assets/web/dist/assets/{julia-CrhkZ6Tt.js → julia-_Xvten1-.js} +1 -1
  90. package/dist/assets/web/dist/assets/{just-D0LFOuhq.js → just-bLps4qOu.js} +1 -1
  91. package/dist/assets/web/dist/assets/{latex-BHAlwCXK.js → latex-D6UaYsUP.js} +1 -1
  92. package/dist/assets/web/dist/assets/{liquid-CkaLfCWh.js → liquid-CoDIeULa.js} +1 -1
  93. package/dist/assets/web/dist/assets/{lua-B1h4aAzP.js → lua-D1KFRnVf.js} +1 -1
  94. package/dist/assets/web/dist/assets/main-C4QfwybO.css +1 -0
  95. package/dist/assets/web/dist/assets/main-Comxmwi4.js +28 -0
  96. package/dist/assets/web/dist/assets/{marko-D6CG4hvX.js → marko-B5N5XcOw.js} +1 -1
  97. package/dist/assets/web/dist/assets/{mdc-CVQzimAU.js → mdc-uxzjQO3q.js} +1 -1
  98. package/dist/assets/web/dist/assets/{nginx-h-9Ir54h.js → nginx-BMJxs2TK.js} +1 -1
  99. package/dist/assets/web/dist/assets/{nim-DHVI30sp.js → nim-DqQ3-8p1.js} +1 -1
  100. package/dist/assets/web/dist/assets/{org-AasAXfMF.js → org-DsY6LK59.js} +1 -1
  101. package/dist/assets/web/dist/assets/{perl-BVi5aTEy.js → perl--pq9iJFp.js} +1 -1
  102. package/dist/assets/web/dist/assets/{php-qOkCeUKr.js → php-RHCMbsM2.js} +1 -1
  103. package/dist/assets/web/dist/assets/{pug-8TnUGvEX.js → pug-CFNq_FCp.js} +1 -1
  104. package/dist/assets/web/dist/assets/{qml-CpJbhoxn.js → qml-C9Acx9E8.js} +1 -1
  105. package/dist/assets/web/dist/assets/{r-JkUNcAJW.js → r-DxlU8FBd.js} +1 -1
  106. package/dist/assets/web/dist/assets/{razor-CtU4ws5a.js → razor-CLJ2kKih.js} +1 -1
  107. package/dist/assets/web/dist/assets/{regexp-J2zA6ceN.js → regexp-CzmdGoEp.js} +1 -1
  108. package/dist/assets/web/dist/assets/{rst-CMCvf-yZ.js → rst-D9yuxBET.js} +1 -1
  109. package/dist/assets/web/dist/assets/{ruby-ChLBY_iR.js → ruby-CIRcEvnD.js} +1 -1
  110. package/dist/assets/web/dist/assets/{sas-cwn4x2VY.js → sas-LOl-uUPh.js} +1 -1
  111. package/dist/assets/web/dist/assets/{scss-jSrJlzLI.js → scss-BX2_sZHY.js} +1 -1
  112. package/dist/assets/web/dist/assets/{shellscript-D5nAd0gs.js → shellscript-4d-QvKkY.js} +1 -1
  113. package/dist/assets/web/dist/assets/{shellsession-BZY4-Tdh.js → shellsession-DhB16UGy.js} +1 -1
  114. package/dist/assets/web/dist/assets/{soy-COppPOKr.js → soy-Cm1xTUBr.js} +1 -1
  115. package/dist/assets/web/dist/assets/{sql-Blc_6dOA.js → sql-BsfcBJdu.js} +1 -1
  116. package/dist/assets/web/dist/assets/{sseReplay-DmyMXfRC.js → sseReplay-IzTdD4-3.js} +5 -5
  117. package/dist/assets/web/dist/assets/{stata-DRv3OY-h.js → stata-Dwat3BSw.js} +1 -1
  118. package/dist/assets/web/dist/assets/{surrealql-qMv_eeJ6.js → surrealql-P4rtxzAW.js} +1 -1
  119. package/dist/assets/web/dist/assets/{svelte-d1Edb6Rz.js → svelte-DTcsi8S8.js} +1 -1
  120. package/dist/assets/web/dist/assets/{templ-CUMSIOXG.js → templ-D-kP0Tg5.js} +1 -1
  121. package/dist/assets/web/dist/assets/{tex-BGZQA-Ei.js → tex-D-4vuedK.js} +1 -1
  122. package/dist/assets/web/dist/assets/{ts-tags-Z9ulxVsq.js → ts-tags-jEEWYxsu.js} +1 -1
  123. package/dist/assets/web/dist/assets/{tsx-oI4bI3Vf.js → tsx-CFnlrVzT.js} +1 -1
  124. package/dist/assets/web/dist/assets/{twig-D_RXwBIX.js → twig-D5rGrPjs.js} +1 -1
  125. package/dist/assets/web/dist/assets/{typescript-BgqQDYoN.js → typescript-nYIQ35or.js} +1 -1
  126. package/dist/assets/web/dist/assets/{typst-5MW-KRDd.js → typst-3-UX8dna.js} +1 -1
  127. package/dist/assets/web/dist/assets/{vue-CZhHHsPm.js → vue-CLIPIX03.js} +1 -1
  128. package/dist/assets/web/dist/assets/{vue-html-DlYy2d8v.js → vue-html-Ci9CpkHU.js} +1 -1
  129. package/dist/assets/web/dist/assets/{vue-vine-CJDnx-qn.js → vue-vine-DL5pEYYk.js} +1 -1
  130. package/dist/assets/web/dist/assets/{xml-BRBDk65Q.js → xml-bO80qikC.js} +1 -1
  131. package/dist/assets/web/dist/assets/{xsl-BlCykPxo.js → xsl-BPze60Ej.js} +1 -1
  132. package/dist/assets/web/dist/assets/{yaml-BqW48szf.js → yaml-BQUSon_o.js} +1 -1
  133. package/dist/cli.js +36552 -33171
  134. package/package.json +1 -1
  135. package/dist/assets/web/dist/assets/CostsPage-BoKzYa4B.js +0 -2
  136. package/dist/assets/web/dist/assets/HomePage-BG_ok-K2.js +0 -2
  137. package/dist/assets/web/dist/assets/PendingTurnRow-ChCQOLgZ.js +0 -1
  138. package/dist/assets/web/dist/assets/RunFoldRow-D3wVpzBa.js +0 -1
  139. package/dist/assets/web/dist/assets/RunRoutePage-B3IirUVi.js +0 -9
  140. package/dist/assets/web/dist/assets/RunsIndexPage-DiFmtGaJ.js +0 -1
  141. package/dist/assets/web/dist/assets/indexRow-BT0cPVRw.js +0 -1
  142. package/dist/assets/web/dist/assets/main-5Gm_1Gv8.js +0 -28
  143. package/dist/assets/web/dist/assets/main-zbP_dTjR.css +0 -1
@@ -11,6 +11,13 @@ providers:
11
11
  anthropic:
12
12
  wire: anthropic-messages
13
13
  apiKeyEnv: ANTHROPIC_API_KEY
14
+ # The biller's invoice for the daily tie-out on the costs page (costs.md item
15
+ # 4d): each block may name its own invoice API and the env var holding that
16
+ # API's key — an admin or management key, never the inference key. This is
17
+ # where `costs.anthropicAdminKeyEnv` moved; the old key under `costs:` is
18
+ # still accepted for one release.
19
+ # invoiceApi: anthropic-cost-report # GET /v1/organizations/cost_report
20
+ # invoiceKeyEnv: ANTHROPIC_ADMIN_KEY # sk-ant-admin…
14
21
  # OpenAI itself runs on its Responses API (record 0052): every first-party
15
22
  # OpenAI card in pi's registry is `openai-responses`, OpenAI recommends the
16
23
  # wire for new projects, and its chat route loses tool calling with any
@@ -21,6 +28,8 @@ providers:
21
28
  wire: openai-responses
22
29
  baseUrl: https://api.openai.com/v1
23
30
  apiKeyEnv: OPENAI_API_KEY
31
+ # invoiceApi: openai-costs # GET /v1/organization/costs, an admin key
32
+ # invoiceKeyEnv: OPENAI_ADMIN_KEY
24
33
  # groq:
25
34
  # wire: openai-chat
26
35
  # baseUrl: https://api.groq.com/openai/v1
@@ -42,6 +51,10 @@ providers:
42
51
  catalog: openrouter
43
52
  baseUrl: https://openrouter.ai/api/v1
44
53
  apiKeyEnv: OPENROUTER_API_KEY
54
+ # invoiceApi: openrouter-activity # GET /api/v1/activity, a management key;
55
+ # # its `usage` ties against the summed BYOK
56
+ # # fees, `byok_usage_inference` the remainder
57
+ # invoiceKeyEnv: OPENROUTER_MANAGEMENT_KEY
45
58
  # The operator's layer over the registry card: what a run needs that no
46
59
  # layer names goes out unvouched (and a note says so on the record) until
47
60
  # an override like this pins it. `providers check` (a later unit) reads the
@@ -167,6 +180,12 @@ defaults:
167
180
  # verbosity: verbose # hear every acknowledgement of what the bot does for you
168
181
  # harness:
169
182
  # coding: opencode
183
+ # # The person's GitHub author binding (record 0062; authorization.md item 18):
184
+ # # the login their commits are authored as. A bare login here is resolved to
185
+ # # { login, id } once at first use; `config set user --user <id> --github
186
+ # # <login>` (identity:write holders) stores the pair. Never set by the person
187
+ # # themselves; `config clear me` keeps it. One login/id binds one person.
188
+ # github: octocat
170
189
 
171
190
  # Authorization (docs/reference/specs/authorization.md item 9, docs/reference/authorization.md):
172
191
  # two blocks. `restrict` names what is CLOSED unless granted — an agent listed
@@ -388,6 +407,8 @@ workspaceDir: ./workspaces
388
407
  # ship:
389
408
  # maxRounds: 3 # review rounds per unit
390
409
  # maxMinutes: 240 # the ship preset's wall-clock budget in minutes (the registry's default)
410
+ # idleDays: 0 # days a ship unit idles instead of ending (record 0051): 0–365, 0 = today's
411
+ # # endings; also per channel/user (`channels.<id>.ship.idleDays`), user > channel > org
391
412
 
392
413
  # Which harness each preset's runs are driven by, deployment-wide
393
414
  # (docs/reference/specs/harness.md item 8): a mapping of preset to a harness's
@@ -454,10 +475,17 @@ workspaceDir: ./workspaces
454
475
  # `tool` (default) forces a call to the router's `route` tool, whose schema is
455
476
  # the answer, so prose cannot occur; `text` is the one-JSON-object text contract
456
477
  # alone — set it for a provider or model that cannot take a forced tool call.
478
+ # `operator` is the one door's flag (routing-and-config item 29): `on`
479
+ # (default) — the operator's decision is what runs; `shadow` — one operator
480
+ # turn per admitted chat event, ahead of stage A, its decision written beside
481
+ # the routed request in the run store and nothing run from it; `off` — the
482
+ # rollback lever: it turns the operator back off after a bad day, not a choice
483
+ # to make up front. `shadow` and `on` run even under `auto: false`.
457
484
  # routing:
458
485
  # auto: false
459
486
  # model: anthropic/claude-haiku-4-5
460
487
  # answer: text
488
+ # operator: off
461
489
 
462
490
  # The thread-reply intake gate (docs/decisions/0058-a-thread-reply-is-read-before-it-is-answered-intake-decides-whether-the-bot-was-addressed.md;
463
491
  # docs/reference/specs/routing-and-config.md item 27). How an unmentioned reply
@@ -479,6 +507,19 @@ workspaceDir: ./workspaces
479
507
  # threadReplies: classify
480
508
  # model: anthropic/claude-haiku-4-5
481
509
 
510
+ # The orchestration plane (docs/decisions/0064-the-plane-owns-every-runs-state-a-refusal-becomes-a-queue-position-an-ending-is-judged-by-the-ledger-that-saw-it-and-a-release-is-a-quiet-window-a-person-closes.md;
511
+ # docs/reference/specs/routing-and-config.md item 31; orchestration-plane.md).
512
+ # `admission` gates the ledger object's queue decider: `off` (default) — the
513
+ # plane hears of no dispatch and nothing is posted; `shadow` — the bot posts
514
+ # its own outcome per dispatch (`proceeded`, `refused:<code>`) to the ledger
515
+ # object, which logs its decider's decision beside it — nothing runs from the
516
+ # decider; `on` — a later release's flip (the decider's answer is what runs).
517
+ # `reaskMinutes` (default 2) is the plane's one re-ask cadence, used only while
518
+ # something waits on a reporter that fell silent; nothing reads it yet.
519
+ # plane:
520
+ # admission: shadow
521
+ # reaskMinutes: 2
522
+
482
523
  # Linked threads (docs/decisions/0037-a-linked-thread-is-quoted-not-joined.md;
483
524
  # docs/reference/specs/routing-and-config.md item 22). Off by default. On, a
484
525
  # permalink in a request to a thread in another PUBLIC channel the bot is a
@@ -494,7 +535,8 @@ workspaceDir: ./workspaces
494
535
  # cloudflareAccountId: <32-hex account id>
495
536
  # cloudflareAccountName: acme-infra # optional: how the page names the account beside its share (else the id's first hex)
496
537
  # cloudflareTokenEnv: CF_ANALYTICS_TOKEN # token with Account Analytics:Read
497
- # anthropicAdminKeyEnv: ANTHROPIC_ADMIN_KEY # optional: sk-ant-admin… for LLM spend
538
+ # anthropicAdminKeyEnv: ANTHROPIC_ADMIN_KEY # legacy (one release): moved to providers.anthropic.invoiceKeyEnv
539
+ # # (invoiceApi: anthropic-cost-report); still feeds the LLM line here
498
540
  # snapshot: # the page serves a snapshot of both billing sources, never a live read;
499
541
  # everyHours: 24 # how often the bot reads them (1–168, default 24). `costs snapshot`
500
542
  # # takes one now. Kept on the state Worker any `*.worker` block names
@@ -519,6 +561,17 @@ workspaceDir: ./workspaces
519
561
  # cacheRead: 0.125 # never $0, on the costs page and on a run's own page
520
562
  # cacheWrite: 0
521
563
 
564
+ # Run metrics (docs/reference/specs/run-metrics.md). Optional. The Analytics Engine
565
+ # dataset every finished run's point lands in — the SAME name the deployment
566
+ # profile's `metrics.dataset` binds on the state Worker as RUN_METRICS (the bot
567
+ # warns at boot when the two differ; neither side refuses to start). With the
568
+ # `costs` block's Cloudflare account and analytics token this turns the `metrics`
569
+ # capability on: `metrics trend` reads the trend report from the dataset over the
570
+ # Analytics Engine SQL API, weighted for sampling.
571
+ # metrics:
572
+ # dataset: switchboard_runs
573
+ # days: 30 # optional: the default report range in whole UTC days, 1..90
574
+
522
575
  # Delivery indicators: GET /delivery and `delivery report` (docs/reference/specs/delivery.md).
523
576
  # Optional. Needs a GitHub credential (the App triple or GH_TOKEN); read-only on GitHub.
524
577
  # delivery:
@@ -0,0 +1,31 @@
1
+ import type { RunMetricsPoint } from "../../src/core/runMetrics.ts";
2
+
3
+ // The run-metrics sink (docs/reference/specs/run-metrics.md): where the
4
+ // RunHistoryDO writes the one point of a run whose row turned final, after the
5
+ // record's commit. Two implementations behind one seam (AGENTS.md invariant 2):
6
+ // the Workers Analytics Engine dataset when the Worker is deployed with the
7
+ // optional `RUN_METRICS` binding, the null sink otherwise — so a Worker without
8
+ // the binding behaves byte-identically, the same shape as `SHIP_COORDINATOR?`.
9
+ // The write is advisory on the caller's side too: one try, one console.warn,
10
+ // never a failed put or finish.
11
+
12
+ export interface RunMetricsSink {
13
+ write(point: RunMetricsPoint): void;
14
+ }
15
+
16
+ /** The dataset the deploy bound: `writeDataPoint` is synchronous and does not
17
+ * throw on a platform-side drop; the caller's try covers a missing or
18
+ * misconfigured binding. */
19
+ export class AnalyticsEngineSink implements RunMetricsSink {
20
+ constructor(private readonly dataset: AnalyticsEngineDataset) {}
21
+ write(point: RunMetricsPoint): void {
22
+ this.dataset.writeDataPoint({ indexes: point.indexes, blobs: point.blobs, doubles: point.doubles });
23
+ }
24
+ }
25
+
26
+ /** No binding: points are dropped — the off state. */
27
+ export class NullSink implements RunMetricsSink {
28
+ write(): void {
29
+ // nothing is written without the binding
30
+ }
31
+ }