@oxygen-agent/cli 1.750.4 → 1.766.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 (42) hide show
  1. package/README.md +1 -1
  2. package/dist/command-manifest.js +11 -1
  3. package/dist/help.js +8 -0
  4. package/dist/index.js +481 -94
  5. package/node_modules/@oxygen/shared/dist/billing.d.ts +88 -46
  6. package/node_modules/@oxygen/shared/dist/billing.js +134 -74
  7. package/node_modules/@oxygen/shared/dist/capability-discovery.js +12 -4
  8. package/node_modules/@oxygen/shared/dist/cli-result.js +1 -0
  9. package/node_modules/@oxygen/shared/dist/copilot-journeys.d.ts +8 -0
  10. package/node_modules/@oxygen/shared/dist/copilot-journeys.js +23 -5
  11. package/node_modules/@oxygen/shared/dist/future-signup-events.d.ts +13 -2
  12. package/node_modules/@oxygen/shared/dist/future-signup-events.js +17 -2
  13. package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.d.ts +106 -1
  14. package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.js +156 -45
  15. package/node_modules/@oxygen/shared/dist/index.d.ts +4 -0
  16. package/node_modules/@oxygen/shared/dist/index.js +4 -0
  17. package/node_modules/@oxygen/shared/dist/object-storage.d.ts +33 -0
  18. package/node_modules/@oxygen/shared/dist/object-storage.js +69 -4
  19. package/node_modules/@oxygen/shared/dist/person-name.d.ts +40 -0
  20. package/node_modules/@oxygen/shared/dist/person-name.js +23 -0
  21. package/node_modules/@oxygen/shared/dist/plan-capabilities.d.ts +82 -0
  22. package/node_modules/@oxygen/shared/dist/plan-capabilities.js +130 -0
  23. package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +2 -2
  24. package/node_modules/@oxygen/shared/dist/plan-limits.js +18 -2
  25. package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +50 -56
  26. package/node_modules/@oxygen/shared/dist/pricing-sheet.js +77 -90
  27. package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +62 -0
  28. package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +91 -0
  29. package/node_modules/@oxygen/shared/dist/provider-funding-errors.d.ts +44 -0
  30. package/node_modules/@oxygen/shared/dist/provider-funding-errors.js +81 -0
  31. package/node_modules/@oxygen/shared/dist/publishing-limits.d.ts +24 -0
  32. package/node_modules/@oxygen/shared/dist/publishing-limits.js +24 -0
  33. package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +27 -6
  34. package/node_modules/@oxygen/shared/dist/spend-safety.js +34 -6
  35. package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
  36. package/node_modules/@oxygen/shared/dist/version.js +6 -3
  37. package/node_modules/@oxygen/shared/package.json +10 -0
  38. package/node_modules/@oxygen/workflows/dist/graph/topology.d.ts +27 -0
  39. package/node_modules/@oxygen/workflows/dist/graph/topology.js +95 -0
  40. package/node_modules/@oxygen/workflows/dist/graph/types.d.ts +20 -0
  41. package/node_modules/@oxygen/workflows/dist/graph/types.js +2 -0
  42. package/package.json +1 -1
@@ -3,24 +3,52 @@
3
3
  * page's "what credits buy" table, the pricing calculator, and docs.
4
4
  *
5
5
  * Pricing Model 2.0 (founder-ratified 2026-07-14): ONE credit pool pays for
6
- * everything; 1 USD = 1,000 credits (CREDITS_PER_USD in ./billing.ts).
7
- * Representative values here mirror the canonical billing sources — the
8
- * enrichment/AI resolver seed (packages/integrations/src/cogs-rates.ts), the
9
- * infra cost-plus rules (vendor COGS × 1.25), and the ratified LinkedIn
10
- * prices — as DISPLAY constants. If a canonical price moves, move it here in
11
- * the same change.
6
+ * everything; 1 USD = 1,000 credits.
7
+ *
8
+ * THIS FILE NO LONGER DECLARES PRICES. It used to carry hand-copied literals
9
+ * under a comment asking the next person to remember to update them — which is
10
+ * how it came to quote 25 credits for web-search grounding that actually
11
+ * reserved 115. Prices now arrive from exactly two places, and neither of them
12
+ * is a human retyping a number:
13
+ *
14
+ * ./pricing-snapshot.generated.ts platform prices, rendered from
15
+ * packages/control-db/src/pricing/seed.ts by
16
+ * `npm run pricing:snapshot` and CI-gated.
17
+ * To change one, edit the SEED.
18
+ *
19
+ * resolver-derived values below AI column tiers, web-search grounding and
20
+ * the representative enrichment prices come
21
+ * from provider_cost_config (seeded by
22
+ * cogs-rates.ts) — a different source of
23
+ * truth, pinned by
24
+ * pricing-sheet-conformance.test.ts in
25
+ * @oxygen/integrations, which can see both
26
+ * sides and fails when they diverge.
12
27
  *
13
28
  * Dependency-free on purpose: this module is imported by "use client"
14
29
  * marketing components via the `@oxygen/shared/pricing-sheet` subpath, so it
15
30
  * must never drag the shared barrel (async_hooks etc.) into a client bundle.
31
+ * The generated snapshot holds that property too — it is literals only.
32
+ *
33
+ * Anything that CAN await a query should read the control DB via
34
+ * loadPricingBook() instead of importing this file, so a staff re-price at
35
+ * /admin/costs takes effect without a deploy.
16
36
  */
37
+ export { creditsToUsd, usdToCredits } from "./pricing-snapshot.generated.js";
17
38
  export declare const PRICING_SHEET_VERIFIED = "2026-07";
18
- /** Mirror of CREDITS_PER_USD in ./billing.ts (kept literal: client-safe module). */
19
39
  export declare const PRICING_CREDITS_PER_USD = 1000;
20
40
  /** On-demand top-up price per 1,000 credits (USD); subscriptions pay $1.00. */
21
41
  export declare const TOPUP_USD_PER_1K = 1.25;
22
42
  export declare const SUBSCRIPTION_USD_PER_1K = 1;
