@bytesbrains/cruise-worker 0.0.0-stage → 0.12.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 (137) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +37 -2
  3. package/index.d.ts +14 -0
  4. package/index.mjs +41 -0
  5. package/migrations/0001_virtual_keys.sql +102 -0
  6. package/migrations/0002_seed_projects.sql +16 -0
  7. package/migrations/0003_budgets.sql +43 -0
  8. package/migrations/0004_tenant_isolation_and_integer_money.sql +49 -0
  9. package/migrations/0005_model_prices.sql +42 -0
  10. package/migrations/0006_budget_reservation.sql +38 -0
  11. package/migrations/0007_routing_table.sql +93 -0
  12. package/migrations/0008_measurement_provenance.sql +24 -0
  13. package/migrations/0009_conformance.sql +37 -0
  14. package/migrations/0010_conformance_key.sql +20 -0
  15. package/migrations/0011_correct_workers_ai_price.sql +30 -0
  16. package/migrations/0012_rate_limits.sql +28 -0
  17. package/migrations/0013_deepseek_and_mistral.sql +42 -0
  18. package/migrations/0014_cost_ledger.sql +104 -0
  19. package/migrations/0015_memberships.sql +33 -0
  20. package/migrations/0016_latency.sql +23 -0
  21. package/migrations/0017_ledger_provider_index.sql +8 -0
  22. package/migrations/0018_fallback_chains.sql +34 -0
  23. package/migrations/0019_rate_buckets.sql +27 -0
  24. package/migrations/0020_mistral_price_and_pin.sql +62 -0
  25. package/migrations/0021_mistral_price_date_is_utc.sql +35 -0
  26. package/migrations/0022_drop_unenforced_key_budget.sql +32 -0
  27. package/migrations/0023_model_limits.sql +48 -0
  28. package/migrations/0024_conditional_prices.sql +84 -0
  29. package/migrations/0025_catalogue_from_keyed_hosts.sql +172 -0
  30. package/migrations/0026_lanes.sql +83 -0
  31. package/migrations/0027_lane_alternatives.sql +36 -0
  32. package/migrations/0028_lanes_tenant_scope.sql +66 -0
  33. package/migrations/0029_lane_jobs.sql +146 -0
  34. package/migrations/0030_lane_requires.sql +38 -0
  35. package/migrations/0031_tenant_billable.sql +15 -0
  36. package/migrations/0032_cache_hit_billing.sql +35 -0
  37. package/migrations/0033_sell_markup.sql +37 -0
  38. package/migrations/0034_tiers_and_lane_quotas.sql +38 -0
  39. package/migrations/0035_wallet_scope.sql +68 -0
  40. package/migrations/0036_credit_grants.sql +53 -0
  41. package/migrations/0037_reconciliation.sql +45 -0
  42. package/migrations/0038_balance_service_keys.sql +35 -0
  43. package/migrations/0039_deepseek_peak_is_weekdays.sql +77 -0
  44. package/migrations/0040_glm_5_3_on_workers_ai.sql +63 -0
  45. package/migrations/0041_mistral_sweep_2026_08_29.sql +89 -0
  46. package/migrations/0042_provision_service_keys.sql +50 -0
  47. package/migrations/0043_tier_project_quota.sql +32 -0
  48. package/migrations/0044_audit_tenant_scope.sql +49 -0
  49. package/migrations/0045_audit_backfill_derivable.sql +42 -0
  50. package/migrations/0046_measurement_note.sql +24 -0
  51. package/migrations/0047_ledger_max_tokens.sql +21 -0
  52. package/migrations/0048_price_observations.sql +140 -0
  53. package/migrations/0049_openai_and_gemini.sql +239 -0
  54. package/migrations/0050_meta_direct_upstream.sql +127 -0
  55. package/migrations/0051_upstream_credential_and_operator.sql +74 -0
  56. package/migrations/0052_muse_spark_1_3.sql +71 -0
  57. package/migrations/0053_anthropic_groq_and_xai.sql +172 -0
  58. package/migrations/0054_tier_service_keys.sql +60 -0
  59. package/migrations/0055_output_defaults.sql +79 -0
  60. package/migrations/0056_model_modality.sql +37 -0
  61. package/migrations/0057_openai_image_models.sql +177 -0
  62. package/migrations/0058_price_components.sql +230 -0
  63. package/migrations/0059_speech.sql +151 -0
  64. package/migrations/0060_embeddings.sql +131 -0
  65. package/migrations/0061_data_retention_backfill.sql +121 -0
  66. package/migrations/0062_gemini_embedding_disabled.sql +125 -0
  67. package/migrations/0063_google_provider_path_prefix.sql +59 -0
  68. package/migrations/0064_economics_service_keys.sql +51 -0
  69. package/migrations/0065_lane_selection.sql +66 -0
  70. package/migrations/0066_tenant_default_selection.sql +42 -0
  71. package/migrations/0067_graduated_selection.sql +103 -0
  72. package/migrations/0068_cache_scope.sql +73 -0
  73. package/migrations/0069_lane_cache_settings.sql +50 -0
  74. package/migrations/0070_lane_member_quality_rank.sql +98 -0
  75. package/migrations/0071_key_cache_pool.sql +60 -0
  76. package/migrations/0072_cache_digest.sql +51 -0
  77. package/migrations/0073_lane_max_chain.sql +51 -0
  78. package/migrations/0074_hunter_builder_lanes.sql +149 -0
  79. package/migrations/0075_hunter_builder_frontline.sql +36 -0
  80. package/migrations/0076_deepseek_flash.sql +86 -0
  81. package/migrations/0077_gpt_6_astra.sql +35 -0
  82. package/migrations/0078_astra_deep_reasoning.sql +20 -0
  83. package/migrations/0079_gemini_flash_lite_extraction.sql +15 -0
  84. package/migrations/0080_priced_by.sql +24 -0
  85. package/migrations/0081_grok_imagine.sql +81 -0
  86. package/migrations/0082_markup_three_percent.sql +32 -0
  87. package/migrations/0083_markup_per_tenant_and_tier.sql +57 -0
  88. package/migrations/0084_coding_lanes_frontier.sql +93 -0
  89. package/migrations/0085_minute_period_and_demo_charge.sql +77 -0
  90. package/migrations/0086_project_sentry.sql +41 -0
  91. package/migrations/0087_lane_router.sql +71 -0
  92. package/migrations/0088_openai_frontier_coding_lanes.sql +54 -0
  93. package/migrations/0089_agentic_coding_drops_codestral.sql +44 -0
  94. package/migrations/0090_board_followups_2026_10.sql +196 -0
  95. package/migrations/0091_opus_5_5_coding_lanes.sql +43 -0
  96. package/migrations/0092_deepseek_peak_holidays.sql +83 -0
  97. package/migrations/0093_tool_choice_forced.sql +26 -0
  98. package/migrations/0094_board_followups_2026_10_08.sql +115 -0
  99. package/migrations/0095_request_compression.sql +43 -0
  100. package/migrations/0096_lane_compress.sql +36 -0
  101. package/migrations/0097_tenant_default_compress.sql +34 -0
  102. package/migrations/0098_ledger_session.sql +47 -0
  103. package/migrations/0099_wallet_low_water_backfill.sql +47 -0
  104. package/migrations/0100_rag_grounded_answers_lane.sql +92 -0
  105. package/migrations/0101_perplexity_agent_api.sql +125 -0
  106. package/migrations/0102_web_search_job_and_flag.sql +137 -0
  107. package/migrations/0103_openai_web_search_price.sql +44 -0
  108. package/migrations/0104_web_search_lane.sql +82 -0
  109. package/migrations/0105_web_search_lane_billed.sql +22 -0
  110. package/migrations/0106_reservations_journal.sql +64 -0
  111. package/migrations/0107_session_cap.sql +65 -0
  112. package/migrations/0108_ledger_attempts.sql +41 -0
  113. package/migrations/0109_gemini_retention.sql +39 -0
  114. package/migrations/0110_gemini_4_argon.sql +110 -0
  115. package/migrations/0111_gemini_4_argon_lanes.sql +80 -0
  116. package/migrations/0112_ledger_affinity.sql +42 -0
  117. package/migrations/0113_contributor_lane_namespace.sql +125 -0
  118. package/migrations/0114_meta_contributor_models.sql +55 -0
  119. package/migrations/0115_oss_chat_assistant_lane.sql +41 -0
  120. package/migrations/0116_promo_credits.sql +63 -0
  121. package/migrations/0117_oss_mirror_lanes.sql +85 -0
  122. package/migrations/0118_project_management_job.sql +112 -0
  123. package/migrations/0119_oss_project_management_lane.sql +29 -0
  124. package/migrations/0120_moonshot_k3_1_pro.sql +107 -0
  125. package/migrations/0121_jobs.sql +100 -0
  126. package/migrations/0122_batch_prices.sql +188 -0
  127. package/migrations/0123_batch_files.sql +50 -0
  128. package/migrations/0124_batch_run.sql +21 -0
  129. package/migrations/0125_anthropic_path_prefix.sql +22 -0
  130. package/package.json +37 -4
  131. package/worker/284906b51fc0a3173ea7d301234907f30e834f54-cruise-mark-64.png +0 -0
  132. package/worker/2c39de526314484775fdfc503fac50c437d21e4e-cruise-logo-240.png +0 -0
  133. package/worker/63fb63e2d8ae6d8b68228768ef6c91ab8f0c0100-cruise-logo-480.png +0 -0
  134. package/worker/VERSION +1 -0
  135. package/worker/b23bfbc792e8710d3b74284a0a1b8ab044c18897-logo-dark.png +0 -0
  136. package/worker/index.js +31451 -0
  137. package/wrangler.template.jsonc +48 -0
