@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.
- package/LICENSE +202 -0
- package/README.md +37 -2
- package/index.d.ts +14 -0
- package/index.mjs +41 -0
- package/migrations/0001_virtual_keys.sql +102 -0
- package/migrations/0002_seed_projects.sql +16 -0
- package/migrations/0003_budgets.sql +43 -0
- package/migrations/0004_tenant_isolation_and_integer_money.sql +49 -0
- package/migrations/0005_model_prices.sql +42 -0
- package/migrations/0006_budget_reservation.sql +38 -0
- package/migrations/0007_routing_table.sql +93 -0
- package/migrations/0008_measurement_provenance.sql +24 -0
- package/migrations/0009_conformance.sql +37 -0
- package/migrations/0010_conformance_key.sql +20 -0
- package/migrations/0011_correct_workers_ai_price.sql +30 -0
- package/migrations/0012_rate_limits.sql +28 -0
- package/migrations/0013_deepseek_and_mistral.sql +42 -0
- package/migrations/0014_cost_ledger.sql +104 -0
- package/migrations/0015_memberships.sql +33 -0
- package/migrations/0016_latency.sql +23 -0
- package/migrations/0017_ledger_provider_index.sql +8 -0
- package/migrations/0018_fallback_chains.sql +34 -0
- package/migrations/0019_rate_buckets.sql +27 -0
- package/migrations/0020_mistral_price_and_pin.sql +62 -0
- package/migrations/0021_mistral_price_date_is_utc.sql +35 -0
- package/migrations/0022_drop_unenforced_key_budget.sql +32 -0
- package/migrations/0023_model_limits.sql +48 -0
- package/migrations/0024_conditional_prices.sql +84 -0
- package/migrations/0025_catalogue_from_keyed_hosts.sql +172 -0
- package/migrations/0026_lanes.sql +83 -0
- package/migrations/0027_lane_alternatives.sql +36 -0
- package/migrations/0028_lanes_tenant_scope.sql +66 -0
- package/migrations/0029_lane_jobs.sql +146 -0
- package/migrations/0030_lane_requires.sql +38 -0
- package/migrations/0031_tenant_billable.sql +15 -0
- package/migrations/0032_cache_hit_billing.sql +35 -0
- package/migrations/0033_sell_markup.sql +37 -0
- package/migrations/0034_tiers_and_lane_quotas.sql +38 -0
- package/migrations/0035_wallet_scope.sql +68 -0
- package/migrations/0036_credit_grants.sql +53 -0
- package/migrations/0037_reconciliation.sql +45 -0
- package/migrations/0038_balance_service_keys.sql +35 -0
- package/migrations/0039_deepseek_peak_is_weekdays.sql +77 -0
- package/migrations/0040_glm_5_3_on_workers_ai.sql +63 -0
- package/migrations/0041_mistral_sweep_2026_08_29.sql +89 -0
- package/migrations/0042_provision_service_keys.sql +50 -0
- package/migrations/0043_tier_project_quota.sql +32 -0
- package/migrations/0044_audit_tenant_scope.sql +49 -0
- package/migrations/0045_audit_backfill_derivable.sql +42 -0
- package/migrations/0046_measurement_note.sql +24 -0
- package/migrations/0047_ledger_max_tokens.sql +21 -0
- package/migrations/0048_price_observations.sql +140 -0
- package/migrations/0049_openai_and_gemini.sql +239 -0
- package/migrations/0050_meta_direct_upstream.sql +127 -0
- package/migrations/0051_upstream_credential_and_operator.sql +74 -0
- package/migrations/0052_muse_spark_1_3.sql +71 -0
- package/migrations/0053_anthropic_groq_and_xai.sql +172 -0
- package/migrations/0054_tier_service_keys.sql +60 -0
- package/migrations/0055_output_defaults.sql +79 -0
- package/migrations/0056_model_modality.sql +37 -0
- package/migrations/0057_openai_image_models.sql +177 -0
- package/migrations/0058_price_components.sql +230 -0
- package/migrations/0059_speech.sql +151 -0
- package/migrations/0060_embeddings.sql +131 -0
- package/migrations/0061_data_retention_backfill.sql +121 -0
- package/migrations/0062_gemini_embedding_disabled.sql +125 -0
- package/migrations/0063_google_provider_path_prefix.sql +59 -0
- package/migrations/0064_economics_service_keys.sql +51 -0
- package/migrations/0065_lane_selection.sql +66 -0
- package/migrations/0066_tenant_default_selection.sql +42 -0
- package/migrations/0067_graduated_selection.sql +103 -0
- package/migrations/0068_cache_scope.sql +73 -0
- package/migrations/0069_lane_cache_settings.sql +50 -0
- package/migrations/0070_lane_member_quality_rank.sql +98 -0
- package/migrations/0071_key_cache_pool.sql +60 -0
- package/migrations/0072_cache_digest.sql +51 -0
- package/migrations/0073_lane_max_chain.sql +51 -0
- package/migrations/0074_hunter_builder_lanes.sql +149 -0
- package/migrations/0075_hunter_builder_frontline.sql +36 -0
- package/migrations/0076_deepseek_flash.sql +86 -0
- package/migrations/0077_gpt_6_astra.sql +35 -0
- package/migrations/0078_astra_deep_reasoning.sql +20 -0
- package/migrations/0079_gemini_flash_lite_extraction.sql +15 -0
- package/migrations/0080_priced_by.sql +24 -0
- package/migrations/0081_grok_imagine.sql +81 -0
- package/migrations/0082_markup_three_percent.sql +32 -0
- package/migrations/0083_markup_per_tenant_and_tier.sql +57 -0
- package/migrations/0084_coding_lanes_frontier.sql +93 -0
- package/migrations/0085_minute_period_and_demo_charge.sql +77 -0
- package/migrations/0086_project_sentry.sql +41 -0
- package/migrations/0087_lane_router.sql +71 -0
- package/migrations/0088_openai_frontier_coding_lanes.sql +54 -0
- package/migrations/0089_agentic_coding_drops_codestral.sql +44 -0
- package/migrations/0090_board_followups_2026_10.sql +196 -0
- package/migrations/0091_opus_5_5_coding_lanes.sql +43 -0
- package/migrations/0092_deepseek_peak_holidays.sql +83 -0
- package/migrations/0093_tool_choice_forced.sql +26 -0
- package/migrations/0094_board_followups_2026_10_08.sql +115 -0
- package/migrations/0095_request_compression.sql +43 -0
- package/migrations/0096_lane_compress.sql +36 -0
- package/migrations/0097_tenant_default_compress.sql +34 -0
- package/migrations/0098_ledger_session.sql +47 -0
- package/migrations/0099_wallet_low_water_backfill.sql +47 -0
- package/migrations/0100_rag_grounded_answers_lane.sql +92 -0
- package/migrations/0101_perplexity_agent_api.sql +125 -0
- package/migrations/0102_web_search_job_and_flag.sql +137 -0
- package/migrations/0103_openai_web_search_price.sql +44 -0
- package/migrations/0104_web_search_lane.sql +82 -0
- package/migrations/0105_web_search_lane_billed.sql +22 -0
- package/migrations/0106_reservations_journal.sql +64 -0
- package/migrations/0107_session_cap.sql +65 -0
- package/migrations/0108_ledger_attempts.sql +41 -0
- package/migrations/0109_gemini_retention.sql +39 -0
- package/migrations/0110_gemini_4_argon.sql +110 -0
- package/migrations/0111_gemini_4_argon_lanes.sql +80 -0
- package/migrations/0112_ledger_affinity.sql +42 -0
- package/migrations/0113_contributor_lane_namespace.sql +125 -0
- package/migrations/0114_meta_contributor_models.sql +55 -0
- package/migrations/0115_oss_chat_assistant_lane.sql +41 -0
- package/migrations/0116_promo_credits.sql +63 -0
- package/migrations/0117_oss_mirror_lanes.sql +85 -0
- package/migrations/0118_project_management_job.sql +112 -0
- package/migrations/0119_oss_project_management_lane.sql +29 -0
- package/migrations/0120_moonshot_k3_1_pro.sql +107 -0
- package/migrations/0121_jobs.sql +100 -0
- package/migrations/0122_batch_prices.sql +188 -0
- package/migrations/0123_batch_files.sql +50 -0
- package/migrations/0124_batch_run.sql +21 -0
- package/migrations/0125_anthropic_path_prefix.sql +22 -0
- package/package.json +37 -4
- package/worker/284906b51fc0a3173ea7d301234907f30e834f54-cruise-mark-64.png +0 -0
- package/worker/2c39de526314484775fdfc503fac50c437d21e4e-cruise-logo-240.png +0 -0
- package/worker/63fb63e2d8ae6d8b68228768ef6c91ab8f0c0100-cruise-logo-480.png +0 -0
- package/worker/VERSION +1 -0
- package/worker/b23bfbc792e8710d3b74284a0a1b8ab044c18897-logo-dark.png +0 -0
- package/worker/index.js +31451 -0
- package/wrangler.template.jsonc +48 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
-- A declared order among a lane's members, so a lane hit can only be an
|
|
2
|
+
-- upgrade (#278, epic #272). Spec: #20, auto-mode.md §6.
|
|
3
|
+
--
|
|
4
|
+
-- ## What the rank is for
|
|
5
|
+
--
|
|
6
|
+
-- Lane scope relaxes exactly one term of the cache key — the model — so an
|
|
7
|
+
-- answer a frontier member already produced can serve a request the lane
|
|
8
|
+
-- would have sent to a cheaper one. That is a saving and a quality upgrade at
|
|
9
|
+
-- once, which is what makes it safe. Reverse the direction and it is the
|
|
10
|
+
-- worst failure available to this system: a worse answer, reported as a hit
|
|
11
|
+
-- from a better model, invisible to the caller who is billed a fraction for
|
|
12
|
+
-- it. `rank` is the column that fixes the direction.
|
|
13
|
+
--
|
|
14
|
+
-- 1 is best. A hit is served only when the entry's origin ranks at or above
|
|
15
|
+
-- the member the lane would otherwise have sent to, and **NULL on either side
|
|
16
|
+
-- is a miss** — an unranked member is not "probably fine", it is a model
|
|
17
|
+
-- nobody has placed, and placing it is the act this column records.
|
|
18
|
+
--
|
|
19
|
+
-- ## Why it is declared, and not derived
|
|
20
|
+
--
|
|
21
|
+
-- Not from `position`, which is listing order and has never meant quality —
|
|
22
|
+
-- 0026 says so in as many words: `lane_members` is the candidate set, not a
|
|
23
|
+
-- priority. Not from price either: #19 scores on price alone precisely
|
|
24
|
+
-- because quality is unmeasured, so deriving quality back out of price would
|
|
25
|
+
-- be circular, and a lane's cheapest member is frequently not its worst.
|
|
26
|
+
--
|
|
27
|
+
-- auto-mode.md §6 asks for an ordering that is "statistically clear, not
|
|
28
|
+
-- nominal", and holds that cross-model serving is permitted only across a
|
|
29
|
+
-- margin wide enough to survive its own confidence interval. **There is no
|
|
30
|
+
-- such measurement yet, and this column is not it.** It is a person's reading
|
|
31
|
+
-- of model families and sizes, written down so the direction is at least
|
|
32
|
+
-- stated rather than assumed. The margin is the follow-up, and it needs a
|
|
33
|
+
-- quality signal this repo does not collect; that is named here so the next
|
|
34
|
+
-- person does not mistake a declared order for the designed one.
|
|
35
|
+
--
|
|
36
|
+
-- ## The values below
|
|
37
|
+
--
|
|
38
|
+
-- Coarse on purpose, three or four tiers per lane rather than a total order.
|
|
39
|
+
-- A tie asserts the two members are peers for this lane's job, and either may
|
|
40
|
+
-- serve the other's answer; separating models this repo cannot tell apart
|
|
41
|
+
-- would be a precision the input does not have. Proposed 2026-09-07 against
|
|
42
|
+
-- the eight global lanes as they stood, and reviewed before merge by the
|
|
43
|
+
-- person who owns them.
|
|
44
|
+
--
|
|
45
|
+
-- Tenant lanes are left NULL. Nobody here can rank another tenant's members,
|
|
46
|
+
-- and the control plane is how their owner does it (#278).
|
|
47
|
+
--
|
|
48
|
+
-- ## Why `quality_rank` and not `rank`
|
|
49
|
+
--
|
|
50
|
+
-- #278 proposed `rank`, and the word was already taken twice. The published
|
|
51
|
+
-- API reference uses "rank" for the *allocator's* order under `graduated`
|
|
52
|
+
-- selection — "rate-limited first, then failing, then price"
|
|
53
|
+
-- (`openapi-schemas-lanes.ts`) — and `tierOf` in `lanes-quota.ts` is the
|
|
54
|
+
-- tenant's billing tier. Either collision is the kind that reads fine until
|
|
55
|
+
-- somebody wires `graduated`'s shares to this column, at which point a lane
|
|
56
|
+
-- distributes traffic by a quality order nobody meant it to, and the two
|
|
57
|
+
-- meanings are close enough that the mistake would survive review. The name
|
|
58
|
+
-- says which rank it is.
|
|
59
|
+
|
|
60
|
+
ALTER TABLE lane_members ADD COLUMN quality_rank INTEGER;
|
|
61
|
+
|
|
62
|
+
-- 1 = best. Written per lane, so a member appearing in two lanes can rank
|
|
63
|
+
-- differently in each — `codestral` is a first-tier code-completion model and
|
|
64
|
+
-- a second-tier agentic-coding one, and that is a fact about the job, not
|
|
65
|
+
-- about the model.
|
|
66
|
+
|
|
67
|
+
UPDATE lane_members SET quality_rank = 1 WHERE lane_id = 'bb/agentic-coding' AND model_id IN ('deepseek/deepseek-v4-pro');
|
|
68
|
+
UPDATE lane_members SET quality_rank = 2 WHERE lane_id = 'bb/agentic-coding' AND model_id IN ('mistral/mistral-medium-2604', 'mistral/codestral-2508');
|
|
69
|
+
UPDATE lane_members SET quality_rank = 3 WHERE lane_id = 'bb/agentic-coding' AND model_id IN ('deepseek/deepseek-v4-flash');
|
|
70
|
+
UPDATE lane_members SET quality_rank = 4 WHERE lane_id = 'bb/agentic-coding' AND model_id IN ('workers-ai/@cf/qwen/qwen3.8-27b');
|
|
71
|
+
|
|
72
|
+
UPDATE lane_members SET quality_rank = 1 WHERE lane_id = 'bb/chat-assistant' AND model_id IN ('mistral/mistral-small-latest');
|
|
73
|
+
UPDATE lane_members SET quality_rank = 2 WHERE lane_id = 'bb/chat-assistant' AND model_id IN ('mistral/ministral-8b-2512', 'workers-ai/@cf/google/gemma-4-26b-a4b-it', 'workers-ai/@cf/openai/gpt-oss-20b', 'workers-ai/@cf/zai-org/glm-4.7-flash');
|
|
74
|
+
UPDATE lane_members SET quality_rank = 3 WHERE lane_id = 'bb/chat-assistant' AND model_id IN ('mistral/ministral-3b-2512', 'workers-ai/@cf/meta/llama-3.2-3b-instruct');
|
|
75
|
+
|
|
76
|
+
UPDATE lane_members SET quality_rank = 1 WHERE lane_id = 'bb/code-completion' AND model_id IN ('mistral/codestral-2508');
|
|
77
|
+
UPDATE lane_members SET quality_rank = 2 WHERE lane_id = 'bb/code-completion' AND model_id IN ('deepseek/deepseek-v4-flash');
|
|
78
|
+
UPDATE lane_members SET quality_rank = 3 WHERE lane_id = 'bb/code-completion' AND model_id IN ('workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct', 'workers-ai/@cf/qwen/qwen3.8-27b');
|
|
79
|
+
|
|
80
|
+
UPDATE lane_members SET quality_rank = 1 WHERE lane_id = 'bb/code-review' AND model_id IN ('deepseek/deepseek-v4-pro', 'mistral/mistral-large-2512');
|
|
81
|
+
UPDATE lane_members SET quality_rank = 2 WHERE lane_id = 'bb/code-review' AND model_id IN ('mistral/mistral-medium-2604', 'workers-ai/@cf/openai/gpt-oss-120b');
|
|
82
|
+
UPDATE lane_members SET quality_rank = 3 WHERE lane_id = 'bb/code-review' AND model_id IN ('deepseek/deepseek-v4-flash');
|
|
83
|
+
|
|
84
|
+
UPDATE lane_members SET quality_rank = 1 WHERE lane_id = 'bb/deep-reasoning' AND model_id IN ('deepseek/deepseek-v4-pro');
|
|
85
|
+
UPDATE lane_members SET quality_rank = 2 WHERE lane_id = 'bb/deep-reasoning' AND model_id IN ('workers-ai/@cf/openai/gpt-oss-120b', 'workers-ai/@cf/nvidia/nemotron-3-120b-a12b');
|
|
86
|
+
UPDATE lane_members SET quality_rank = 3 WHERE lane_id = 'bb/deep-reasoning' AND model_id IN ('workers-ai/@cf/qwen/qwq-32b', 'workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b', 'mistral/mistral-medium-2604');
|
|
87
|
+
|
|
88
|
+
UPDATE lane_members SET quality_rank = 1 WHERE lane_id = 'bb/extraction' AND model_id IN ('mistral/mistral-small-latest', 'deepseek/deepseek-v4-flash');
|
|
89
|
+
UPDATE lane_members SET quality_rank = 2 WHERE lane_id = 'bb/extraction' AND model_id IN ('mistral/ministral-8b-2512', 'workers-ai/@cf/zai-org/glm-4.7-flash');
|
|
90
|
+
UPDATE lane_members SET quality_rank = 3 WHERE lane_id = 'bb/extraction' AND model_id IN ('workers-ai/@cf/ibm-granite/granite-4.0-h-micro');
|
|
91
|
+
|
|
92
|
+
UPDATE lane_members SET quality_rank = 1 WHERE lane_id = 'bb/summarization' AND model_id IN ('mistral/mistral-small-latest', 'deepseek/deepseek-v4-flash');
|
|
93
|
+
UPDATE lane_members SET quality_rank = 2 WHERE lane_id = 'bb/summarization' AND model_id IN ('mistral/ministral-8b-2512', 'workers-ai/@cf/google/gemma-4-26b-a4b-it', 'workers-ai/@cf/zai-org/glm-4.7-flash');
|
|
94
|
+
UPDATE lane_members SET quality_rank = 3 WHERE lane_id = 'bb/summarization' AND model_id IN ('workers-ai/@cf/meta/llama-3.2-3b-instruct');
|
|
95
|
+
|
|
96
|
+
UPDATE lane_members SET quality_rank = 1 WHERE lane_id = 'bb/translation' AND model_id IN ('mistral/mistral-medium-2604');
|
|
97
|
+
UPDATE lane_members SET quality_rank = 2 WHERE lane_id = 'bb/translation' AND model_id IN ('mistral/mistral-small-latest', 'mistral/ministral-14b-2512');
|
|
98
|
+
UPDATE lane_members SET quality_rank = 3 WHERE lane_id = 'bb/translation' AND model_id IN ('workers-ai/@cf/google/gemma-4-26b-a4b-it', 'workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it', 'deepseek/deepseek-v4-flash');
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
-- The pool a key's cached answers are shared within (#279, epic #272).
|
|
2
|
+
-- Spec: #20, auto-mode.md §6, v0.md §4.
|
|
3
|
+
--
|
|
4
|
+
-- ## Why this column exists at all
|
|
5
|
+
--
|
|
6
|
+
-- auto-mode.md §6 is blunt about the trade: a cache spanning projects
|
|
7
|
+
-- dissolves v0's isolation model deliberately, and cross-project sharing is
|
|
8
|
+
-- where most of the savings live. Per-project is the default and stays the
|
|
9
|
+
-- default; this column is the *widening*, and the whole design of it is that
|
|
10
|
+
-- a caller cannot perform the widening on itself.
|
|
11
|
+
--
|
|
12
|
+
-- Three pools, and the key names one:
|
|
13
|
+
--
|
|
14
|
+
-- project {tenant}:{project} the default, and the only pool an unmarked key touches
|
|
15
|
+
-- tenant {tenant} every marked key in the tenant
|
|
16
|
+
-- platform bb ours: the conformance runner, eval prep, internal tooling
|
|
17
|
+
--
|
|
18
|
+
-- `platform` is the deliberate version auto-mode.md §6 asks for — a `bb/` lane's hot set,
|
|
19
|
+
-- paid for once at frontier quality, serving every project underneath. It is
|
|
20
|
+
-- not something a tenant can reach: `issueKey` refuses it unless the key's
|
|
21
|
+
-- project belongs to a tenant with `operator = 1` (0051), which is the same
|
|
22
|
+
-- column that decides who may read the platform's own state, and `doctor`
|
|
23
|
+
-- re-asks the question of every live key rather than trusting the write.
|
|
24
|
+
--
|
|
25
|
+
-- ## Why it is on the key, and not on the request
|
|
26
|
+
--
|
|
27
|
+
-- A traffic class is a label the caller chooses within what the key allows
|
|
28
|
+
-- (`src/metadata.ts`), and that is exactly the shape this must not have. A
|
|
29
|
+
-- caller declaring "my traffic carries no end-user content" is a caller
|
|
30
|
+
-- widening its own cache pool, which is the mistake the gate exists to
|
|
31
|
+
-- prevent — and it would be a privacy incident rather than a bug, because the
|
|
32
|
+
-- widening is invisible from both sides: the project whose answer leaks sent
|
|
33
|
+
-- a request that succeeded, and the project that received it was served a
|
|
34
|
+
-- correct answer to its own question.
|
|
35
|
+
--
|
|
36
|
+
-- So it is set once, at issue, by someone who has read what the key will
|
|
37
|
+
-- carry, and it lands in `audit_events` beside the issue like every other
|
|
38
|
+
-- privileged act (0044). A key's pool can be narrowed afterwards; widening is
|
|
39
|
+
-- a new key, because the argument for the wider pool was made about the
|
|
40
|
+
-- traffic the old key was already sending.
|
|
41
|
+
--
|
|
42
|
+
-- ## Read down, write own
|
|
43
|
+
--
|
|
44
|
+
-- A marked key **reads** its own pool and every narrower one, and **writes**
|
|
45
|
+
-- only its own. So a project key never sees another project's entry; a
|
|
46
|
+
-- tenant-pool key never sees another tenant's; and a tenant-pool key's write
|
|
47
|
+
-- is not visible to a project-pool key in the same project, which is the
|
|
48
|
+
-- direction that keeps the default honest — an unmarked key behaves today
|
|
49
|
+
-- exactly as it did before this migration, whatever its neighbours are marked.
|
|
50
|
+
--
|
|
51
|
+
-- ## The default, and why NOT NULL
|
|
52
|
+
--
|
|
53
|
+
-- Every key issued before this reads back `project`, which is what it has been
|
|
54
|
+
-- doing since #274. NOT NULL with a default rather than a nullable column,
|
|
55
|
+
-- because a null here would have to be *interpreted*, and the two readings
|
|
56
|
+
-- ("unmarked, so narrowest" and "not yet decided") differ by exactly the
|
|
57
|
+
-- privacy property this column carries.
|
|
58
|
+
|
|
59
|
+
ALTER TABLE virtual_keys ADD COLUMN cache_pool TEXT NOT NULL DEFAULT 'project'
|
|
60
|
+
CHECK (cache_pool IN ('project', 'tenant', 'platform'));
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
-- The two facts a tier-rule violation is found from (#281, epic #272; the
|
|
2
|
+
-- rule is #20 and auto-mode.md §6, the measurement #21 and auto-mode.md §9).
|
|
3
|
+
--
|
|
4
|
+
-- A lane hit is an answer produced by a *different* model than the one this
|
|
5
|
+
-- request would have been sent to, served on the strength of a declared
|
|
6
|
+
-- order that says the origin ranks at or above it. Nothing measures that
|
|
7
|
+
-- order (#19: score is price-only), so the only evidence that it is wrong
|
|
8
|
+
-- comes from callers: a lane hit followed within minutes by the **same
|
|
9
|
+
-- normalised body from the same key** asking `scope=off` or `scope=model` is
|
|
10
|
+
-- a caller saying the replay was not good enough and paying for a live answer
|
|
11
|
+
-- to prove it. That is the violation counter, target zero.
|
|
12
|
+
--
|
|
13
|
+
-- The ledger could not find one. It kept `cache_scope` and the origin (0068),
|
|
14
|
+
-- and neither says what was asked nor lets two rows be recognised as the same
|
|
15
|
+
-- request. Hence two columns.
|
|
16
|
+
--
|
|
17
|
+
-- ## `cache_digest`
|
|
18
|
+
--
|
|
19
|
+
-- The whole unsalted SHA-256 of the normalised body — the last term of the
|
|
20
|
+
-- store key (`src/cache-store.ts`), so "the same request" here means exactly
|
|
21
|
+
-- what it means to the cache, and the violation counter can join a hit to the
|
|
22
|
+
-- live request that followed it. Not the prompt: the row still carries no
|
|
23
|
+
-- content. Not "nothing a person wrote" either (#374): an unsalted digest of a
|
|
24
|
+
-- short, guessable body confirms a guess exactly. Left unsalted on purpose —
|
|
25
|
+
-- salting both this column and the store key would keep the join and close
|
|
26
|
+
-- that oracle, at the cost that rotating the salt orphans every historical
|
|
27
|
+
-- digest and invalidates every cache entry. The digest is returned by no
|
|
28
|
+
-- route; who can read D1 can read the KV bodies directly. NULL when the cache
|
|
29
|
+
-- was off (`CACHE_MODE=off`, or no binding), which is when nothing can hit and
|
|
30
|
+
-- so nothing can be found to have hit wrongly; NULL on every row before this.
|
|
31
|
+
--
|
|
32
|
+
-- ## `cache_requested`
|
|
33
|
+
--
|
|
34
|
+
-- The scope the caller's `x-cruise-cache` asked for — `model`, `lane`, `off`
|
|
35
|
+
-- — NULL when the header named no scope, and NULL, like the digest, when the
|
|
36
|
+
-- cache was off. Kept separately from
|
|
37
|
+
-- `cache_scope`, which is what *served* and is NULL on every miss: the
|
|
38
|
+
-- violation is read from what was asked, on a row that was deliberately not
|
|
39
|
+
-- served from cache.
|
|
40
|
+
--
|
|
41
|
+
-- The index is the join the counter makes: a hit's key and digest, then
|
|
42
|
+
-- forward in time. Partial, because most rows have no digest and none of
|
|
43
|
+
-- them can be the second half of a violation.
|
|
44
|
+
|
|
45
|
+
ALTER TABLE ledger ADD COLUMN cache_digest TEXT;
|
|
46
|
+
ALTER TABLE ledger ADD COLUMN cache_requested TEXT
|
|
47
|
+
CHECK (cache_requested IS NULL OR cache_requested IN ('model', 'lane', 'off'));
|
|
48
|
+
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_ledger_cache_digest
|
|
50
|
+
ON ledger (key_prefix, cache_digest, at)
|
|
51
|
+
WHERE cache_digest IS NOT NULL;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
-- A lane holds its own chain depth (#362).
|
|
2
|
+
--
|
|
3
|
+
-- `MAX_CHAIN = 3` in `src/fallback.ts` bounds how many candidates one request
|
|
4
|
+
-- may try. It is a wall-clock bound and not a taste: every candidate gets the
|
|
5
|
+
-- **full** upstream deadline, so a five-member lane on a bad day is five
|
|
6
|
+
-- deadlines end to end, long after the caller stopped waiting. #244 wrote that
|
|
7
|
+
-- down and this column does not touch it. What it adds is the ability to ask
|
|
8
|
+
-- for **fewer**.
|
|
9
|
+
--
|
|
10
|
+
-- ## Two lanes want a shorter chain, and neither could ask
|
|
11
|
+
--
|
|
12
|
+
-- **Fail fast.** An interactive lane would rather hand back the provider's 429
|
|
13
|
+
-- and its `retry-after` in milliseconds and let the client decide than spend a
|
|
14
|
+
-- second full deadline discovering the same thing. A pinned model can already
|
|
15
|
+
-- say this — a chain with no fallbacks is depth 1, and `fallback:set` writes
|
|
16
|
+
-- it — and a lane could not. That asymmetry is what this closes.
|
|
17
|
+
--
|
|
18
|
+
-- **Members sharing an upstream.** `bb/long-context` is DeepSeek, DeepSeek,
|
|
19
|
+
-- Mistral, Mistral. DeepSeek throttles per organisation, so a 429 on the first
|
|
20
|
+
-- member is a 429 on the second: depth 3 there buys one useful attempt and one
|
|
21
|
+
-- round trip that could not have gone differently. `fallbacks-write.ts` already
|
|
22
|
+
-- warns an operator whose hand-written chain sits entirely on one upstream; a
|
|
23
|
+
-- lane has no equivalent. #361 is the half of that needing no setting.
|
|
24
|
+
--
|
|
25
|
+
-- ## NULL, not 3
|
|
26
|
+
--
|
|
27
|
+
-- 0069 gave `cache_ttl_seconds` NOT NULL DEFAULT 0 because 0 was a real
|
|
28
|
+
-- decision somebody could have made — the lane caches nothing — and every
|
|
29
|
+
-- existing lane had in fact been doing it. This column's default is not a
|
|
30
|
+
-- number. It is "whatever the platform bound is", and writing 3 into every row
|
|
31
|
+
-- would state a figure nobody chose and pin each lane to it on the day
|
|
32
|
+
-- `MAX_CHAIN` moves. So NULL means *defer to the platform*, every lane
|
|
33
|
+
-- existing today reads back NULL, and the constant stays in one place.
|
|
34
|
+
--
|
|
35
|
+
-- ## The CHECK repeats the constant, deliberately
|
|
36
|
+
--
|
|
37
|
+
-- 1 to 3, which is `MAX_CHAIN` said in SQL, the way 0069's 2592000 is
|
|
38
|
+
-- `CACHE_MAX_TTL_SECONDS` said in SQL. A value the request path would clamp
|
|
39
|
+
-- away is a value somebody would later read back and trust, so the table
|
|
40
|
+
-- refuses to hold one. The cost is that raising `MAX_CHAIN` needs a migration
|
|
41
|
+
-- as well as a constant — which is correct: raising it is a claim about how
|
|
42
|
+
-- long a Worker may hold a request open, and that deserves the paperwork.
|
|
43
|
+
-- `lanes-validate.ts` refuses the same range earlier, with a message; this is
|
|
44
|
+
-- the floor under it, not the report.
|
|
45
|
+
--
|
|
46
|
+
-- **Deploy order is migrate first, then the Worker.** Adding a column is
|
|
47
|
+
-- invisible to code that does not name it, so the running Worker is
|
|
48
|
+
-- unaffected; new code naming a column that is not there is what would fail.
|
|
49
|
+
|
|
50
|
+
ALTER TABLE lanes ADD COLUMN max_chain INTEGER
|
|
51
|
+
CHECK (max_chain IS NULL OR max_chain BETWEEN 1 AND 3);
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
-- Platform lanes for an agent tenant's Hunter and Builder (#409).
|
|
2
|
+
--
|
|
3
|
+
-- Both consumers already send `x-cruise-session` (affinity, #394) and
|
|
4
|
+
-- `x-cruise-class: agentic`, and both have been calling `bb/agentic-coding`.
|
|
5
|
+
-- That lane is the right *surface* — long tool-use over a repository — and
|
|
6
|
+
-- the wrong *job*: one quality ranking cannot optimise for "find and prove a
|
|
7
|
+
-- vuln" and "implement and prove green" at once. Separate lanes let each
|
|
8
|
+
-- product's outcome metrics retune members without dragging Claude Code's
|
|
9
|
+
-- general coding agent along.
|
|
10
|
+
--
|
|
11
|
+
-- ## Vocabulary ahead of the board
|
|
12
|
+
--
|
|
13
|
+
-- `hunter` and `builder` are not on the model board's job list as of this
|
|
14
|
+
-- migration. The board owns the words (#79); until it does, Cruise is one
|
|
15
|
+
-- step ahead for two product-facing defaults that cannot wait on a tenant
|
|
16
|
+
-- lane under `other`. The CHECK and `JOBS` grow together; a later board
|
|
17
|
+
-- rename is a migration, same as 0029's `bulk-extraction` → `extraction`.
|
|
18
|
+
--
|
|
19
|
+
-- ## Why rebuild rather than ALTER
|
|
20
|
+
--
|
|
21
|
+
-- SQLite cannot widen a CHECK. 0029 put the closed job set on `lanes.job`;
|
|
22
|
+
-- adding two words means recreating `lanes` (and its children that FK it).
|
|
23
|
+
-- Same shape as 0028/0029: new tables, copy, drop children then parent,
|
|
24
|
+
-- rename. No `PRAGMA foreign_keys` — D1 does not offer a usable deferral
|
|
25
|
+
-- (0067).
|
|
26
|
+
--
|
|
27
|
+
-- ## Member pools
|
|
28
|
+
--
|
|
29
|
+
-- Same bar as every other `bb/` lane: ≥3 routable, measured members with
|
|
30
|
+
-- real price spread. Overlap with `bb/agentic-coding` / `bb/code-review` is
|
|
31
|
+
-- expected; the *ranks* diverge.
|
|
32
|
+
--
|
|
33
|
+
-- bb/hunter — security expedition (prove by detonation). Prefer
|
|
34
|
+
-- security-strong members; codestral stays out (coding
|
|
35
|
+
-- polish invents plausible vulns). Flash is failover only.
|
|
36
|
+
-- bb/builder — implementation loop (prove by green tests). Coding-
|
|
37
|
+
-- strong first; flash last. Selection `graduated` on both
|
|
38
|
+
-- so a cheap flash does not own the sticky run.
|
|
39
|
+
--
|
|
40
|
+
-- `tools-required` on both, same as agentic-coding. `long-context` is not
|
|
41
|
+
-- seeded: several otherwise-fit members sit under 131k, and affinity already
|
|
42
|
+
-- holds the member once the run starts — a cold pick among short-window
|
|
43
|
+
-- models is a different problem than mid-run reallocation.
|
|
44
|
+
|
|
45
|
+
CREATE TABLE lanes_new (
|
|
46
|
+
id TEXT PRIMARY KEY,
|
|
47
|
+
tenant_id TEXT REFERENCES tenants(id),
|
|
48
|
+
job TEXT NOT NULL CHECK (job IN (
|
|
49
|
+
'chat-assistant', 'deep-reasoning', 'summarization', 'translation',
|
|
50
|
+
'content-writing', 'extraction', 'code-completion', 'agentic-coding',
|
|
51
|
+
'hunter', 'builder',
|
|
52
|
+
'code-review', 'document-understanding', 'speech', 'rag-grounded-answers',
|
|
53
|
+
'computer-use', 'content-moderation', 'other')),
|
|
54
|
+
description TEXT NOT NULL,
|
|
55
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
56
|
+
created_by TEXT NOT NULL DEFAULT 'migration',
|
|
57
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
58
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
59
|
+
archived_at TEXT,
|
|
60
|
+
selection TEXT NOT NULL DEFAULT 'cheap'
|
|
61
|
+
CHECK (selection IN ('cheap', 'random', 'weighted')),
|
|
62
|
+
selection_policy TEXT NOT NULL DEFAULT 'cheap'
|
|
63
|
+
CHECK (selection_policy IN ('cheap', 'random', 'weighted', 'graduated')),
|
|
64
|
+
cache_ttl_seconds INTEGER NOT NULL DEFAULT 0
|
|
65
|
+
CHECK (cache_ttl_seconds BETWEEN 0 AND 2592000),
|
|
66
|
+
cache_scope TEXT NOT NULL DEFAULT 'model'
|
|
67
|
+
CHECK (cache_scope IN ('model', 'lane')),
|
|
68
|
+
max_chain INTEGER
|
|
69
|
+
CHECK (max_chain IS NULL OR max_chain BETWEEN 1 AND 3),
|
|
70
|
+
CHECK (
|
|
71
|
+
(tenant_id IS NULL AND substr(id, 1, 3) = 'bb/') OR
|
|
72
|
+
(tenant_id IS NOT NULL AND substr(id, 1, length(tenant_id) + 1) = tenant_id || '/'
|
|
73
|
+
AND substr(id, 1, 3) <> 'bb/')
|
|
74
|
+
),
|
|
75
|
+
CHECK (tenant_id IS NOT NULL OR (id = 'bb/' || job AND job <> 'other'))
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
INSERT INTO lanes_new (
|
|
79
|
+
id, tenant_id, job, description, enabled, created_by, created_at, updated_at,
|
|
80
|
+
archived_at, selection, selection_policy, cache_ttl_seconds, cache_scope, max_chain
|
|
81
|
+
)
|
|
82
|
+
SELECT id, tenant_id, job, description, enabled, created_by, created_at, updated_at,
|
|
83
|
+
archived_at, selection, selection_policy, cache_ttl_seconds, cache_scope, max_chain
|
|
84
|
+
FROM lanes;
|
|
85
|
+
|
|
86
|
+
INSERT INTO lanes_new (id, job, description, selection_policy) VALUES
|
|
87
|
+
('bb/hunter', 'hunter',
|
|
88
|
+
'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.',
|
|
89
|
+
'graduated'),
|
|
90
|
+
('bb/builder', 'builder',
|
|
91
|
+
'Autonomous implementation loop: turn an issue into a green change. Edit, run tests, iterate on failures; finish verified-green or honestly unfinished.',
|
|
92
|
+
'graduated');
|
|
93
|
+
|
|
94
|
+
CREATE TABLE lane_members_new (
|
|
95
|
+
lane_id TEXT NOT NULL REFERENCES lanes_new(id),
|
|
96
|
+
model_id TEXT NOT NULL REFERENCES models(id),
|
|
97
|
+
position INTEGER NOT NULL,
|
|
98
|
+
weight REAL NOT NULL DEFAULT 1 CHECK (weight > 0),
|
|
99
|
+
quality_rank INTEGER,
|
|
100
|
+
PRIMARY KEY (lane_id, model_id)
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
INSERT INTO lane_members_new (lane_id, model_id, position, weight, quality_rank)
|
|
104
|
+
SELECT lane_id, model_id, position, weight, quality_rank FROM lane_members;
|
|
105
|
+
|
|
106
|
+
-- Position is listing order only. quality_rank is 1 = best for this lane's job.
|
|
107
|
+
INSERT INTO lane_members_new (lane_id, model_id, position, quality_rank) VALUES
|
|
108
|
+
('bb/hunter', 'deepseek/deepseek-v4-pro', 1, 1),
|
|
109
|
+
('bb/hunter', 'mistral/mistral-large-2512', 2, 2),
|
|
110
|
+
('bb/hunter', 'mistral/mistral-medium-2604', 3, 2),
|
|
111
|
+
('bb/hunter', 'workers-ai/@cf/openai/gpt-oss-120b', 4, 3),
|
|
112
|
+
('bb/hunter', 'deepseek/deepseek-v4-flash', 5, 4),
|
|
113
|
+
|
|
114
|
+
('bb/builder', 'deepseek/deepseek-v4-pro', 1, 1),
|
|
115
|
+
('bb/builder', 'mistral/codestral-2508', 2, 1),
|
|
116
|
+
('bb/builder', 'mistral/mistral-medium-2604', 3, 2),
|
|
117
|
+
('bb/builder', 'workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct', 4, 3),
|
|
118
|
+
('bb/builder', 'deepseek/deepseek-v4-flash', 5, 4),
|
|
119
|
+
('bb/builder', 'workers-ai/@cf/qwen/qwen3.8-27b', 6, 4);
|
|
120
|
+
|
|
121
|
+
CREATE TABLE lane_requires_new (
|
|
122
|
+
lane_id TEXT NOT NULL REFERENCES lanes_new(id),
|
|
123
|
+
constraint_ TEXT NOT NULL CHECK (constraint_ IN (
|
|
124
|
+
'long-context', 'tools-required', 'json-schema', 'vision-required',
|
|
125
|
+
'no-training-on-data',
|
|
126
|
+
'low-latency', 'high-throughput', 'open-weights', 'data-residency',
|
|
127
|
+
'audio-required', 'batch-api')),
|
|
128
|
+
value TEXT,
|
|
129
|
+
PRIMARY KEY (lane_id, constraint_)
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
INSERT INTO lane_requires_new (lane_id, constraint_, value)
|
|
133
|
+
SELECT lane_id, constraint_, value FROM lane_requires;
|
|
134
|
+
|
|
135
|
+
INSERT INTO lane_requires_new (lane_id, constraint_) VALUES
|
|
136
|
+
('bb/hunter', 'tools-required'),
|
|
137
|
+
('bb/builder', 'tools-required');
|
|
138
|
+
|
|
139
|
+
DROP INDEX idx_lane_members_lane;
|
|
140
|
+
DROP INDEX idx_lanes_tenant;
|
|
141
|
+
DROP TABLE lane_requires;
|
|
142
|
+
DROP TABLE lane_members;
|
|
143
|
+
DROP TABLE lanes;
|
|
144
|
+
ALTER TABLE lanes_new RENAME TO lanes;
|
|
145
|
+
ALTER TABLE lane_members_new RENAME TO lane_members;
|
|
146
|
+
ALTER TABLE lane_requires_new RENAME TO lane_requires;
|
|
147
|
+
|
|
148
|
+
CREATE INDEX idx_lane_members_lane ON lane_members (lane_id, position);
|
|
149
|
+
CREATE INDEX idx_lanes_tenant ON lanes (tenant_id, enabled);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
-- Restaff bb/hunter and bb/builder with frontline lab models.
|
|
2
|
+
--
|
|
3
|
+
-- 0074 staffed both from the DeepSeek/Mistral/Workers-AI pool that was
|
|
4
|
+
-- already on `bb/agentic-coding`. That cleared the ≥3-routable bar; it did
|
|
5
|
+
-- not put Google / Moonshot / Zhipu frontier at quality_rank 1. Both lanes
|
|
6
|
+
-- are tools-required, so only members with a fresh tools=1 measurement
|
|
7
|
+
-- may join (an unmeasured or tools=0 row never allocates).
|
|
8
|
+
--
|
|
9
|
+
-- What is absent on purpose (2026-09-12 UTC):
|
|
10
|
+
-- anthropic/claude-*-5 — measured_at null; not routable
|
|
11
|
+
-- openai/gpt-5.6-* — measured, tools=0; fails tools-required
|
|
12
|
+
-- Re-measure those with tools, then a later migration can promote them.
|
|
13
|
+
--
|
|
14
|
+
-- hunter still keeps codestral out (coding polish invents plausible vulns).
|
|
15
|
+
-- mistral-large drops: tools=1 in the catalogue but measured_at null on
|
|
16
|
+
-- production, so it was dead weight. Builder drops the qwen mid-tier now
|
|
17
|
+
-- covered by Kimi coding / GLM-5.3 / Gemini Pro. Selection stays graduated.
|
|
18
|
+
|
|
19
|
+
DELETE FROM lane_members WHERE lane_id IN ('bb/hunter', 'bb/builder');
|
|
20
|
+
|
|
21
|
+
INSERT INTO lane_members (lane_id, model_id, position, quality_rank) VALUES
|
|
22
|
+
('bb/hunter', 'google-ai-studio/gemini-3.1-pro-preview', 1, 1),
|
|
23
|
+
('bb/hunter', 'deepseek/deepseek-v4-pro', 2, 1),
|
|
24
|
+
('bb/hunter', 'workers-ai/@cf/moonshotai/kimi-k2.6', 3, 2),
|
|
25
|
+
('bb/hunter', 'mistral/mistral-medium-2604', 4, 2),
|
|
26
|
+
('bb/hunter', 'google-ai-studio/gemini-3.8-flash', 5, 3),
|
|
27
|
+
('bb/hunter', 'workers-ai/@cf/openai/gpt-oss-120b', 6, 3),
|
|
28
|
+
('bb/hunter', 'deepseek/deepseek-v4-flash', 7, 4),
|
|
29
|
+
|
|
30
|
+
('bb/builder', 'google-ai-studio/gemini-3.1-pro-preview', 1, 1),
|
|
31
|
+
('bb/builder', 'deepseek/deepseek-v4-pro', 2, 1),
|
|
32
|
+
('bb/builder', 'workers-ai/@cf/moonshotai/kimi-k2.7-code', 3, 1),
|
|
33
|
+
('bb/builder', 'workers-ai/@cf/zai-org/glm-5.3', 4, 1),
|
|
34
|
+
('bb/builder', 'mistral/codestral-2508', 5, 2),
|
|
35
|
+
('bb/builder', 'mistral/mistral-medium-2604', 6, 3),
|
|
36
|
+
('bb/builder', 'deepseek/deepseek-v4-flash', 7, 4);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
-- DeepSeek V4.1-Flash cutover (#375).
|
|
2
|
+
--
|
|
3
|
+
-- On 2026-09-10 DeepSeek shipped V4.1-Flash as `deepseek-flash` and retired
|
|
4
|
+
-- V4-Flash / V4-Flash-Vision-Exp. The old API names still answer, temporarily,
|
|
5
|
+
-- but they serve V4.1-Flash at that model's rate — so a Cruise row pinned to
|
|
6
|
+
-- `deepseek-v4-flash` with the old price_observations is a silent misbill.
|
|
7
|
+
-- From 04:00 UTC on 2026-09-14 the same happens to `deepseek-v4-pro` until a
|
|
8
|
+
-- V4.1-Pro ships. Source: https://api-docs.deepseek.com/news/news260910
|
|
9
|
+
--
|
|
10
|
+
-- Do not UPDATE `upstream_model` in place on the old Cruise ids. That is the
|
|
11
|
+
-- alias-drift failure 0013 and 0020 exist to prevent: the ledger, conformance
|
|
12
|
+
-- and prices key on `models.id`, and a row that kept the old id while the
|
|
13
|
+
-- host served a different model at a different rate would look continuous
|
|
14
|
+
-- and be wrong. New pinned id, disable the retired ones, restaff the lanes.
|
|
15
|
+
--
|
|
16
|
+
-- Prices (USD per 1M tokens, in force 2026-09-10 04:00 UTC), from
|
|
17
|
+
-- https://api-docs.deepseek.com/quick_start/pricing — off-peak cache hit
|
|
18
|
+
-- $0.003 / input $0.15 / output $0.60; peak is 2x; window unchanged
|
|
19
|
+
-- (mon-fri@01:00-04:00,mon-fri@06:00-10:00, 0039).
|
|
20
|
+
--
|
|
21
|
+
-- Workers AI dated rehosts (`…-0731` / `…-0813`) are a different host; leave
|
|
22
|
+
-- them alone until Cloudflare's page moves.
|
|
23
|
+
|
|
24
|
+
INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output) VALUES
|
|
25
|
+
('deepseek/deepseek-flash', 'deepseek', 'deepseek-flash', 1000000, 384000);
|
|
26
|
+
|
|
27
|
+
INSERT INTO price_observations
|
|
28
|
+
(observed_at, model, effective_from, prompt_tokens_from, peak_utc,
|
|
29
|
+
input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source, note)
|
|
30
|
+
VALUES
|
|
31
|
+
('2026-09-12 00:00:00', 'deepseek/deepseek-flash', '2026-09-10', 0, '',
|
|
32
|
+
150000, 600000, 3000, 'https://api-docs.deepseek.com/quick_start/pricing',
|
|
33
|
+
'First observation: DeepSeek-V4.1-Flash as deepseek-flash (#375, 0076). Off-peak.'),
|
|
34
|
+
('2026-09-12 00:00:00', 'deepseek/deepseek-flash', '2026-09-10', 0,
|
|
35
|
+
'mon-fri@01:00-04:00,mon-fri@06:00-10:00',
|
|
36
|
+
300000, 1200000, 6000, 'https://api-docs.deepseek.com/quick_start/pricing',
|
|
37
|
+
'Peak window unchanged from 0039; rate is 2x off-peak.');
|
|
38
|
+
|
|
39
|
+
-- One Flash member per lane that held any retired DeepSeek id. Keep the best
|
|
40
|
+
-- (lowest) quality_rank and earliest position among the removed rows so a
|
|
41
|
+
-- Pro-at-rank-1 lane does not demote Flash to the old failover slot.
|
|
42
|
+
INSERT INTO lane_members (lane_id, model_id, position, quality_rank)
|
|
43
|
+
SELECT lane_id, 'deepseek/deepseek-flash', MIN(position), MIN(quality_rank)
|
|
44
|
+
FROM lane_members
|
|
45
|
+
WHERE model_id IN (
|
|
46
|
+
'deepseek/deepseek-v4-flash',
|
|
47
|
+
'deepseek/deepseek-v4-pro',
|
|
48
|
+
'deepseek/deepseek-v4-flash-vision-exp'
|
|
49
|
+
)
|
|
50
|
+
GROUP BY lane_id;
|
|
51
|
+
|
|
52
|
+
DELETE FROM lane_members
|
|
53
|
+
WHERE model_id IN (
|
|
54
|
+
'deepseek/deepseek-v4-flash',
|
|
55
|
+
'deepseek/deepseek-v4-pro',
|
|
56
|
+
'deepseek/deepseek-v4-flash-vision-exp'
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
-- 0018's cheap pair: rewrite onto the new id. Any chain that named a retired
|
|
60
|
+
-- DeepSeek id as primary or fallback is dropped and the seeded pair restored.
|
|
61
|
+
DELETE FROM model_fallbacks
|
|
62
|
+
WHERE model IN (
|
|
63
|
+
'deepseek/deepseek-v4-flash',
|
|
64
|
+
'deepseek/deepseek-v4-pro',
|
|
65
|
+
'deepseek/deepseek-v4-flash-vision-exp'
|
|
66
|
+
)
|
|
67
|
+
OR fallback_model IN (
|
|
68
|
+
'deepseek/deepseek-v4-flash',
|
|
69
|
+
'deepseek/deepseek-v4-pro',
|
|
70
|
+
'deepseek/deepseek-v4-flash-vision-exp'
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
INSERT INTO model_fallbacks (model, position, fallback_model) VALUES
|
|
74
|
+
('deepseek/deepseek-flash', 1, 'mistral/mistral-small-latest'),
|
|
75
|
+
('mistral/mistral-small-latest', 1, 'deepseek/deepseek-flash');
|
|
76
|
+
|
|
77
|
+
UPDATE models
|
|
78
|
+
SET enabled = 0,
|
|
79
|
+
measured_at = NULL,
|
|
80
|
+
measured_by = NULL,
|
|
81
|
+
measurement_source = NULL
|
|
82
|
+
WHERE id IN (
|
|
83
|
+
'deepseek/deepseek-v4-flash',
|
|
84
|
+
'deepseek/deepseek-v4-pro',
|
|
85
|
+
'deepseek/deepseek-v4-flash-vision-exp'
|
|
86
|
+
);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- GPT-6 Astra (#375).
|
|
2
|
+
--
|
|
3
|
+
-- OpenAI's models page now names `gpt-6-astra` the default starting point for
|
|
4
|
+
-- complex reasoning and coding. Candidate for `bb/deep-reasoning` and
|
|
5
|
+
-- `bb/agentic-coding` once measured — this migration only catalogues and
|
|
6
|
+
-- prices. 0029 / 0049: a model enters a lane once it is routable in
|
|
7
|
+
-- production, which is a later act after conformance writes the flags.
|
|
8
|
+
--
|
|
9
|
+
-- Figures fetched 2026-09-13 UTC from the host's own model page,
|
|
10
|
+
-- https://developers.openai.com/api/docs/models/gpt-6-astra — not the board.
|
|
11
|
+
-- Window 1,050,000 / max output 128,000 (stated). Standard $10 / $50 per 1M;
|
|
12
|
+
-- cached input $1.00. Long context: prompts with more than 272K input tokens
|
|
13
|
+
-- are priced at 2x input and cache rates and 1.5x output for the full request
|
|
14
|
+
-- — same rule and boundary reading as 0049 (`prompt_tokens_from` = 272001).
|
|
15
|
+
-- Cache writes ($12.50 = 1.25x input) are not a Cruise price column; Batch /
|
|
16
|
+
-- Flex / Fast are not written either (0049 left those off for the same reason).
|
|
17
|
+
--
|
|
18
|
+
-- `data_retention` is `retained`, same unconditional API terms as the 0049
|
|
19
|
+
-- gpt-5.6 rows.
|
|
20
|
+
|
|
21
|
+
INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output,
|
|
22
|
+
data_retention, data_retention_source, data_retention_as_of) VALUES
|
|
23
|
+
('openai/gpt-6-astra', 'openai', 'gpt-6-astra', 1050000, 128000,
|
|
24
|
+
'retained', 'https://developers.openai.com/api/docs/guides/your-data', '2026-09-13');
|
|
25
|
+
|
|
26
|
+
INSERT INTO price_observations
|
|
27
|
+
(observed_at, model, effective_from, prompt_tokens_from, peak_utc,
|
|
28
|
+
input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source, note)
|
|
29
|
+
VALUES
|
|
30
|
+
('2026-09-13 00:00:00', 'openai/gpt-6-astra', '2026-09-13', 0, '',
|
|
31
|
+
10000000, 50000000, 1000000, 'https://developers.openai.com/api/docs/models/gpt-6-astra',
|
|
32
|
+
'First observation: GPT-6 Astra (#375, 0077).'),
|
|
33
|
+
('2026-09-13 00:00:00', 'openai/gpt-6-astra', '2026-09-13', 272001, '',
|
|
34
|
+
20000000, 75000000, 2000000, 'https://developers.openai.com/api/docs/models/gpt-6-astra',
|
|
35
|
+
'Long-context tier: >272K input tokens, 2x input/cache and 1.5x output for the whole request.');
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- Staff gpt-6-astra on bb/deep-reasoning (#375).
|
|
2
|
+
--
|
|
3
|
+
-- Measured 2026-09-13 on staging and production: streaming, usage and
|
|
4
|
+
-- json_schema pass; tools=0 and vision=0. The tools failure is OpenAI's
|
|
5
|
+
-- chat-completions refusal of function tools when reasoning_effort is in
|
|
6
|
+
-- play ("use /v1/responses or set reasoning_effort to 'none'"), not a proof
|
|
7
|
+
-- the model has no tools forever — but the folded flag is tools=0 today, so
|
|
8
|
+
-- bb/agentic-coding (tools-required) must not take it.
|
|
9
|
+
--
|
|
10
|
+
-- bb/deep-reasoning carries no tools gate. quality_rank 1: OpenAI's models
|
|
11
|
+
-- page names Astra the default for complex reasoning. Lane selection is
|
|
12
|
+
-- still `cheap`, so price keeps Flash and Workers AI ahead of Astra's
|
|
13
|
+
-- $10/$50 until a policy change; rank is for graduated / the cache tier
|
|
14
|
+
-- rule. Position 7 sits after the existing six members.
|
|
15
|
+
--
|
|
16
|
+
-- Not staffed elsewhere. Revisit agentic-coding when the probe (or the
|
|
17
|
+
-- Responses path) can measure tools honestly.
|
|
18
|
+
|
|
19
|
+
INSERT INTO lane_members (lane_id, model_id, position, quality_rank) VALUES
|
|
20
|
+
('bb/deep-reasoning', 'openai/gpt-6-astra', 7, 1);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- Staff gemini-3.5-flash-lite on bb/extraction (#375).
|
|
2
|
+
--
|
|
3
|
+
-- Already measured on staging and production 2026-09-10: tools=1, vision=1,
|
|
4
|
+
-- json_schema=1 — the last is what bb/extraction requires (0030). Audio input
|
|
5
|
+
-- is priced at the text rate on Google's page (0049's row already holds that
|
|
6
|
+
-- single rate). data_retention stays NULL until someone reads the account
|
|
7
|
+
-- tier; extraction does not carry no-training-on-data, so NULL does not
|
|
8
|
+
-- refuse the member.
|
|
9
|
+
--
|
|
10
|
+
-- quality_rank 2 with the other flash/cheap extractors (ministral-8b,
|
|
11
|
+
-- glm-4.7-flash). Position 6 after the five members 0076 left. Not staffed
|
|
12
|
+
-- elsewhere this pass.
|
|
13
|
+
|
|
14
|
+
INSERT INTO lane_members (lane_id, model_id, position, quality_rank) VALUES
|
|
15
|
+
('bb/extraction', 'google-ai-studio/gemini-3.5-flash-lite', 6, 2);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- How a model's bill is shaped, when two models of one modality disagree (#240).
|
|
2
|
+
--
|
|
3
|
+
-- Until this column, `BILL` in `src/billing-block.ts` was keyed on modality
|
|
4
|
+
-- alone. That is enough while every speech model is per character and every
|
|
5
|
+
-- image model is per token — which was true when 0056–0059 landed. It is not
|
|
6
|
+
-- enough once a host prices images per image with no token rate to convert
|
|
7
|
+
-- from: xAI's `grok-imagine-*` (read 2026-09-06), which is why #240 re-opened.
|
|
8
|
+
--
|
|
9
|
+
-- The tempting alternative is to *derive* the shape: no token rows and an
|
|
10
|
+
-- `image` component means per-image. That reads a misconfiguration — a
|
|
11
|
+
-- token-priced model whose headline was retracted — as a legitimately
|
|
12
|
+
-- component-priced one, and bills it on components alone. Silent under-
|
|
13
|
+
-- counting, which 0011 exists to prevent. So the shape is **declared**,
|
|
14
|
+
-- defaulted to the only value that has ever been true, exactly as `modality`
|
|
15
|
+
-- arrived in 0056.
|
|
16
|
+
--
|
|
17
|
+
-- Speech rows already live on the component side of this pair; they move to
|
|
18
|
+
-- `component` in the same statement so `BILL` keyed on `(modality, priced_by)`
|
|
19
|
+
-- describes them rather than special-casing the modality. Grok Imagine itself
|
|
20
|
+
-- is #284 — this migration only makes the column and the speech rewrite.
|
|
21
|
+
ALTER TABLE models ADD COLUMN priced_by TEXT NOT NULL DEFAULT 'token'
|
|
22
|
+
CHECK (priced_by IN ('token', 'component'));
|
|
23
|
+
|
|
24
|
+
UPDATE models SET priced_by = 'component' WHERE modality = 'speech';
|