chore(free-models): derive the free-tier regime sets from the regime table (#11537)

Validated in a combined 3-PR batch worktree off release/v3.8.51 tip.
- Focused tests: free-regime-traits-derived-sets.test.ts, free-model-catalog.test.ts — pass; vitest autoCombo suite 108/111 (3 pre-existing timing-flaky failures unrelated to this diff, reproduced identically on the pure release/v3.8.51 tip in an isolated probe — auto/glm and Cerebras-rotation timeouts, none of the files this PR touches)
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK

Thanks for collapsing the four duplicated regime answers into one table-driven source — the `satisfies Record<...>` trick turning a missing answer into a compile error is a nice touch.
This commit is contained in:
Dizzle
2026-08-25 21:30:59 +02:00
committed by GitHub
parent a63b3e21b9
commit 60eb0806df
4 changed files with 204 additions and 30 deletions

View File

@@ -0,0 +1 @@
- **chore(free-models):** the free-tier regime table now declares which totals figure each regime feeds and whether it may take the no-auth shortcut, so the sets that used to repeat those answers by hand are derived from it — a new `freeType` no longer compiles until it has answered every question, instead of silently contributing to no total ([#11537](https://github.com/diegosouzapw/OmniRoute/pull/11537))

View File

@@ -67,33 +67,106 @@ export interface FreeModelTotals {
headline: string;
}
const RECURRING = new Set<FreeModelFreeType>(["recurring-daily", "recurring-monthly", "keyless"]);
/**
* Which figure a regime's allowance belongs to. Every regime lands in exactly
* one bucket, so a regime added tomorrow cannot quietly contribute to nothing:
* the compiler asks which figure it feeds.
*/
export type FreeRegimeTokenBucket =
| "steady-monthly" // summed into the steady recurring headline
| "recurring-credit" // credit that refills, reported next to the steady figure
| "one-time-credit" // signup credit, first month only
| "uncapped" // real access, no published cap — listed, never summed
| "none"; // grants nothing, so it feeds no figure
interface FreeRegimeTraits {
/** Can a request route here without paying? */
grantsFreeAccess: boolean;
/** Which totals figure this regime's allowance belongs to. */
tokenBucket: FreeRegimeTokenBucket;
/**
* May a candidate of this regime skip the live allowance check when it is
* reached through the synthetic no-auth path? True only where the catalogue
* says no credential exists at all, so no request against it can be billed.
*
* This is NOT "this provider needs no API key". `providerCredentialRequirement.ts`
* answers that other question and documents (`:1-16`) the cost of confusing the
* two: blackbox, friendliai, iflytek and sparkdesk are catalogued `keyless` yet
* answer 401 without a credential. Keep the two questions apart.
*/
allowsNoAuthShortcut: boolean;
}
/**
* What each free-tier regime engages for "can I route here without paying?".
* Exhaustive by construction: adding a member to `FreeModelFreeType` will not
* compile until it is classified here. `discontinued` is the one regime a
* provider uses to retire a free tier behind a paid key — it does NOT grant
* free access, and the shared predicate (`isFreeModel`) must read this instead
* of treating every catalogued id as free. `RECURRING` (above) answers a
* different question (which regimes feed the headline token totals) and is left
* independent on purpose — deriving it from this table would silently change
* the homepage totals.
* What each free-tier regime engages, for every question the codebase asks of a
* regime. Exhaustive by construction: adding a member to `FreeModelFreeType`
* will not compile until it is classified here, on every axis.
*
* `discontinued` is the regime a provider uses to retire a free tier behind a
* paid key — it grants no access, so the shared predicate (`isFreeModel`) reads
* this table instead of treating every catalogued id as free.
*/
const FREE_REGIME_TRAITS = {
"recurring-daily": { grantsFreeAccess: true },
"recurring-monthly": { grantsFreeAccess: true },
"recurring-credit": { grantsFreeAccess: true },
"recurring-uncapped": { grantsFreeAccess: true },
"one-time-initial": { grantsFreeAccess: true },
keyless: { grantsFreeAccess: true },
discontinued: { grantsFreeAccess: false },
} satisfies Record<FreeModelFreeType, { grantsFreeAccess: boolean }>;
export const FREE_REGIME_TRAITS = {
"recurring-daily": {
grantsFreeAccess: true,
tokenBucket: "steady-monthly",
allowsNoAuthShortcut: false,
},
"recurring-monthly": {
grantsFreeAccess: true,
tokenBucket: "steady-monthly",
allowsNoAuthShortcut: false,
},
"recurring-credit": {
grantsFreeAccess: true,
tokenBucket: "recurring-credit",
allowsNoAuthShortcut: false,
},
"recurring-uncapped": {
grantsFreeAccess: true,
tokenBucket: "uncapped",
allowsNoAuthShortcut: false,
},
"one-time-initial": {
grantsFreeAccess: true,
tokenBucket: "one-time-credit",
allowsNoAuthShortcut: false,
},
keyless: {
grantsFreeAccess: true,
tokenBucket: "steady-monthly",
allowsNoAuthShortcut: true,
},
discontinued: {
grantsFreeAccess: false,
tokenBucket: "none",
allowsNoAuthShortcut: false,
},
} satisfies Record<FreeModelFreeType, FreeRegimeTraits>;
export function grantsFreeAccess(freeType: FreeModelFreeType): boolean {
return FREE_REGIME_TRAITS[freeType].grantsFreeAccess;
}
/** The regimes whose allowance belongs to `bucket`, derived from the table. */
export function freeTypesInBucket(bucket: FreeRegimeTokenBucket): Set<FreeModelFreeType> {
return new Set(
(Object.keys(FREE_REGIME_TRAITS) as FreeModelFreeType[]).filter(
(freeType) => FREE_REGIME_TRAITS[freeType].tokenBucket === bucket
)
);
}
/** See `FreeRegimeTraits.allowsNoAuthShortcut` — routing question, not a credential one. */
export function allowsNoAuthShortcut(freeType: FreeModelFreeType): boolean {
return FREE_REGIME_TRAITS[freeType].allowsNoAuthShortcut;
}
const STEADY_MONTHLY = freeTypesInBucket("steady-monthly");
const RECURRING_CREDIT = freeTypesInBucket("recurring-credit");
const ONE_TIME_CREDIT = freeTypesInBucket("one-time-credit");
const UNCAPPED = freeTypesInBucket("uncapped");
/**
* Deposit-unlock boosts: a one-time small top-up that permanently raises a
* provider's recurring free quota. Kept OUT of the steady headline and surfaced
@@ -139,30 +212,30 @@ export function computeFreeModelTotals(opts: { excludeTosAvoid?: boolean } = {})
const steadyRecurringTokens = dedupedSum(
models,
(m) => m.monthlyTokens,
(m) => RECURRING.has(m.freeType)
(m) => STEADY_MONTHLY.has(m.freeType)
);
const recurringCredits = dedupedSum(
models,
(m) => m.creditTokens,
(m) => m.freeType === "recurring-credit"
(m) => RECURRING_CREDIT.has(m.freeType)
);
const oneTimeCredits = dedupedSum(
models,
(m) => m.creditTokens,
(m) => m.freeType === "one-time-initial"
(m) => ONE_TIME_CREDIT.has(m.freeType)
);
const steadyWithRecurringCreditsTokens = steadyRecurringTokens + recurringCredits;
const firstMonthRealisticTokens = steadyWithRecurringCreditsTokens + oneTimeCredits;
const poolCount = new Set(
models.filter((m) => RECURRING.has(m.freeType) && m.poolKey).map((m) => m.poolKey)
models.filter((m) => STEADY_MONTHLY.has(m.freeType) && m.poolKey).map((m) => m.poolKey)
).size;
// Deposit-unlock boost: sum the FREE_TIER_BOOSTS whose pool still has a live
// recurring model in the (optionally ToS-filtered) set.
const livePools = new Set(
models.filter((m) => RECURRING.has(m.freeType) && m.poolKey).map((m) => m.poolKey)
models.filter((m) => STEADY_MONTHLY.has(m.freeType) && m.poolKey).map((m) => m.poolKey)
);
const boostMonthlyTokens = Object.entries(FREE_TIER_BOOSTS)
.filter(([pool]) => livePools.has(pool))
@@ -170,7 +243,7 @@ export function computeFreeModelTotals(opts: { excludeTosAvoid?: boolean } = {})
// Permanently-free-but-uncapped providers (real access, no published cap).
const uncappedProviders = [
...new Set(models.filter((m) => m.freeType === "recurring-uncapped").map((m) => m.provider)),
...new Set(models.filter((m) => UNCAPPED.has(m.freeType)).map((m) => m.provider)),
].sort();
return {

View File

@@ -49,16 +49,13 @@
* same set, by construction — no new enforcement point needed.
*/
import {
allowsNoAuthShortcut,
FREE_MODEL_BUDGETS,
grantsFreeAccess,
type FreeModelBudget,
} from "@omniroute/open-sse/config/freeModelCatalog.ts";
import { SYNTHETIC_NOAUTH_CONNECTION_ID } from "./resilienceCandidateFilter";
/** Types whose allowance needs no runtime verification: no credential exists
* for the candidate at all, so no request against it can ever be billed. */
const KEYLESS_FREE_TYPES = new Set<FreeModelBudget["freeType"]>(["keyless"]);
export type FreeAccessStatus = "SAFE" | "EXHAUSTED" | "UNKNOWN";
/** Live-checked allowance state for one (provider, connection) pair. Resolved
@@ -174,7 +171,7 @@ export function evaluateCandidateConnections(
if (!budgetEntry) return []; // not in the catalog at all → paid, or genuinely unknown
const isGenuineNoAuthCandidate = candidate.connectionId === SYNTHETIC_NOAUTH_CONNECTION_ID;
if (KEYLESS_FREE_TYPES.has(budgetEntry.freeType)) {
if (allowsNoAuthShortcut(budgetEntry.freeType)) {
// The keyless shortcut is trustworthy ONLY when this specific candidate
// instance actually has no credential behind it. A `keyless`-catalogued
// model reached through a real DB connection (connectionId is a real id,

View File

@@ -0,0 +1,103 @@
import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import {
FREE_REGIME_TRAITS,
computeFreeModelTotals,
freeTypesInBucket,
grantsFreeAccess,
type FreeModelFreeType,
} from "../../open-sse/config/freeModelCatalog.ts";
const ALL_FREE_TYPES: FreeModelFreeType[] = [
"recurring-daily",
"recurring-monthly",
"recurring-credit",
"recurring-uncapped",
"one-time-initial",
"keyless",
"discontinued",
];
test("every free-tier regime is classified for every question the table answers", () => {
assert.deepEqual(Object.keys(FREE_REGIME_TRAITS).sort(), [...ALL_FREE_TYPES].sort());
for (const freeType of ALL_FREE_TYPES) {
const traits = FREE_REGIME_TRAITS[freeType];
assert.equal(typeof traits.grantsFreeAccess, "boolean", `${freeType}: grantsFreeAccess`);
assert.equal(typeof traits.tokenBucket, "string", `${freeType}: tokenBucket`);
assert.equal(
typeof traits.allowsNoAuthShortcut,
"boolean",
`${freeType}: allowsNoAuthShortcut`
);
}
});
test("each regime declares the one totals bucket it feeds", () => {
const buckets = Object.fromEntries(
ALL_FREE_TYPES.map((t) => [t, FREE_REGIME_TRAITS[t].tokenBucket])
);
assert.deepEqual(buckets, {
"recurring-daily": "steady-monthly",
"recurring-monthly": "steady-monthly",
keyless: "steady-monthly",
"recurring-credit": "recurring-credit",
"one-time-initial": "one-time-credit",
"recurring-uncapped": "uncapped",
discontinued: "none",
});
});
test("the steady-headline set derived from the table is the one the totals were built on", () => {
// Non-regression lock. Before this table existed, `RECURRING` was a hand-kept
// literal; these three regimes are what the published homepage totals have
// always summed. A fourth regime silently joining this bucket would inflate
// the headline with no other test noticing.
assert.deepEqual([...freeTypesInBucket("steady-monthly")].sort(), [
"keyless",
"recurring-daily",
"recurring-monthly",
]);
});
test("a regime that grants no free access feeds no total", () => {
for (const freeType of ALL_FREE_TYPES) {
if (grantsFreeAccess(freeType)) continue;
assert.equal(
FREE_REGIME_TRAITS[freeType].tokenBucket,
"none",
`${freeType} does not grant free access, so it cannot feed a free-tier total`
);
}
});
test("only the keyless regime takes the no-auth shortcut", () => {
const shortcut = ALL_FREE_TYPES.filter((t) => FREE_REGIME_TRAITS[t].allowsNoAuthShortcut);
assert.deepEqual(shortcut, ["keyless"]);
});
test("the dashboard's own copy of the steady regimes still matches the derived set", () => {
// FreeBudgetCard states the invariant it depends on: "Segments therefore sum
// to `steadyRecurringTokens`". It cannot import the catalog — that would pull
// every budget row into the client bundle — so the copy is guarded here
// instead of being hoped for.
const card = readFileSync(
new URL(
"../../src/app/(dashboard)/dashboard/usage/components/FreeBudgetCard.tsx",
import.meta.url
),
"utf8"
);
const literal = card.match(/const RECURRING_TYPES = new Set\(\[([^\]]*)\]\)/);
assert.ok(literal, "RECURRING_TYPES literal not found in FreeBudgetCard.tsx");
const clientSide = [...literal[1].matchAll(/"([^"]+)"/g)].map((m) => m[1]).sort();
assert.deepEqual(clientSide, [...freeTypesInBucket("steady-monthly")].sort());
});
test("totals stay split across the buckets the table declares", () => {
const totals = computeFreeModelTotals();
assert.ok(totals.steadyRecurringTokens > 0);
assert.ok(totals.steadyWithRecurringCreditsTokens >= totals.steadyRecurringTokens);
assert.ok(totals.firstMonthRealisticTokens >= totals.steadyWithRecurringCreditsTokens);
assert.ok(totals.uncappedProviders.length >= 3);
});