@@ -0,0 +1,63 @@
1
+ -- Promotional credit: free balance with no settled payment behind it (#692,
2
+ -- shared with #688).
3
+ --
4
+ -- `POST /payments/credits` confirms every grant against the payments side's
5
+ -- settled-intents surface, and no confirmation configured means no grants.
6
+ -- That fails closed exactly as designed — and it means free credit cannot go
7
+ -- through that route at all: there is no intent to confirm, so the only
8
+ -- honest answer it can give is `intent_unconfirmed`. Trial credit, contributor
9
+ -- incentives and partner free tiers all need a grant path that does not ask
10
+ -- the system of record, because there is nothing to ask it about.
11
+ --
12
+ -- ## The shape: the same table, a marked row, a separate key
13
+ --
14
+ -- A promo grant is a row in `credits`, so the wallet cap — sum(credits),
15
+ -- recomputed on every grant — counts it with no code change, and the grant
16
+ -- history shows it beside paid credit. What marks it is `kind`: `payment`
17
+ -- for everything this table has ever held, `promo` for the new rows. The
18
+ -- default backfills the column honestly — every existing row arrived through
19
+ -- confirmation — and a CHECK holds the closed set.
20
+ --
21
+ -- Two things read `kind`. Reconciliation's `grantsVsSettled` re-confirms
22
+ -- every credit against the settled-intents surface; a promo row would fail
23
+ -- that check every day forever, so it reads `payment` rows only. The promo
24
+ -- backstop is not re-confirmation — there is nothing to re-confirm against —
25
+ -- it is the audit trail (every grant writes one), the per-grant ceiling and
26
+ -- the lifetime allowance the route enforces, and the separate capability
27
+ -- below.
28
+ --
29
+ -- The capability is `promo`, on 0038's terms: one per key, issued for one
30
+ -- value and never two. A `credits` key presented to the promo route is the
31
+ -- same 401 as a string that was never a key, and a `promo` key presented to
32
+ -- the payment route likewise — the lookup names its purposes, so neither
33
+ -- holder learns the other exists. Minting free credit and minting settled
34
+ -- credit are separate powers, and one leaked credential must not be both.
35
+ --
36
+ -- SQLite cannot widen a CHECK in place, so `service_keys` is rebuilt, and
37
+ -- 0038's, 0042's, 0054's and 0064's note on why that is safe applies
38
+ -- unchanged: the name and every column stay identical, so code deployed
39
+ -- before this migration and code deployed after read exactly the same shape.
40
+ -- Widening is the safe direction on its own — no existing row can fail the
41
+ -- new CHECK, and a Worker deployed before this simply never matches a `promo`
42
+ -- row, because `authenticate` names the purposes it will accept in the lookup
43
+ -- itself.
44
+
45
+ ALTER TABLE credits ADD COLUMN kind TEXT NOT NULL DEFAULT 'payment'
46
+ CHECK (kind IN ('payment', 'promo'));
47
+
48
+ CREATE TABLE service_keys_new (
49
+ id TEXT PRIMARY KEY,
50
+ prefix TEXT NOT NULL UNIQUE,
51
+ key_hash TEXT NOT NULL,
52
+ purpose TEXT NOT NULL CHECK (purpose IN ('credits', 'balance', 'provision', 'tier', 'economics', 'promo')),
53
+ created_by TEXT NOT NULL,
54
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
55
+ revoked_at TEXT,
56
+ last_used_at TEXT
57
+ );
58
+
59
+ INSERT INTO service_keys_new (id, prefix, key_hash, purpose, created_by, created_at, revoked_at, last_used_at)
60
+ SELECT id, prefix, key_hash, purpose, created_by, created_at, revoked_at, last_used_at FROM service_keys;
61
+
62
+ DROP TABLE service_keys;
63
+ ALTER TABLE service_keys_new RENAME TO service_keys;
@@ -0,0 +1,85 @@
1
+ -- The contributor mirror set: `oss/` lanes for every `bb/` job the contributor
2
+ -- models can actually serve (#692).
3
+ --
4
+ -- 0115 seeded the first lane, `oss/chat-assistant`, on unmeasured members.
5
+ -- Conformance has since measured both contributor rows (2026-10-22):
6
+ -- `tools` yes, `json_schema`, `streaming`, `vision` and `web_search` no, 1M
7
+ -- context. So this seats eight more lanes on the same two members — nine
8
+ -- with `oss/chat-assistant`, and deliberately not twelve. The three missing
9
+ -- jobs are missing because the members fail their gates, not because
10
+ -- somebody forgot them:
11
+ --
12
+ -- - `oss/web-search`: the search gate is job-implied (`lanes-search.ts`
13
+ -- keys on `lane.job`, either namespace), and both members measure
14
+ -- `web_search = 0`. A lane named web-search that can never search is a
15
+ -- name without service — and a permanent `doctor` failure.
16
+ -- - `oss/extraction` and `oss/rag-grounded-answers`: both jobs require
17
+ -- `json-schema`, as their `bb/` lanes do, and both members measure 0.
18
+ -- (The 1M window clears rag's `long-context 200000`; it is the schema
19
+ -- check that refuses.) Same verdict: unservable today, seatable the day
20
+ -- a contributor model measures the flag.
21
+ --
22
+ -- Seeding a lane that refuses every request is not neutral. `doctor` fails
23
+ -- `lane_members` for it on every environment, every deploy's verify step
24
+ -- has to re-judge the same known failure, and — the part that decides it —
25
+ -- lanes are disabled, never deleted. A skipped job is one insert away; a
26
+ -- dead lane is a row to explain forever. Nine contributor lanes that serve
27
+ -- beats twelve of which three never do.
28
+ --
29
+ -- ## What the eight carry
30
+ --
31
+ -- The `bb/` lane's job, requires and selection, verbatim: same job, same
32
+ -- gate. Four carry `tools-required` (both members measure `tools = 1`);
33
+ -- four carry nothing. Descriptions are the `bb/` text plus the consent
34
+ -- sentence from 0115, because the description is shown to callers beside
35
+ -- the lane. Both members unranked, for 0115's reason: placing 1.3 above
36
+ -- 1.2 is a judgement no measurement here makes.
37
+ --
38
+ -- These lanes serve the moment this applies — members measured, priced,
39
+ -- `trains` — on every environment, with no Worker deploy and no seed step.
40
+ -- Staging and the demo already hold the measurements this needs: 0114's
41
+ -- rows shipped in the #693 deploy, and conformance's mirror copies flags,
42
+ -- so the next `staging:seed`/`demo:seed` (or the next conformance run's
43
+ -- mirror job) carries them across.
44
+
45
+ INSERT INTO lanes (id, job, description) VALUES
46
+ ('oss/agentic-coding', 'agentic-coding',
47
+ 'Long tool-use loops over a repository. Output tokens dominate the bill. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.'),
48
+ ('oss/builder', 'builder',
49
+ 'Autonomous implementation loop: turn an issue into a green change. Edit, run tests, iterate on failures; finish verified-green or honestly unfinished. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.'),
50
+ ('oss/code-completion', 'code-completion',
51
+ 'Fill-in-the-middle and next lines. Members with a code-specialised training set. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.'),
52
+ ('oss/code-review', 'code-review',
53
+ 'Reads a diff or a repository and reasons about what is wrong with it. Tool calling and a large window; quality over price. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.'),
54
+ ('oss/deep-reasoning', 'deep-reasoning',
55
+ 'Problems that reward thinking tokens. The one lane where the cheapest member is the wrong default; price still decides, so pin a model when it matters. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.'),
56
+ ('oss/hunter', 'hunter',
57
+ 'Autonomous security expedition over a pull request or repository: trace untrusted input to a dangerous sink, write a PoC, detonate it, and only then claim a finding. Not a diff review. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.'),
58
+ ('oss/summarization', 'summarization',
59
+ 'A long input to a short output. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.'),
60
+ ('oss/translation', 'translation',
61
+ 'Between natural languages. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.');
62
+
63
+ INSERT INTO lane_members (lane_id, model_id, position, quality_rank) VALUES
64
+ ('oss/agentic-coding', 'meta/muse-spark-1.3-contributor', 1, NULL),
65
+ ('oss/agentic-coding', 'meta/muse-spark-1.2-contributor', 2, NULL),
66
+ ('oss/builder', 'meta/muse-spark-1.3-contributor', 1, NULL),
67
+ ('oss/builder', 'meta/muse-spark-1.2-contributor', 2, NULL),
68
+ ('oss/code-completion', 'meta/muse-spark-1.3-contributor', 1, NULL),
69
+ ('oss/code-completion', 'meta/muse-spark-1.2-contributor', 2, NULL),
70
+ ('oss/code-review', 'meta/muse-spark-1.3-contributor', 1, NULL),
71
+ ('oss/code-review', 'meta/muse-spark-1.2-contributor', 2, NULL),
72
+ ('oss/deep-reasoning', 'meta/muse-spark-1.3-contributor', 1, NULL),
73
+ ('oss/deep-reasoning', 'meta/muse-spark-1.2-contributor', 2, NULL),
74
+ ('oss/hunter', 'meta/muse-spark-1.3-contributor', 1, NULL),
75
+ ('oss/hunter', 'meta/muse-spark-1.2-contributor', 2, NULL),
76
+ ('oss/summarization', 'meta/muse-spark-1.3-contributor', 1, NULL),
77
+ ('oss/summarization', 'meta/muse-spark-1.2-contributor', 2, NULL),
78
+ ('oss/translation', 'meta/muse-spark-1.3-contributor', 1, NULL),
79
+ ('oss/translation', 'meta/muse-spark-1.2-contributor', 2, NULL);
80
+
81
+ INSERT INTO lane_requires (lane_id, constraint_, value) VALUES
82
+ ('oss/agentic-coding', 'tools-required', NULL),
83
+ ('oss/builder', 'tools-required', NULL),
84
+ ('oss/code-review', 'tools-required', NULL),
85
+ ('oss/hunter', 'tools-required', NULL);
@@ -0,0 +1,112 @@
1
+ -- `project-management` joins the closed job set (#695).
2
+ --
3
+ -- An agent tenant's PM runs — plan work, track status, drive tools over a project —
4
+ -- file under `other` today (`bb-adm/project-management`), which is the
5
+ -- demand signal working as designed: `other` names the job the vocabulary
6
+ -- does not have yet. This is the vocabulary answering. The word is ahead of
7
+ -- the board, as `hunter`, `builder` and `web-search` each were, and asked to
8
+ -- be owned there (board#385), so the copy stays vendored rather
9
+ -- than invented. If the board picks another word, it renames in a migration,
10
+ -- as 0029 did for `bulk-extraction` → `extraction`.
11
+ --
12
+ -- SQLite cannot widen a CHECK, so this is the sixth rebuild of the `lanes`
13
+ -- table's shape — 0028, 0029, 0074, 0102, 0113, and now this — over the
14
+ -- schema as 0113 left it, with one word added to the job list. Nothing else
15
+ -- moves: the namespaces, the id-is-job pin, the `other`-is-for-tenants rule
16
+ -- (which is exactly why the PM lane needs a real job), the `compress` bar.
17
+ -- No lane is created here; 0119 seeds the one this job exists for.
18
+ --
19
+ -- **The window is real and is stated rather than argued small** (0102's
20
+ -- words, still true): each statement is its own transaction on D1, so between
21
+ -- `DROP TABLE lanes` and the `RENAME` a lane lookup finds no table and fails.
22
+ -- Run it at the quietest hour, and expect a handful of lane requests to 500
23
+ -- if traffic lands inside. Pinned-model requests do not read `lanes` and are
24
+ -- unaffected.
25
+
26
+ CREATE TABLE lanes_new (
27
+ id TEXT PRIMARY KEY,
28
+ tenant_id TEXT REFERENCES tenants(id),
29
+ job TEXT NOT NULL CHECK (job IN (
30
+ 'chat-assistant', 'deep-reasoning', 'summarization', 'translation',
31
+ 'content-writing', 'extraction', 'code-completion', 'agentic-coding',
32
+ 'hunter', 'builder', 'web-search',
33
+ 'code-review', 'document-understanding', 'speech', 'rag-grounded-answers',
34
+ 'computer-use', 'content-moderation', 'project-management',
35
+ 'other')),
36
+ description TEXT NOT NULL,
37
+ enabled INTEGER NOT NULL DEFAULT 1,
38
+ created_by TEXT NOT NULL DEFAULT 'migration',
39
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
40
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
41
+ archived_at TEXT,
42
+ selection TEXT NOT NULL DEFAULT 'cheap'
43
+ CHECK (selection IN ('cheap', 'random', 'weighted')),
44
+ selection_policy TEXT NOT NULL DEFAULT 'cheap'
45
+ CHECK (selection_policy IN ('cheap', 'random', 'weighted', 'graduated')),
46
+ cache_ttl_seconds INTEGER NOT NULL DEFAULT 0
47
+ CHECK (cache_ttl_seconds BETWEEN 0 AND 2592000),
48
+ cache_scope TEXT NOT NULL DEFAULT 'model'
49
+ CHECK (cache_scope IN ('model', 'lane')),
50
+ max_chain INTEGER
51
+ CHECK (max_chain IS NULL OR max_chain BETWEEN 1 AND 3),
52
+ router TEXT
53
+ CHECK (router IS NULL OR router IN ('jev')),
54
+ router_input TEXT NOT NULL DEFAULT 'hint'
55
+ CHECK (router_input IN ('hint', 'prompt')),
56
+ compress INTEGER NOT NULL DEFAULT 0
57
+ CHECK (compress IN (0, 1) AND (compress = 0 OR tenant_id IS NOT NULL)),
58
+ CHECK (
59
+ (tenant_id IS NULL AND (substr(id, 1, 3) = 'bb/' OR substr(id, 1, 4) = 'oss/')) OR
60
+ (tenant_id IS NOT NULL AND substr(id, 1, length(tenant_id) + 1) = tenant_id || '/'
61
+ AND substr(id, 1, 3) <> 'bb/' AND substr(id, 1, 4) <> 'oss/')
62
+ ),
63
+ CHECK (tenant_id IS NOT NULL OR ((id = 'bb/' || job OR id = 'oss/' || job) AND job <> 'other'))
64
+ );
65
+
66
+ INSERT INTO lanes_new (
67
+ id, tenant_id, job, description, enabled, created_by, created_at, updated_at,
68
+ archived_at, selection, selection_policy, cache_ttl_seconds, cache_scope, max_chain,
69
+ router, router_input, compress
70
+ )
71
+ SELECT id, tenant_id, job, description, enabled, created_by, created_at, updated_at,
72
+ archived_at, selection, selection_policy, cache_ttl_seconds, cache_scope, max_chain,
73
+ router, router_input, compress
74
+ FROM lanes;
75
+
76
+ CREATE TABLE lane_members_new (
77
+ lane_id TEXT NOT NULL REFERENCES lanes_new(id),
78
+ model_id TEXT NOT NULL REFERENCES models(id),
79
+ position INTEGER NOT NULL,
80
+ weight REAL NOT NULL DEFAULT 1 CHECK (weight > 0),
81
+ quality_rank INTEGER,
82
+ PRIMARY KEY (lane_id, model_id)
83
+ );
84
+
85
+ INSERT INTO lane_members_new (lane_id, model_id, position, weight, quality_rank)
86
+ SELECT lane_id, model_id, position, weight, quality_rank FROM lane_members;
87
+
88
+ CREATE TABLE lane_requires_new (
89
+ lane_id TEXT NOT NULL REFERENCES lanes_new(id),
90
+ constraint_ TEXT NOT NULL CHECK (constraint_ IN (
91
+ 'long-context', 'tools-required', 'json-schema', 'vision-required',
92
+ 'no-training-on-data',
93
+ 'low-latency', 'high-throughput', 'open-weights', 'data-residency',
94
+ 'audio-required', 'batch-api')),
95
+ value TEXT,
96
+ PRIMARY KEY (lane_id, constraint_)
97
+ );
98
+
99
+ INSERT INTO lane_requires_new (lane_id, constraint_, value)
100
+ SELECT lane_id, constraint_, value FROM lane_requires;
101
+
102
+ DROP INDEX idx_lane_members_lane;
103
+ DROP INDEX idx_lanes_tenant;
104
+ DROP TABLE lane_requires;
105
+ DROP TABLE lane_members;
106
+ DROP TABLE lanes;
107
+ ALTER TABLE lanes_new RENAME TO lanes;
108
+ ALTER TABLE lane_members_new RENAME TO lane_members;
109
+ ALTER TABLE lane_requires_new RENAME TO lane_requires;
110
+
111
+ CREATE INDEX idx_lane_members_lane ON lane_members (lane_id, position);
112
+ CREATE INDEX idx_lanes_tenant ON lanes (tenant_id, enabled);
@@ -0,0 +1,29 @@
1
+ -- `oss/project-management`: the contributor lane for PM work (#695).
2
+ --
3
+ -- The use case is `bb-adm/project-management`'s — plan work, track status,
4
+ -- drive tools over a project — on contributor models instead of standard
5
+ -- ones. Staffed like the 0117 mirrors: the two Meta contributor tiers,
6
+ -- `tools-required` as the `bb-adm` lane carries (both members measure
7
+ -- `tools = 1`), `cheap` with 1.3 first. Both members cost the same, so the
8
+ -- curated order falls out of listing order under `cheap` — no new selection
9
+ -- semantic, which is why none was built.
10
+ --
11
+ -- This is the job 0118 exists for, and its only global lane: no
12
+ -- `bb/project-management` is seeded, because `bb-adm/project-management`
13
+ -- already serves PM on standard models and a `bb/` twin would duplicate it.
14
+ -- The job addition makes one trivially seedable later if anyone wants it.
15
+ -- Both members unranked, for 0115's reason.
16
+ --
17
+ -- Serves the moment this applies — members measured, priced, `trains` — on
18
+ -- every environment, with no Worker deploy and no seed step.
19
+
20
+ INSERT INTO lanes (id, job, description) VALUES
21
+ ('oss/project-management', 'project-management',
22
+ 'Plan work, track status, and drive tools over a project. Long context and tool calling; quality over price. Contributor tier: the host may train future models on this traffic, at the discounted rates that bought the consent — choosing this lane is the consent.');
23
+
24
+ INSERT INTO lane_members (lane_id, model_id, position, quality_rank) VALUES
25
+ ('oss/project-management', 'meta/muse-spark-1.3-contributor', 1, NULL),
26
+ ('oss/project-management', 'meta/muse-spark-1.2-contributor', 2, NULL);
27
+
28
+ INSERT INTO lane_requires (lane_id, constraint_, value) VALUES
29
+ ('oss/project-management', 'tools-required', NULL);
@@ -0,0 +1,107 @@
1
+ -- Moonshot / Kimi, through the lab's own API: Kimi K3.1 Pro and K3.1 Pro Highspeed (#700).
2
+ --
3
+ -- #208 is the reason this file is small and the reason it exists at all.
4
+ -- Moonshot was "a key, four models and no published price": `PROVIDER_KEY_MOONSHOT`
5
+ -- is set on staging and production, the direct path built for Meta in 0050 covers
6
+ -- any OpenAI-shaped host, and the only thing missing was a number. The Kimi API
7
+ -- team's announcement of 2026-10-26 UTC is that number — for two new models, not
8
+ -- for the K2/K3 rows #208 names, which stay unpriced.
9
+ --
10
+ -- ## What arrived, and that it is live
11
+ --
12
+ -- `kimi-k3.1-pro` and `kimi-k3.1-pro-highspeed`: first models of the K3.1 series,
13
+ -- described as the most capable 3T-class open-weight models to date, 1,048,576-token
14
+ -- context window, Highspeed at 2-3x the speed of Pro. Live on the Kimi API on
15
+ -- announcement day — the vendor's own quickstart names both ids and sends them to
16
+ -- `POST https://api.moonshot.ai/v1/chat/completions` with an OpenAI-shaped body:
17
+ --
18
+ -- https://platform.kimi.ai/docs/guide/kimi-k3-1-pro-quickstart.md (read 2026-10-26)
19
+ --
20
+ -- `base_url="https://api.moonshot.ai/v1"` is quoted from that page's own examples.
21
+ -- **`.ai`, not `.cn`** — #208 records that `.cn` rejects this key with
22
+ -- `invalid_authentication_error`, a different account estate, not a bad key.
23
+ -- No `provider_path_prefix`: unlike Google (0063), Moonshot serves the OpenAI
24
+ -- shape at its root, exactly like Meta's `https://api.meta.ai/v1` in 0050. No
25
+ -- request-path code — `isDirect` in `src/routing.ts` is the whole of the branch,
26
+ -- and `headersFor` already builds the fresh header set a third-party host needs.
27
+ --
28
+ -- ## The prices, and where each figure was actually read
29
+ --
30
+ -- The per-model figures below are from the vendor's announcement email
31
+ -- (2026-10-26 UTC), not from a price cell on the host's page: the K3 series
32
+ -- section of `https://platform.kimi.ai/docs/pricing/chat` (read 2026-10-26)
33
+ -- states the 1,048,576-token window and the cache-write-by-TTL billing logic,
34
+ -- and names this quickstart for ids and prices, but its table cells did not
35
+ -- render a citable per-model figure on that read. #208's rule — a number is
36
+ -- written only when somebody read it — is satisfied here in the form #208
37
+ -- itself allows as option 2: announcement-derived, provenance in the note,
38
+ -- correctable when the page prints the cells. Two independent reports print
39
+ -- the same figures (Artificial Analysis: $2/$10; VentureBeat: $4/$20
40
+ -- Highspeed), which is corroboration, not provenance — the note says which.
41
+ --
42
+ -- 1 MTok = 1,000,000 tokens; micros per MTok = USD x 1,000,000:
43
+ --
44
+ -- kimi-k3.1-pro: input 2000000, output 10000000, cached 200000
45
+ -- kimi-k3.1-pro-highspeed: input 4000000, output 20000000, cached 200000
46
+ --
47
+ -- **Cache writes are recorded here, not as `price_components` rows.** K3
48
+ -- billing charges cache writes separately by TTL (5min: $2.00/$4.00 per MTok;
49
+ -- 1h: $4.00/$8.00 per MTok → 2000000/4000000 and 4000000/8000000 micros per
50
+ -- MTok). `cache_write` has a vocabulary entry and no reader — `READERS` in
51
+ -- `src/pricing-components.ts` reads `request`, `search`, `character` and
52
+ -- `image` only — and a model carrying a row with no reader fails closed as
53
+ -- `unread` at bound time. Writing the rows now would make both models
54
+ -- unroutable to billed tenants, which is exactly why 0058 wrote none for
55
+ -- Anthropic's write rates either. The reader lands first; the rows follow.
56
+ --
57
+ -- ## `data_retention` is NULL, and that is the read, not the default
58
+ --
59
+ -- Moonshot did not state a training term in the launch: third parties report
60
+ -- "zero data retention available to API customers" as an enterprise on-request
61
+ -- option, with default traffic not covered by it. An option on request is an
62
+ -- account setting, the same shape as ElevenLabs' plan-dependent rows (0059)
63
+ -- and the pre-0109 Google tier — so NULL joins `ACCOUNT_DEPENDENT` in
64
+ -- `test/catalogue-retention.test.ts` rather than inventing `retained`, which
65
+ -- would pass `no-training-on-data` on a guess. Fill when the terms are read (#454).
66
+ --
67
+ -- ## The K2 clock, and what this file does not do
68
+ --
69
+ -- The same announcement retires the K2 series: no newly registered users from
70
+ -- 2026-10-31, all K2 models retired by end of December 2026. That touches
71
+ -- `workers-ai/@cf/moonshotai/kimi-k2.6` and `kimi-k2.7-code` (0025), both lane
72
+ -- members (0075, 0088) — K3.1 Pro is their migration target, and K2 member
73
+ -- removal is its own dated follow-up once the retirement is confirmed, not
74
+ -- this file.
75
+ --
76
+ -- Nothing here is routable and nothing joins a lane (0049's shape): both rows
77
+ -- land with `measured_at` NULL, and the gate refuses them until a conformance
78
+ -- run measures them. Lane placement is the allocation decision that follows
79
+ -- measurement, tracked in #700's acceptance list.
80
+ --
81
+ -- ## The dates are UTC
82
+ --
83
+ -- Read 2026-10-26 on both the announcement and the pricing and quickstart
84
+ -- pages. 0020 and 0021: a row dated in the future prices in the future and
85
+ -- every request reads as unpriced until then.
86
+
87
+ INSERT INTO upstreams (id, name, kind, base_url) VALUES
88
+ ('moonshot', 'Moonshot', 'provider', 'https://api.moonshot.ai/v1');
89
+
90
+ INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output) VALUES
91
+ ('moonshot/kimi-k3.1-pro', 'moonshot', 'kimi-k3.1-pro', 1048576, NULL),
92
+ ('moonshot/kimi-k3.1-pro-highspeed', 'moonshot', 'kimi-k3.1-pro-highspeed', 1048576, NULL);
93
+
94
+ -- `max_output` stays NULL on both: no maximum output is published, so 0011's
95
+ -- rule holds — never write a number you did not fetch — and `checkLimits`
96
+ -- derives the bound from the window while billed callers send `max_tokens`.
97
+
98
+ INSERT INTO price_observations
99
+ (observed_at, model, effective_from, prompt_tokens_from, peak_utc,
100
+ input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source, note)
101
+ VALUES
102
+ ('2026-10-26 00:00:00', 'moonshot/kimi-k3.1-pro', '2026-10-26', 0, '',
103
+ 2000000, 10000000, 200000, 'https://platform.kimi.ai/docs/pricing/chat',
104
+ 'First observation: Kimi K3.1 Pro catalogued (0120, #700). Figures from the Kimi API team announcement 2026-10-26 UTC ($2.00 in, $10.00 out, $0.20 cached per MTok; cache writes $2.00 5min / $4.00 1h held in the migration comment, no reader yet); K3 series section of the pricing page confirms the 1,048,576 window and TTL-graded cache-write billing. Re-read the page before treating these as page-quoted.'),
105
+ ('2026-10-26 00:00:00', 'moonshot/kimi-k3.1-pro-highspeed', '2026-10-26', 0, '',
106
+ 4000000, 20000000, 200000, 'https://platform.kimi.ai/docs/pricing/chat',
107
+ 'First observation: Kimi K3.1 Pro Highspeed catalogued (0120, #700). Same provenance as the Pro row ($4.00 in, $20.00 out, $0.20 cached per MTok; cache writes $4.00 5min / $8.00 1h held in the migration comment).');
@@ -0,0 +1,100 @@
1
+ -- Jobs: work submitted now and finished later, posted to a hook the project
2
+ -- registered (#712, #714).
3
+ --
4
+ -- Every request Cruise has served until now is synchronous: the reserve, the
5
+ -- upstream call and the settle all happen inside one invocation, and the
6
+ -- journal (0106) exists for the case where that invocation dies. A job breaks
7
+ -- the assumption the journal's threshold rests on — a provider batch has up to
8
+ -- 24 hours to finish — so this migration adds the job, the hook it reports to,
9
+ -- and the one column that tells the sweep a hold is long on purpose.
10
+ --
11
+ -- Provider batch (#716) is the first and, for now, only kind. The table says
12
+ -- so in its CHECK rather than accepting kinds nothing writes: a kind is added
13
+ -- by the migration that adds the code serving it.
14
+
15
+ -- ## Webhook endpoints: registered, never per request
16
+ --
17
+ -- A job names one of these, never an arbitrary URL. Checking an address once,
18
+ -- at registration, by a member with write access, is a check that can be
19
+ -- audited; a URL in every request body is an SSRF surface on the data plane
20
+ -- and a secret to hand out per call (#712).
21
+ --
22
+ -- **No secret is stored.** The signing secret is derived: HMAC-SHA256 of
23
+ -- `<id>:<secret_version>` under the Worker secret `WEBHOOK_SIGNING_KEY`
24
+ -- (`src/webhook-endpoints.ts`). A row here, read by anyone with console access
25
+ -- to D1, signs nothing. Rotating bumps `secret_version`; for a day after,
26
+ -- deliveries carry both signatures, which Standard Webhooks allows, so a
27
+ -- receiver can roll its secret without dropping an event.
28
+ --
29
+ -- Disabled, never deleted: a job references the endpoint it delivered to.
30
+ CREATE TABLE webhook_endpoints (
31
+ id TEXT PRIMARY KEY,
32
+ project_id TEXT NOT NULL REFERENCES projects(id),
33
+ url TEXT NOT NULL,
34
+ secret_version INTEGER NOT NULL DEFAULT 1 CHECK (secret_version >= 1),
35
+ rotated_at TEXT,
36
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
37
+ created_by TEXT NOT NULL,
38
+ disabled_at TEXT,
39
+ disabled_by TEXT,
40
+ disabled_reason TEXT
41
+ );
42
+
43
+ CREATE INDEX idx_webhook_endpoints_project ON webhook_endpoints (project_id, disabled_at);
44
+
45
+ -- ## Jobs
46
+ --
47
+ -- The money is not here. A job's hold is a `reservations` row like any other,
48
+ -- named by `reservation_id`, so reconcile already counts it (src/reconcile.ts
49
+ -- adds open holds to the ledger sum) and the one statement that enforces a cap
50
+ -- is the one that took it. `reserved_micros` is the figure as reserved, kept
51
+ -- because the journal row is deleted when the hold is released and the job
52
+ -- should still say what it held.
53
+ --
54
+ -- `delivery` is separate from `status` because they fail separately: a batch
55
+ -- can succeed and its hook be down for a day. `undelivered` is terminal for
56
+ -- the callback, never for the result.
57
+ --
58
+ -- `idempotency_key` is unique per project, so a retried submit finds the job
59
+ -- the first one made instead of reserving twice.
60
+ CREATE TABLE jobs (
61
+ id TEXT PRIMARY KEY,
62
+ project_id TEXT NOT NULL REFERENCES projects(id),
63
+ kind TEXT NOT NULL CHECK (kind IN ('batch')),
64
+ status TEXT NOT NULL DEFAULT 'queued'
65
+ CHECK (status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
66
+ reservation_id TEXT NOT NULL,
67
+ reserved_micros INTEGER NOT NULL CHECK (reserved_micros >= 0),
68
+ webhook_endpoint_id TEXT REFERENCES webhook_endpoints(id),
69
+ delivery TEXT NOT NULL DEFAULT 'none'
70
+ CHECK (delivery IN ('none', 'pending', 'delivered', 'undelivered')),
71
+ delivery_attempts INTEGER NOT NULL DEFAULT 0,
72
+ next_delivery_at TEXT,
73
+ idempotency_key TEXT,
74
+ error TEXT,
75
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
76
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
77
+ completed_at TEXT,
78
+ delivered_at TEXT,
79
+ UNIQUE (project_id, idempotency_key),
80
+ -- A callback is owed only once the job is over. Every writer already keeps
81
+ -- to this (the release and the sweep set `pending` in the statement that
82
+ -- makes the job terminal), and the schema says so, so a job still running
83
+ -- can never carry a delivery schedule for a later write to clobber (#717
84
+ -- review).
85
+ CHECK (delivery = 'none' OR status IN ('succeeded', 'failed', 'cancelled'))
86
+ );
87
+
88
+ CREATE INDEX idx_jobs_project ON jobs (project_id, created_at);
89
+ -- What the delivery loop and doctor read: callbacks still owed, oldest first.
90
+ CREATE INDEX idx_jobs_delivery ON jobs (delivery, next_delivery_at);
91
+
92
+ -- ## The hold knows it belongs to a job
93
+ --
94
+ -- The sweep closes a hold older than two hours as abandoned
95
+ -- (`ABANDONED_AFTER_SECONDS`), which is right for a request and wrong for a
96
+ -- batch that is still inside its provider's window. A NULL here is every hold
97
+ -- written before this migration and every synchronous one after it, so the
98
+ -- sweep's existing rule is unchanged for them; a hold with a job gets the
99
+ -- job's longer threshold instead (`JOB_ABANDONED_AFTER_SECONDS`).
100
+ ALTER TABLE reservations ADD COLUMN job_id TEXT;