23
- /** AI column runs, honest 5× of modeled tier COGS. */
43
+ /**
44
+ * AI column runs, honest 5× of modeled tier COGS.
45
+ *
46
+ * RESOLVER-DERIVED, not seed-derived: the canonical values live in
47
+ * packages/integrations/src/cogs-rates.ts and are served per-workspace from
48
+ * provider_cost_config. pricing-sheet-conformance.test.ts pins these literals
49
+ * against the live estimator, so a tier re-price fails a test rather than
50
+ * quietly mispricing the page.
51
+ */
24
52
  export declare const AI_COLUMN_CREDITS: {
25
53
  readonly low: 15;
26
54
  readonly medium: 75;
@@ -38,11 +66,7 @@ export declare const AI_COLUMN_CREDITS: {
38
66
  * with parallel as its one fallback (WEB_SEARCH_ENGINES), so a row costs 35 when
39
67
  * the primary answers and reserves 40 for the case where both lanes fire.
40
68
  *
41
- * LITERAL ON PURPOSE, like PRICING_CREDITS_PER_USD above: this module ships to the
42
- * marketing client bundle and cannot import @oxygen/integrations (which depends on
43
- * @oxygen/shared). `pricing-sheet-conformance.test.ts` in @oxygen/integrations —
44
- * which can see both — pins these numbers to the live resolver, so drift fails a
45
- * test instead of quietly mispricing the page again.
69
+ * Resolver-derived like AI_COLUMN_CREDITS above, and pinned by the same test.
46
70
  */
47
71
  export declare const AI_COLUMN_WEB_SEARCH_TYPICAL_CREDITS = 35;
48
72
  export declare const AI_COLUMN_WEB_SEARCH_RESERVED_CREDITS = 40;
@@ -50,12 +74,9 @@ export declare const AI_COLUMN_WEB_SEARCH_RESERVED_CREDITS = 40;
50
74
  export declare const AUTOMATION_ACTION_CREDITS = 0.01;
51
75
  /**
52
76
  * Managed email inboxes: founder-ratified flat price (2026-07-25), superseding
53
- * the earlier dynamic vendor-COGS × 1.25 range (InboxKit $2.48–3.99 Google /
54
- * flat $5 Microsoft rate card, ×1.25 → 3,100–6,250 cr). The Oxygen-sold managed
55
- * mailbox line is now a flat $3.00/month (3,000 credits) regardless of vendor
56
- * tier. Kept as an object (min/typical/max all equal) rather than a bare number
57
- * so existing callers that destructure any of the three fields need no shape
58
- * change.
77
+ * the earlier dynamic vendor-COGS × 1.25 range. Kept as an object (min/typical/max
78
+ * all equal) rather than a bare number so existing callers that destructure any
79
+ * of the three fields need no shape change.
59
80
  */
60
81
  export declare const MANAGED_INBOX_MARKUP = 1.25;
61
82
  export declare const MANAGED_INBOX_CREDITS_PER_MONTH: {
@@ -77,15 +98,8 @@ export declare const MANAGED_INBOX_CREDITS_PER_MONTH: {
77
98
  * Costing only the outbound leg undercharges every call by 29%.
78
99
  */
79
100
  export declare const VOICE_MARKUP = 5;
80
- /**
81
- * Flat $5.00/mo per number (founder decision 2026-07-26). Twilio's US/CA local
82
- * DID costs $1.15, so this is ~4.3× — priced as a round number rather than a
83
- * computed markup, the way a customer actually reads a price.
84
- */
85
101
  export declare const VOICE_NUMBER_CREDITS_PER_MONTH = 5000;
86
- /** Both legs, $0.018/min × 5 → $0.09/min. */
87
102
  export declare const VOICE_CREDITS_PER_MINUTE = 90;
88
- /** Answering-machine detection is per CALL, not per minute — it bills on no-answers too. */
89
103
  export declare const VOICE_CREDITS_PER_AMD_CALL = 38;
90
104
  /** Managed domains: registrar at-cost × 1.25 (≈ a $10.44 .com → ~13,050 credits/yr). */
91
105
  export declare const MANAGED_DOMAIN_MARKUP = 1.25;
@@ -97,18 +111,6 @@ export declare const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13050;
97
111
  * inbox-placement (spam) tests; tests beyond the allowance bill the per-test
98
112
  * price.
99
113
  *
100
- * All three are DISPLAY mirrors, per this file's contract. The canonical values
101
- * live where they are enforced, and seed-parity.test.ts binds them so a mirror
102
- * can never quietly drift from the number actually billed:
103
- * seat DELIVERABILITY_UNIT_MONTHLY_CREDITS (@oxygen/control-db,
104
- * also PRICING_SEED commitment.deliverability_unit) — 1,000 credits
105
- * ($1.00), restored by the founder on 2026-07-30 after reviewing the
106
- * Agency-plan unit economics, superseding the 2026-07-26 signature
107
- * of 2,000.
108
- * allowance DELIVERABILITY_INCLUDED_TESTS_PER_INBOX (@oxygen/control-db)
109
- * overage EMAILGUARD_MANAGED_PLACEMENT_CREDITS (@oxygen/providers,
110
- * derived from the Agency plan rather than typed in)
111
- *
112
114
  * THE ALLOWANCE IS LOAD-BEARING, not a perk. Placement COGS is per TEST
113
115
  * ($0.1327 on EmailGuard's Agency plan), not per inbox, so an unbounded seat
114
116
  * inverts its own margin: at $1.00/inbox-month the EIGHTH test in a cycle is
@@ -118,14 +120,12 @@ export declare const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13050;
118
120
  */
119
121
  export declare const DELIVERABILITY_SEAT_CREDITS_PER_MONTH = 1000;
120
122
  export declare const DELIVERABILITY_INCLUDED_TESTS_PER_INBOX = 2;
121
- /** Overage placement test: $0.1327 EmailGuard COGS × 1.25, rounded up. */
122
123
  export declare const PLACEMENT_TEST_OVERAGE_CREDITS = 166;
123
124
  /**
124
125
  * LinkedIn accounts: founder decision (2026-07-25) — a PURE seat model. The
125
- * flat monthly connection fee per connected account is now the WHOLE LinkedIn
126
- * price (10,000 credits, up from the 7,000-credit 2026-07-14 Pricing Model 2.0
127
- * figure); every per-action charge below is 0. Per-MESSAGE sends on email and
128
- * WhatsApp stay 0 too — but a connected WhatsApp NUMBER carries its own monthly
126
+ * flat monthly connection fee per connected account is the WHOLE LinkedIn
127
+ * price; every per-action charge is 0. Per-MESSAGE sends on email and WhatsApp
128
+ * stay 0 too — but a connected WhatsApp NUMBER carries its own monthly
129
129
  * connection fee, see WHATSAPP_ACCOUNT_CREDITS_PER_MONTH.
130
130
  */
131
131
  export declare const LINKEDIN_ACCOUNT_CREDITS_PER_MONTH = 10000;
@@ -138,23 +138,16 @@ export declare const LINKEDIN_ACTION_CREDITS: {
138
138
  readonly like_post: 0;
139
139
  readonly comment_post: 0;
140
140
  };
141
- /**
142
- * Editable calculator default: a warmed account's typical monthly action mix.
143
- * 0 under the pure seat model (2026-07-25) — actions no longer add to the
144
- * LinkedIn line regardless of volume, so this default carries no credits.
145
- * Kept (not deleted) because PRICING_CALCULATOR_DEFAULTS.linkedinActionCreditsPerAccount
146
- * still reads it as its default value.
147
- */
148
141
  export declare const LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH = 0;
149
142
  /**
150
143
  * WhatsApp numbers: flat monthly connection fee per connected number, the same
151
- * seat shape as LinkedIn ($10 × 1,000 credits/$). Billed off the rolling-30d peak,
152
- * so a number connected part-way through a month still bills the full cycle.
153
- * WhatsApp message sends themselves remain 0 credits.
144
+ * seat shape as LinkedIn. Billed off the rolling-30d peak, so a number connected
145
+ * part-way through a month still bills the full cycle. WhatsApp message sends
146
+ * themselves remain 0 credits.
154
147
  */
155
148
  export declare const WHATSAPP_ACCOUNT_CREDITS_PER_MONTH = 10000;
156
149
  /** Dedicated egress IP add-on. */
157
- export declare const EGRESS_IP_CREDITS_PER_MONTH = 15000;
150
+ export declare const EGRESS_IP_CREDITS_PER_MONTH = 25000;
158
151
  /**
159
152
  * Email + WhatsApp sends cost nothing per message — the pool pays for inboxes and
160
153
  * connected accounts, not for sends.
@@ -164,6 +157,9 @@ export declare const SEND_CREDITS = 0;
164
157
  * Representative enrichment prices (5× provider COGS via the resolver; the
165
158
  * live per-operation table is served by /api/pricing/customer-credit-prices).
166
159
  * "typical" = the cheap-first waterfall's common case, used by the calculator.
160
+ *
161
+ * Resolver-derived, like AI_COLUMN_CREDITS: these mirror cogs-rates.ts, not the
162
+ * pricing seed.
167
163
  */
168
164
  export declare const ENRICHMENT_CREDITS: {
169
165
  readonly email_verify: 2.245;
@@ -176,5 +172,3 @@ export declare const ENRICHMENT_CREDITS: {
176
172
  };
177
173
  /** Editable calculator default: blended credits per fully-enriched row. */
178
174
  export declare const ENRICHMENT_CREDITS_PER_ROW_TYPICAL = 100;
179
- export declare function creditsToUsd(credits: number): number;
180
- export declare function usdToCredits(usd: number): number;
@@ -3,24 +3,53 @@
3
3
  * page's "what credits buy" table, the pricing calculator, and docs.
4
4
  *
5
5
  * Pricing Model 2.0 (founder-ratified 2026-07-14): ONE credit pool pays for
6
- * everything; 1 USD = 1,000 credits (CREDITS_PER_USD in ./billing.ts).
7
- * Representative values here mirror the canonical billing sources — the
8
- * enrichment/AI resolver seed (packages/integrations/src/cogs-rates.ts), the
9
- * infra cost-plus rules (vendor COGS × 1.25), and the ratified LinkedIn
10
- * prices — as DISPLAY constants. If a canonical price moves, move it here in
11
- * the same change.
6
+ * everything; 1 USD = 1,000 credits.
7
+ *
8
+ * THIS FILE NO LONGER DECLARES PRICES. It used to carry hand-copied literals
9
+ * under a comment asking the next person to remember to update them — which is
10
+ * how it came to quote 25 credits for web-search grounding that actually
11
+ * reserved 115. Prices now arrive from exactly two places, and neither of them
12
+ * is a human retyping a number:
13
+ *
14
+ * ./pricing-snapshot.generated.ts platform prices, rendered from
15
+ * packages/control-db/src/pricing/seed.ts by
16
+ * `npm run pricing:snapshot` and CI-gated.
17
+ * To change one, edit the SEED.
18
+ *
19
+ * resolver-derived values below AI column tiers, web-search grounding and
20
+ * the representative enrichment prices come
21
+ * from provider_cost_config (seeded by
22
+ * cogs-rates.ts) — a different source of
23
+ * truth, pinned by
24
+ * pricing-sheet-conformance.test.ts in
25
+ * @oxygen/integrations, which can see both
26
+ * sides and fails when they diverge.
12
27
  *
13
28
  * Dependency-free on purpose: this module is imported by "use client"
14
29
  * marketing components via the `@oxygen/shared/pricing-sheet` subpath, so it
15
30
  * must never drag the shared barrel (async_hooks etc.) into a client bundle.
31
+ * The generated snapshot holds that property too — it is literals only.
32
+ *
33
+ * Anything that CAN await a query should read the control DB via
34
+ * loadPricingBook() instead of importing this file, so a staff re-price at
35
+ * /admin/costs takes effect without a deploy.
16
36
  */
17
- export const PRICING_SHEET_VERIFIED = "2026-07";
18
- /** Mirror of CREDITS_PER_USD in ./billing.ts (kept literal: client-safe module). */
19
- export const PRICING_CREDITS_PER_USD = 1_000;
37
+ import { AUTOMATION_ACTION_CREDITS as SNAPSHOT_AUTOMATION_ACTION_CREDITS, CREDITS_PER_USD as SNAPSHOT_CREDITS_PER_USD, DELIVERABILITY_INCLUDED_TESTS_PER_INBOX as SNAPSHOT_DELIVERABILITY_INCLUDED_TESTS_PER_INBOX, DELIVERABILITY_SEAT_CREDITS_PER_MONTH as SNAPSHOT_DELIVERABILITY_SEAT_CREDITS_PER_MONTH, EGRESS_IP_CREDITS_PER_MONTH as SNAPSHOT_EGRESS_IP_CREDITS_PER_MONTH, ENRICHMENT_CREDITS_PER_ROW_TYPICAL as SNAPSHOT_ENRICHMENT_CREDITS_PER_ROW_TYPICAL, LINKEDIN_ACCOUNT_CREDITS_PER_MONTH as SNAPSHOT_LINKEDIN_ACCOUNT_CREDITS_PER_MONTH, LINKEDIN_ACTION_CREDITS as SNAPSHOT_LINKEDIN_ACTION_CREDITS, LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH as SNAPSHOT_LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH, MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL as SNAPSHOT_MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL, MANAGED_DOMAIN_MARKUP as SNAPSHOT_MANAGED_DOMAIN_MARKUP, MANAGED_INBOX_CREDITS_PER_MONTH as SNAPSHOT_MANAGED_INBOX_CREDITS_PER_MONTH, MANAGED_INBOX_MARKUP as SNAPSHOT_MANAGED_INBOX_MARKUP, PLACEMENT_TEST_OVERAGE_CREDITS as SNAPSHOT_PLACEMENT_TEST_OVERAGE_CREDITS, PRICE_SHEET_VERIFIED as SNAPSHOT_PRICE_SHEET_VERIFIED, SEND_CREDITS as SNAPSHOT_SEND_CREDITS, SUBSCRIPTION_USD_PER_1K as SNAPSHOT_SUBSCRIPTION_USD_PER_1K, TOPUP_USD_PER_1K as SNAPSHOT_TOPUP_USD_PER_1K, VOICE_CREDITS_PER_AMD_CALL as SNAPSHOT_VOICE_CREDITS_PER_AMD_CALL, VOICE_CREDITS_PER_MINUTE as SNAPSHOT_VOICE_CREDITS_PER_MINUTE, VOICE_MARKUP as SNAPSHOT_VOICE_MARKUP, VOICE_NUMBER_CREDITS_PER_MONTH as SNAPSHOT_VOICE_NUMBER_CREDITS_PER_MONTH, WHATSAPP_ACCOUNT_CREDITS_PER_MONTH as SNAPSHOT_WHATSAPP_ACCOUNT_CREDITS_PER_MONTH, } from "./pricing-snapshot.generated.js";
38
+ export { creditsToUsd, usdToCredits } from "./pricing-snapshot.generated.js";
39
+ export const PRICING_SHEET_VERIFIED = SNAPSHOT_PRICE_SHEET_VERIFIED;
40
+ export const PRICING_CREDITS_PER_USD = SNAPSHOT_CREDITS_PER_USD;
20
41
  /** On-demand top-up price per 1,000 credits (USD); subscriptions pay $1.00. */
21
- export const TOPUP_USD_PER_1K = 1.25;
22
- export const SUBSCRIPTION_USD_PER_1K = 1.0;
23
- /** AI column runs, honest 5× of modeled tier COGS. */
42
+ export const TOPUP_USD_PER_1K = SNAPSHOT_TOPUP_USD_PER_1K;
43
+ export const SUBSCRIPTION_USD_PER_1K = SNAPSHOT_SUBSCRIPTION_USD_PER_1K;
44
+ /**
45
+ * AI column runs, honest 5× of modeled tier COGS.
46
+ *
47
+ * RESOLVER-DERIVED, not seed-derived: the canonical values live in
48
+ * packages/integrations/src/cogs-rates.ts and are served per-workspace from
49
+ * provider_cost_config. pricing-sheet-conformance.test.ts pins these literals
50
+ * against the live estimator, so a tier re-price fails a test rather than
51
+ * quietly mispricing the page.
52
+ */
24
53
  export const AI_COLUMN_CREDITS = { low: 15, medium: 75, high: 250 };
25
54
  /**
26
55
  * Web-search grounding, billed per SEARCH on top of the model — not a flat adder.
@@ -34,27 +63,24 @@ export const AI_COLUMN_CREDITS = { low: 15, medium: 75, high: 250 };
34
63
  * with parallel as its one fallback (WEB_SEARCH_ENGINES), so a row costs 35 when
35
64
  * the primary answers and reserves 40 for the case where both lanes fire.
36
65
  *
37
- * LITERAL ON PURPOSE, like PRICING_CREDITS_PER_USD above: this module ships to the
38
- * marketing client bundle and cannot import @oxygen/integrations (which depends on
39
- * @oxygen/shared). `pricing-sheet-conformance.test.ts` in @oxygen/integrations —
40
- * which can see both — pins these numbers to the live resolver, so drift fails a
41
- * test instead of quietly mispricing the page again.
66
+ * Resolver-derived like AI_COLUMN_CREDITS above, and pinned by the same test.
42
67
  */
43
68
  export const AI_COLUMN_WEB_SEARCH_TYPICAL_CREDITS = 35;
44
69
  export const AI_COLUMN_WEB_SEARCH_RESERVED_CREDITS = 40;
45
70
  /** Workflow/automation actions (steps, tool calls, row writes) — capacity guard. */
46
- export const AUTOMATION_ACTION_CREDITS = 0.01;
71
+ export const AUTOMATION_ACTION_CREDITS = SNAPSHOT_AUTOMATION_ACTION_CREDITS;
47
72
  /**
48
73
  * Managed email inboxes: founder-ratified flat price (2026-07-25), superseding
49
- * the earlier dynamic vendor-COGS × 1.25 range (InboxKit $2.48–3.99 Google /
50
- * flat $5 Microsoft rate card, ×1.25 → 3,100–6,250 cr). The Oxygen-sold managed
51
- * mailbox line is now a flat $3.00/month (3,000 credits) regardless of vendor
52
- * tier. Kept as an object (min/typical/max all equal) rather than a bare number
53
- * so existing callers that destructure any of the three fields need no shape
54
- * change.
74
+ * the earlier dynamic vendor-COGS × 1.25 range. Kept as an object (min/typical/max
75
+ * all equal) rather than a bare number so existing callers that destructure any
76
+ * of the three fields need no shape change.
55
77
  */
56
- export const MANAGED_INBOX_MARKUP = 1.25;
57
- export const MANAGED_INBOX_CREDITS_PER_MONTH = { min: 3_000, typical: 3_000, max: 3_000 };
78
+ export const MANAGED_INBOX_MARKUP = SNAPSHOT_MANAGED_INBOX_MARKUP;
79
+ export const MANAGED_INBOX_CREDITS_PER_MONTH = {
80
+ min: SNAPSHOT_MANAGED_INBOX_CREDITS_PER_MONTH,
81
+ typical: SNAPSHOT_MANAGED_INBOX_CREDITS_PER_MONTH,
82
+ max: SNAPSHOT_MANAGED_INBOX_CREDITS_PER_MONTH,
83
+ };
58
84
  /**
59
85
  * VOICE (the call channel). Marked up 5×, not the 1.25× infra rule the inbox and
60
86
  * domain rails use: a phone number carries ongoing reputation work (warm-up,
@@ -68,20 +94,13 @@ export const MANAGED_INBOX_CREDITS_PER_MONTH = { min: 3_000, typical: 3_000, max
68
94
  * $0.0180 / min
69
95
  * Costing only the outbound leg undercharges every call by 29%.
70
96
  */
71
- export const VOICE_MARKUP = 5;
72
- /**
73
- * Flat $5.00/mo per number (founder decision 2026-07-26). Twilio's US/CA local
74
- * DID costs $1.15, so this is ~4.3× — priced as a round number rather than a
75
- * computed markup, the way a customer actually reads a price.
76
- */
77
- export const VOICE_NUMBER_CREDITS_PER_MONTH = 5_000;
78
- /** Both legs, $0.018/min × 5 → $0.09/min. */
79
- export const VOICE_CREDITS_PER_MINUTE = 90;
80
- /** Answering-machine detection is per CALL, not per minute — it bills on no-answers too. */
81
- export const VOICE_CREDITS_PER_AMD_CALL = 38;
97
+ export const VOICE_MARKUP = SNAPSHOT_VOICE_MARKUP;
98
+ export const VOICE_NUMBER_CREDITS_PER_MONTH = SNAPSHOT_VOICE_NUMBER_CREDITS_PER_MONTH;
99
+ export const VOICE_CREDITS_PER_MINUTE = SNAPSHOT_VOICE_CREDITS_PER_MINUTE;
100
+ export const VOICE_CREDITS_PER_AMD_CALL = SNAPSHOT_VOICE_CREDITS_PER_AMD_CALL;
82
101
  /** Managed domains: registrar at-cost × 1.25 (≈ a $10.44 .com → ~13,050 credits/yr). */
83
- export const MANAGED_DOMAIN_MARKUP = 1.25;
84
- export const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13_050;
102
+ export const MANAGED_DOMAIN_MARKUP = SNAPSHOT_MANAGED_DOMAIN_MARKUP;
103
+ export const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = SNAPSHOT_MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL;
85
104
  /**
86
105
  * Inbox deliverability (EmailGuard placement seat). A flat monthly price per
87
106
  * SUBSCRIBED inbox covering continuous deliverability monitoring (blacklist,
@@ -89,18 +108,6 @@ export const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13_050;
89
108
  * inbox-placement (spam) tests; tests beyond the allowance bill the per-test
90
109
  * price.
91
110
  *
92
- * All three are DISPLAY mirrors, per this file's contract. The canonical values
93
- * live where they are enforced, and seed-parity.test.ts binds them so a mirror
94
- * can never quietly drift from the number actually billed:
95
- * seat DELIVERABILITY_UNIT_MONTHLY_CREDITS (@oxygen/control-db,
96
- * also PRICING_SEED commitment.deliverability_unit) — 1,000 credits
97
- * ($1.00), restored by the founder on 2026-07-30 after reviewing the
98
- * Agency-plan unit economics, superseding the 2026-07-26 signature
99
- * of 2,000.
100
- * allowance DELIVERABILITY_INCLUDED_TESTS_PER_INBOX (@oxygen/control-db)
101
- * overage EMAILGUARD_MANAGED_PLACEMENT_CREDITS (@oxygen/providers,
102
- * derived from the Agency plan rather than typed in)
103
- *
104
111
  * THE ALLOWANCE IS LOAD-BEARING, not a perk. Placement COGS is per TEST
105
112
  * ($0.1327 on EmailGuard's Agency plan), not per inbox, so an unbounded seat
106
113
  * inverts its own margin: at $1.00/inbox-month the EIGHTH test in a cycle is
@@ -108,54 +115,40 @@ export const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13_050;
108
115
  * revenue — a ~73% margin — and everything past them bills
109
116
  * PLACEMENT_TEST_OVERAGE_CREDITS. Orgs on their own EmailGuard key (BYOK) pay 0.
110
117
  */
111
- export const DELIVERABILITY_SEAT_CREDITS_PER_MONTH = 1_000;
112
- export const DELIVERABILITY_INCLUDED_TESTS_PER_INBOX = 2;
113
- /** Overage placement test: $0.1327 EmailGuard COGS × 1.25, rounded up. */
114
- export const PLACEMENT_TEST_OVERAGE_CREDITS = 166;
118
+ export const DELIVERABILITY_SEAT_CREDITS_PER_MONTH = SNAPSHOT_DELIVERABILITY_SEAT_CREDITS_PER_MONTH;
119
+ export const DELIVERABILITY_INCLUDED_TESTS_PER_INBOX = SNAPSHOT_DELIVERABILITY_INCLUDED_TESTS_PER_INBOX;
120
+ export const PLACEMENT_TEST_OVERAGE_CREDITS = SNAPSHOT_PLACEMENT_TEST_OVERAGE_CREDITS;
115
121
  /**
116
122
  * LinkedIn accounts: founder decision (2026-07-25) — a PURE seat model. The
117
- * flat monthly connection fee per connected account is now the WHOLE LinkedIn
118
- * price (10,000 credits, up from the 7,000-credit 2026-07-14 Pricing Model 2.0
119
- * figure); every per-action charge below is 0. Per-MESSAGE sends on email and
120
- * WhatsApp stay 0 too — but a connected WhatsApp NUMBER carries its own monthly
123
+ * flat monthly connection fee per connected account is the WHOLE LinkedIn
124
+ * price; every per-action charge is 0. Per-MESSAGE sends on email and WhatsApp
125
+ * stay 0 too — but a connected WhatsApp NUMBER carries its own monthly
121
126
  * connection fee, see WHATSAPP_ACCOUNT_CREDITS_PER_MONTH.
122
127
  */
123
- export const LINKEDIN_ACCOUNT_CREDITS_PER_MONTH = 10_000;
124
- export const LINKEDIN_ACTION_CREDITS = {
125
- visit_profile: 0,
126
- invite: 0,
127
- message: 0,
128
- inmail: 0,
129
- follow: 0,
130
- like_post: 0,
131
- comment_post: 0,
132
- };
133
- /**
134
- * Editable calculator default: a warmed account's typical monthly action mix.
135
- * 0 under the pure seat model (2026-07-25) — actions no longer add to the
136
- * LinkedIn line regardless of volume, so this default carries no credits.
137
- * Kept (not deleted) because PRICING_CALCULATOR_DEFAULTS.linkedinActionCreditsPerAccount
138
- * still reads it as its default value.
139
- */
140
- export const LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH = 0;
128
+ export const LINKEDIN_ACCOUNT_CREDITS_PER_MONTH = SNAPSHOT_LINKEDIN_ACCOUNT_CREDITS_PER_MONTH;
129
+ export const LINKEDIN_ACTION_CREDITS = SNAPSHOT_LINKEDIN_ACTION_CREDITS;
130
+ export const LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH = SNAPSHOT_LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH;
141
131
  /**
142
132
  * WhatsApp numbers: flat monthly connection fee per connected number, the same
143
- * seat shape as LinkedIn ($10 × 1,000 credits/$). Billed off the rolling-30d peak,
144
- * so a number connected part-way through a month still bills the full cycle.
145
- * WhatsApp message sends themselves remain 0 credits.
133
+ * seat shape as LinkedIn. Billed off the rolling-30d peak, so a number connected
134
+ * part-way through a month still bills the full cycle. WhatsApp message sends
135
+ * themselves remain 0 credits.
146
136
  */
147
- export const WHATSAPP_ACCOUNT_CREDITS_PER_MONTH = 10_000;
137
+ export const WHATSAPP_ACCOUNT_CREDITS_PER_MONTH = SNAPSHOT_WHATSAPP_ACCOUNT_CREDITS_PER_MONTH;
148
138
  /** Dedicated egress IP add-on. */
149
- export const EGRESS_IP_CREDITS_PER_MONTH = 15_000;
139
+ export const EGRESS_IP_CREDITS_PER_MONTH = SNAPSHOT_EGRESS_IP_CREDITS_PER_MONTH;
150
140
  /**
151
141
  * Email + WhatsApp sends cost nothing per message — the pool pays for inboxes and
152
142
  * connected accounts, not for sends.
153
143
  */
154
- export const SEND_CREDITS = 0;
144
+ export const SEND_CREDITS = SNAPSHOT_SEND_CREDITS;
155
145
  /**
156
146
  * Representative enrichment prices (5× provider COGS via the resolver; the
157
147
  * live per-operation table is served by /api/pricing/customer-credit-prices).
158
148
  * "typical" = the cheap-first waterfall's common case, used by the calculator.
149
+ *
150
+ * Resolver-derived, like AI_COLUMN_CREDITS: these mirror cogs-rates.ts, not the
151
+ * pricing seed.
159
152
  */
160
153
  export const ENRICHMENT_CREDITS = {
161
154
  email_verify: 2.245, // MillionVerifier first pass (exactly 5x COGS)
@@ -167,10 +160,4 @@ export const ENRICHMENT_CREDITS = {
167
160
  linkedin_profile_scrape: 25.5, // HarvestAPI Basic full-profile job, exactly 5x COGS
168
161
  };
169
162
  /** Editable calculator default: blended credits per fully-enriched row. */
170
- export const ENRICHMENT_CREDITS_PER_ROW_TYPICAL = 100;
171
- export function creditsToUsd(credits) {
172
- return credits / PRICING_CREDITS_PER_USD;
173
- }
174
- export function usdToCredits(usd) {
175
- return usd * PRICING_CREDITS_PER_USD;
176
- }
163
+ export const ENRICHMENT_CREDITS_PER_ROW_TYPICAL = SNAPSHOT_ENRICHMENT_CREDITS_PER_ROW_TYPICAL;
@@ -0,0 +1,62 @@
1
+ /** Period the customer-facing price sheet was last reconciled end to end. */
2
+ export declare const PRICE_SHEET_VERIFIED = "2026-07";
3
+ /** $1 = 1_000 credits (Pricing Model 2.0). */
4
+ export declare const CREDITS_PER_USD = 1000;
5
+ /** The divisor in the markup formula; exact inverse of CREDITS_PER_USD. */
6
+ export declare const CREDIT_USD_VALUE = 0.001;
7
+ /** On-demand top-up, in USD cents per 1,000 credits. */
8
+ export declare const TOPUP_USD_CENTS_PER_1K_CREDITS = 125;
9
+ /** On-demand top-up price per 1,000 credits, in USD. */
10
+ export declare const TOPUP_USD_PER_1K = 1.25;
11
+ /** Subscription credits convert at face value, making them exactly 20% cheaper. */
12
+ export declare const SUBSCRIPTION_USD_PER_1K = 1;
13
+ export declare const MANAGED_INBOX_MARKUP = 1.25;
14
+ export declare const MANAGED_DOMAIN_MARKUP = 1.25;
15
+ export declare const VOICE_MARKUP = 5;
16
+ /** Applied to actual provider inference cost at settle time. */
17
+ export declare const COPILOT_CREDIT_MARKUP_MULTIPLIER = 5;
18
+ export declare const LINKEDIN_ACCOUNT_CREDITS_PER_MONTH = 10000;
19
+ export declare const WHATSAPP_ACCOUNT_CREDITS_PER_MONTH = 10000;
20
+ export declare const EGRESS_IP_CREDITS_PER_MONTH = 25000;
21
+ export declare const SENDING_MAILBOX_CREDITS_PER_MONTH = 1000;
22
+ export declare const MANAGED_INBOX_CREDITS_PER_MONTH = 3000;
23
+ export declare const MAILBOX_WARMUP_CREDITS_PER_MONTH = 3000;
24
+ export declare const DELIVERABILITY_SEAT_CREDITS_PER_MONTH = 1000;
25
+ /** Included inbox-placement tests per subscribed inbox per cycle. */
26
+ export declare const DELIVERABILITY_INCLUDED_TESTS_PER_INBOX = 2;
27
+ /** A placement test beyond the included allowance. */
28
+ export declare const PLACEMENT_TEST_OVERAGE_CREDITS = 166;
29
+ /** Representative, not billed: a typical .com at MANAGED_DOMAIN_MARKUP. */
30
+ export declare const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13050;
31
+ export declare const VOICE_NUMBER_CREDITS_PER_MONTH = 5000;
32
+ export declare const VOICE_CREDITS_PER_MINUTE = 90;
33
+ export declare const VOICE_CREDITS_PER_AMD_CALL = 38;
34
+ /** Workflow steps, tool calls and row writes — a capacity guard, not a margin line. */
35
+ export declare const AUTOMATION_ACTION_CREDITS = 0.01;
36
+ /** Email, LinkedIn and WhatsApp sends are free; the pool pays for seats and inboxes. */
37
+ export declare const SEND_CREDITS = 0;
38
+ /** Every LinkedIn action is 0 under the pure seat model. */
39
+ export declare const LINKEDIN_ACTION_CREDITS: {
40
+ readonly visit_profile: 0;
41
+ readonly invite: 0;
42
+ readonly message: 0;
43
+ readonly inmail: 0;
44
+ readonly follow: 0;
45
+ readonly like_post: 0;
46
+ readonly comment_post: 0;
47
+ };
48
+ export declare const ENRICHMENT_CREDITS_PER_ROW_TYPICAL = 100;
49
+ export declare const LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH = 0;
50
+ export type PricingPlanSnapshot = {
51
+ readonly planKey: string;
52
+ readonly tier: string;
53
+ readonly isLegacy: boolean;
54
+ readonly monthlyPriceCents: number | null;
55
+ readonly monthlyCredits: number | null;
56
+ readonly weeklyCreditsLimit: number | null;
57
+ readonly rolloverCap: number | null;
58
+ readonly byokEnabled: boolean;
59
+ };
60
+ export declare const PRICING_PLAN_SNAPSHOT: readonly PricingPlanSnapshot[];
61
+ export declare function creditsToUsd(credits: number): number;
62
+ export declare function usdToCredits(usd: number): number;
@@ -0,0 +1,91 @@
1
+ // GENERATED FROM packages/control-db/src/pricing/seed.ts — DO NOT HAND-EDIT.
2
+ //
3
+ // Regenerate with `npm run pricing:snapshot`. CI runs
4
+ // `npm run pricing:snapshot -- --check` and fails when this file and the seed
5
+ // disagree, so a hand-edit here is reverted rather than shipped.
6
+ //
7
+ // To change a price, edit the SEED. This file is a rendering of it, kept for the
8
+ // consumers that cannot query the control DB: @oxygen/shared (no @oxygen/*
9
+ // dependencies by design), the "use client" marketing and in-product components,
10
+ // and module-level catalogs built at import time.
11
+ //
12
+ // Everything that CAN await a query reads the database instead, via
13
+ // loadPricingBook() — a staff re-price at /admin/costs moves those with no deploy
14
+ // and does NOT move this file.
15
+ /** Period the customer-facing price sheet was last reconciled end to end. */
16
+ export const PRICE_SHEET_VERIFIED = "2026-07";
17
+ // --- conversion -------------------------------------------------------------
18
+ /** $1 = 1_000 credits (Pricing Model 2.0). */
19
+ export const CREDITS_PER_USD = 1_000;
20
+ /** The divisor in the markup formula; exact inverse of CREDITS_PER_USD. */
21
+ export const CREDIT_USD_VALUE = 0.001;
22
+ /** On-demand top-up, in USD cents per 1,000 credits. */
23
+ export const TOPUP_USD_CENTS_PER_1K_CREDITS = 125;
24
+ /** On-demand top-up price per 1,000 credits, in USD. */
25
+ export const TOPUP_USD_PER_1K = 1.25;
26
+ /** Subscription credits convert at face value, making them exactly 20% cheaper. */
27
+ export const SUBSCRIPTION_USD_PER_1K = 1;
28
+ // --- markups ----------------------------------------------------------------
29
+ export const MANAGED_INBOX_MARKUP = 1.25;
30
+ export const MANAGED_DOMAIN_MARKUP = 1.25;
31
+ export const VOICE_MARKUP = 5;
32
+ /** Applied to actual provider inference cost at settle time. */
33
+ export const COPILOT_CREDIT_MARKUP_MULTIPLIER = 5;
34
+ // --- seats and recurring charges --------------------------------------------
35
+ export const LINKEDIN_ACCOUNT_CREDITS_PER_MONTH = 10_000;
36
+ export const WHATSAPP_ACCOUNT_CREDITS_PER_MONTH = 10_000;
37
+ export const EGRESS_IP_CREDITS_PER_MONTH = 25_000;
38
+ export const SENDING_MAILBOX_CREDITS_PER_MONTH = 1_000;
39
+ export const MANAGED_INBOX_CREDITS_PER_MONTH = 3_000;
40
+ export const MAILBOX_WARMUP_CREDITS_PER_MONTH = 3_000;
41
+ export const DELIVERABILITY_SEAT_CREDITS_PER_MONTH = 1_000;
42
+ /** Included inbox-placement tests per subscribed inbox per cycle. */
43
+ export const DELIVERABILITY_INCLUDED_TESTS_PER_INBOX = 2;
44
+ /** A placement test beyond the included allowance. */
45
+ export const PLACEMENT_TEST_OVERAGE_CREDITS = 166;
46
+ /** Representative, not billed: a typical .com at MANAGED_DOMAIN_MARKUP. */
47
+ export const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13_050;
48
+ // --- voice ------------------------------------------------------------------
49
+ export const VOICE_NUMBER_CREDITS_PER_MONTH = 5_000;
50
+ export const VOICE_CREDITS_PER_MINUTE = 90;
51
+ export const VOICE_CREDITS_PER_AMD_CALL = 38;
52
+ // --- per-action -------------------------------------------------------------
53
+ /** Workflow steps, tool calls and row writes — a capacity guard, not a margin line. */
54
+ export const AUTOMATION_ACTION_CREDITS = 0.01;
55
+ /** Email, LinkedIn and WhatsApp sends are free; the pool pays for seats and inboxes. */
56
+ export const SEND_CREDITS = 0;
57
+ /** Every LinkedIn action is 0 under the pure seat model. */
58
+ export const LINKEDIN_ACTION_CREDITS = {
59
+ visit_profile: 0,
60
+ invite: 0,
61
+ message: 0,
62
+ inmail: 0,
63
+ follow: 0,
64
+ like_post: 0,
65
+ comment_post: 0,
66
+ };
67
+ // --- pricing-calculator defaults (not prices) -------------------------------
68
+ export const ENRICHMENT_CREDITS_PER_ROW_TYPICAL = 100;
69
+ export const LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH = 0;
70
+ export const PRICING_PLAN_SNAPSHOT = [
71
+ { planKey: "free", tier: "free", isLegacy: false, monthlyPriceCents: 0, monthlyCredits: 0, weeklyCreditsLimit: null, rolloverCap: null, byokEnabled: false },
72
+ { planKey: "starter", tier: "starter", isLegacy: false, monthlyPriceCents: 9_900, monthlyCredits: 99_000, weeklyCreditsLimit: null, rolloverCap: 99_000, byokEnabled: true },
73
+ { planKey: "pro", tier: "pro", isLegacy: false, monthlyPriceCents: 24_900, monthlyCredits: 249_000, weeklyCreditsLimit: null, rolloverCap: 249_000, byokEnabled: true },
74
+ { planKey: "team", tier: "team", isLegacy: false, monthlyPriceCents: 74_900, monthlyCredits: 749_000, weeklyCreditsLimit: null, rolloverCap: 749_000, byokEnabled: true },
75
+ { planKey: "scale", tier: "scale", isLegacy: false, monthlyPriceCents: null, monthlyCredits: 10_000_000, weeklyCreditsLimit: null, rolloverCap: 10_000_000, byokEnabled: true },
76
+ { planKey: "enterprise", tier: "enterprise", isLegacy: false, monthlyPriceCents: null, monthlyCredits: null, weeklyCreditsLimit: null, rolloverCap: null, byokEnabled: true },
77
+ { planKey: "launch_50", tier: "starter", isLegacy: true, monthlyPriceCents: 5_000, monthlyCredits: 200_000, weeklyCreditsLimit: 200_000, rolloverCap: 200_000, byokEnabled: true },
78
+ { planKey: "starter_50", tier: "starter", isLegacy: true, monthlyPriceCents: 5_000, monthlyCredits: 200_000, weeklyCreditsLimit: 200_000, rolloverCap: 200_000, byokEnabled: true },
79
+ { planKey: "pro_149", tier: "pro", isLegacy: true, monthlyPriceCents: 14_900, monthlyCredits: 1_000_000, weeklyCreditsLimit: 1_000_000, rolloverCap: 1_000_000, byokEnabled: true },
80
+ { planKey: "team_399", tier: "team", isLegacy: true, monthlyPriceCents: 39_900, monthlyCredits: 3_000_000, weeklyCreditsLimit: 3_000_000, rolloverCap: 3_000_000, byokEnabled: true },
81
+ { planKey: "growth_250", tier: "pro", isLegacy: true, monthlyPriceCents: 25_000, monthlyCredits: 250_000, weeklyCreditsLimit: 100_000, rolloverCap: 250_000, byokEnabled: true },
82
+ { planKey: "scale_750", tier: "team", isLegacy: true, monthlyPriceCents: 75_000, monthlyCredits: 750_000, weeklyCreditsLimit: 300_000, rolloverCap: 750_000, byokEnabled: true },
83
+ { planKey: "starter_legacy", tier: "starter", isLegacy: true, monthlyPriceCents: null, monthlyCredits: 200_000, weeklyCreditsLimit: null, rolloverCap: 200_000, byokEnabled: true },
84
+ { planKey: "scale_legacy", tier: "scale", isLegacy: true, monthlyPriceCents: null, monthlyCredits: 1_200_000, weeklyCreditsLimit: null, rolloverCap: 2_400_000, byokEnabled: true },
85
+ ];
86
+ export function creditsToUsd(credits) {
87
+ return credits / CREDITS_PER_USD;
88
+ }
89
+ export function usdToCredits(usd) {
90
+ return usd * CREDITS_PER_USD;
91
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * One vocabulary for "the provider refused because of money".
3
+ *
4
+ * A provider 402 has reached customers wearing four different costumes:
5
+ * - `provider_credits_exhausted` (tool runner, managed pool)
6
+ * - `connection_credits_exhausted` (tool runner, BYOK connection)
7
+ * - `provider_insufficient_credits` (enrichment column runner + waterfall)
8
+ * - `provider_credit_exhausted` (worker lane exclusion, singular)
9
+ * plus `provider_plan_limit` for the adjacent "your plan does not include this"
10
+ * refusal, which is also a money problem and also not retryable.
11
+ *
12
+ * Only the first two were known to the run-bottleneck classifier. The others
13
+ * fell through to a `/rate|limit|429/` test — which `provider_plan_limit`
14
+ * matches on the substring "limit" — or to the deferral branch, so a hard 402
15
+ * surfaced to the customer as `bottlenecks: [provider_rate_limit]`. That reads
16
+ * as "wait and retry": a partner agency spent hours lowering concurrency against
17
+ * an account that was simply out of credits, and the real 402 was only visible
18
+ * through a different command.
19
+ *
20
+ * The distinction that matters operationally: a rate limit clears by waiting, a
21
+ * funding failure never does. Anything that decides "should the customer wait?"
22
+ * must ask this predicate, not a regex over the code string.
23
+ */
24
+ /** Codes meaning the provider refused for funding/entitlement reasons. Never retryable by waiting. */
25
+ export declare const PROVIDER_FUNDING_ERROR_CODES: readonly ["provider_credits_exhausted", "provider_credits_exhausted_deferred", "connection_credits_exhausted", "provider_insufficient_credits", "provider_credit_exhausted", "provider_plan_limit", "blocked_provider_funding"];
26
+ export type ProviderFundingErrorCode = (typeof PROVIDER_FUNDING_ERROR_CODES)[number];
27
+ /**
28
+ * True when the code means "this failed over money", in any of its spellings.
29
+ *
30
+ * Matches on the exact code first, then falls back to a narrow shape test so a
31
+ * provider-specific variant (`peopledatalabs_credits_exhausted`) is still
32
+ * classified as funding rather than silently treated as retryable. Deliberately
33
+ * does NOT match on "limit" alone — `rate_limit_exceeded` is a real rate limit.
34
+ */
35
+ export declare function isProviderFundingErrorCode(code: string | null | undefined): boolean;
36
+ /**
37
+ * True for a genuine rate limit — one that clears by waiting.
38
+ *
39
+ * A funding failure always wins: `provider_plan_limit` contains "limit" and
40
+ * would otherwise read as retryable.
41
+ */
42
+ export declare function isProviderRateLimitErrorCode(code: string | null | undefined): boolean;
43
+ /** The customer-facing next step for a funding refusal, by credential ownership. */
44
+ export declare function providerFundingNextStep(credentialMode: "managed" | "byok" | null | undefined): string;