fix(free-tier): serve the Radar overlay from /api/free-tier/summary (#11550)

Validated in a combined 4-PR batch worktree off release/v3.8.51 tip. Also removed an unused `crypto` import from the new test file (one-line lint fix, 228→229 unrelated-drift comparison confirmed it was the only new finding) — pushed to this branch.
- Focused tests: free-tier-summary-radar-overlay.test.ts (9/9) + free-model-catalog/free-catalog-2026-07-expansion/free-providers-batch-2026-07 — part of batch's 60/60 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:docs-counts-sync — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff (after the crypto-import fix)

Thanks for this — the community/live feed entitlement distinction (never re-publishing paid feed content to anonymous callers) mirrors #9686's treatment carefully, and the catalogUpdatedAt honesty (null over a fabricated download-time stand-in) is the right call.
This commit is contained in:
Dizzle
2026-08-26 00:49:00 +02:00
committed by GitHub
parent 3863dab149
commit d3c395bbcf
4 changed files with 367 additions and 7 deletions

View File

@@ -0,0 +1 @@
- The free-tier summary route now serves the refreshed Radar catalog when the feed is active — the same numbers the dashboard shows — and states which catalog answered plus its real build date, instead of always reporting release-frozen figures with a stale curation date. The supporter-key live feed stays reserved to authenticated callers of the instance.

View File

@@ -206,8 +206,23 @@ function dedupedSum(
return loose;
}
export function computeFreeModelTotals(opts: { excludeTosAvoid?: boolean } = {}): FreeModelTotals {
const models = FREE_MODEL_BUDGETS.filter((m) => !(opts.excludeTosAvoid && m.tos === "avoid"));
export function computeFreeModelTotals(
opts: {
excludeTosAvoid?: boolean;
/**
* The catalog to aggregate. Defaults to the static release baseline, so
* every existing caller is unchanged. Callers that resolve a fresher
* catalog (e.g. the Radar overlay) pass their entries here; an entry with
* `enabled: false` contributes nothing, exactly as if it were absent.
*/
entries?: Array<FreeModelBudget & { enabled?: boolean }>;
} = {}
): FreeModelTotals {
const catalog: ReadonlyArray<FreeModelBudget & { enabled?: boolean }> =
opts.entries ?? FREE_MODEL_BUDGETS;
const models = catalog.filter(
(m) => !(opts.excludeTosAvoid && m.tos === "avoid") && m.enabled !== false
);
const steadyRecurringTokens = dedupedSum(
models,

View File

@@ -1,7 +1,16 @@
import { computeFreeModelTotals } from "@omniroute/open-sse/config/freeModelCatalog.ts";
import { FREE_CATALOG_CURATED_AT } from "@omniroute/open-sse/config/freeModelCatalog.data.ts";
import { listNoCredentialProviders } from "@/shared/utils/providerCredentialRequirement";
import {
computeFreeModelTotals,
type FreeModelBudget,
} from "@omniroute/open-sse/config/freeModelCatalog.ts";
import {
FREE_CATALOG_CURATED_AT,
FREE_MODEL_BUDGETS,
} from "@omniroute/open-sse/config/freeModelCatalog.data.ts";
import type { MergedEntry } from "@/lib/radar/applyFeed";
import { getRadarCatalog } from "@/lib/radar";
import { sumUsageTokensThisMonth } from "@/lib/db/usageSummary";
import { isAuthenticated } from "@/shared/utils/apiAuth";
import { listNoCredentialProviders } from "@/shared/utils/providerCredentialRequirement";
const CORS = {
"Access-Control-Allow-Origin": "*",
@@ -9,6 +18,39 @@ const CORS = {
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
/**
* `hardStopGuaranteed` is a hand-curated fact about the upstream provider that
* the Radar feed does not carry, so it is read back from the baseline entry
* rather than dropped when the overlay is served.
*/
const HARD_STOP_BY_KEY = new Map(
FREE_MODEL_BUDGETS.filter((m) => m.hardStopGuaranteed !== undefined).map((m) => [
`${m.provider}:${m.modelId}`,
m.hardStopGuaranteed,
])
);
/**
* Project a merged catalog entry back onto the response's `FreeModelBudget`
* shape: the overlay's extra fields (origin, provenance, capabilities…) stay
* internal, so the published contract is identical whichever source answered.
*/
function toBudgetEntry(entry: MergedEntry): FreeModelBudget & { enabled?: boolean } {
return {
provider: entry.provider,
modelId: entry.modelId,
displayName: entry.displayName,
monthlyTokens: entry.monthlyTokens,
creditTokens: entry.creditTokens,
freeType: entry.freeType,
poolKey: entry.poolKey,
tos: entry.tos,
trainsOnPrompts: entry.trainsOnPrompts,
hardStopGuaranteed: HARD_STOP_BY_KEY.get(`${entry.provider}:${entry.modelId}`),
enabled: entry.enabled,
};
}
export function OPTIONS(): Response {
return new Response(null, { status: 204, headers: CORS });
}
@@ -16,13 +58,34 @@ export function OPTIONS(): Response {
export async function GET(req: Request): Promise<Response> {
const url = new URL(req.url);
const excludeTosAvoid = url.searchParams.get("excludeTosAvoid") === "1";
const totals = computeFreeModelTotals({ excludeTosAvoid });
// Same catalog resolution as the dashboard screens: one source of
// truth, with meta === null meaning "the baseline answered" (flag off, no
// cache, or corrupt cache).
const { entries, meta } = getRadarCatalog();
// Entitlement follows the feed server's own download-time decision: the
// community feed is the free public catalog, so it serves everyone; the
// live feed is supporter-key content, so it only reaches callers this
// instance has authenticated — never anonymous visitors, or an exposed
// instance would re-publish the paid feed for free.
const serveOverlay = meta !== null && (meta.tier !== "live" || (await isAuthenticated(req)));
const totals = serveOverlay
? computeFreeModelTotals({ excludeTosAvoid, entries: entries.map(toBudgetEntry) })
: computeFreeModelTotals({ excludeTosAvoid });
const usedThisMonth = sumUsageTokensThisMonth();
const body = {
...totals,
usedThisMonth,
remaining: Math.max(0, totals.steadyRecurringTokens - usedThisMonth),
catalogUpdatedAt: FREE_CATALOG_CURATED_AT,
// Which source answered, and the date of what was actually served — the
// feed's own build date when the overlay answers (null when a cache row
// predates build-date tracking; never the download time standing in),
// the release curation date when the baseline does.
catalogUpdatedAt: serveOverlay ? meta.generatedAt : FREE_CATALOG_CURATED_AT,
catalogSource: serveOverlay ? ("radar-overlay" as const) : ("baseline" as const),
// Computed here, not in the component: deriving it client-side would pull
// the whole provider REGISTRY into the browser bundle.
noCredentialProviders: listNoCredentialProviders(),

View File

@@ -0,0 +1,281 @@
/**
* tests/unit/free-tier-summary-radar-overlay.test.ts
*
* GET /api/free-tier/summary used to answer from the release-frozen baseline
* only, while the Radar overlay (flag RADAR_ENABLED) refreshed the very same
* catalog for the dashboard screens — two doors, two answers to one question,
* and the door that advertised a date was the stale one.
*
* The route now resolves its catalog through getRadarCatalog() like the
* screens do, reports which source answered (`catalogSource`), and states the
* date of what it ACTUALLY served: the feed's own build date when the overlay
* answers (null when a pre-migration cache row carries none — never the
* download time standing in for it), the curation date when the baseline does.
*
* Entitlement: the feed server decides community vs live at DOWNLOAD time
* (supporter key). The local instance may re-serve what it legitimately holds,
* but must not become a free relay of premium content when it is exposed to a
* network:
* - community tier => served to every caller (it is the free public feed);
* - live tier => served to authenticated callers only; anonymous
* callers keep the release-frozen baseline;
* - flag off / no cache / corrupt cache => exactly today's behaviour
* (the mirror of radar-inertia.test.ts).
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { SignJWT } from "jose";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-free-tier-summary-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.STORAGE_ENCRYPTION_KEY = "test-encryption-key-for-free-tier-summary-tests-32b";
process.env.JWT_SECRET = "test-jwt-secret-for-free-tier-summary-tests";
process.env.INITIAL_PASSWORD = "test-bootstrap-password-for-free-tier-summary-tests";
delete process.env.RADAR_ENABLED;
const core = await import("../../src/lib/db/core.ts");
const { clearAllFeatureFlagOverrides, setFeatureFlagOverride } =
await import("../../src/lib/db/featureFlags.ts");
const radarDb = await import("../../src/lib/db/radar.ts");
const { GET } = await import("../../src/app/api/free-tier/summary/route.ts");
const { computeFreeModelTotals } = await import("../../open-sse/config/freeModelCatalog.ts");
const { FREE_CATALOG_CURATED_AT } = await import("../../open-sse/config/freeModelCatalog.data.ts");
const GEN_AT = "2026-08-20T12:00:00.000Z";
const FETCHED_AT = "2026-08-25T06:00:00.000Z";
const OVERLAY_TOKENS = 1_234_567;
const DISABLED_TOKENS = 9_999_999;
async function authCookieHeader(): Promise<string> {
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
const token = await new SignJWT({ authenticated: true })
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime("1h")
.sign(secret);
return `auth_token=${token}`;
}
function feedPayload(tier: "community" | "live") {
return {
feed: "omniroute-radar",
schemaVersion: 1,
version: "2026.08.25.1",
generatedAt: GEN_AT,
tier,
counts: { providers: 1, models: 2 },
providers: [{ id: "test-radar", name: "Test Radar" }],
models: [
{
provider: "test-radar",
modelId: "overlay-model",
displayName: "Overlay Model",
familyId: null,
freeType: "recurring-monthly",
budget: { kind: "per_model", tokensPerMonth: OVERLAY_TOKENS },
limits: { rpm: null, rpd: null, tpm: null, tpd: null },
contextWindow: null,
capabilities: { tools: false, vision: false, thinking: false },
trainsOnPrompts: null,
tosRisk: "ok",
setup: null,
enabled: true,
},
{
provider: "test-radar",
modelId: "retired-model",
displayName: "Retired Model",
familyId: null,
freeType: "recurring-monthly",
budget: { kind: "per_model", tokensPerMonth: DISABLED_TOKENS },
limits: { rpm: null, rpd: null, tpm: null, tpd: null },
contextWindow: null,
capabilities: { tools: false, vision: false, thinking: false },
trainsOnPrompts: null,
tosRisk: "ok",
setup: null,
enabled: false,
},
],
quirks: [],
totals: {
dedupedTokensPerMonth: OVERLAY_TOKENS + DISABLED_TOKENS,
modelCount: 2,
poolCount: 0,
},
};
}
function resetState() {
core.resetDbInstance();
try {
if (fs.existsSync(TEST_DATA_DIR)) fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
} catch {
// ignore
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
delete process.env.RADAR_ENABLED;
clearAllFeatureFlagOverrides();
}
function seedCache(tier: "community" | "live", opts: { generatedAt?: string | null } = {}) {
radarDb.setRadarCache({
version: "2026.08.25.1",
generatedAt: "generatedAt" in opts ? (opts.generatedAt ?? undefined) : GEN_AT,
tier,
payload: JSON.stringify(feedPayload(tier)),
signature: "test-signature-not-verified-on-read",
fetchedAt: FETCHED_AT,
});
}
async function getBody(authenticated = false): Promise<Record<string, unknown>> {
const res = await GET(
new Request("https://omni.test/api/free-tier/summary", {
headers: authenticated ? { Cookie: await authCookieHeader() } : {},
})
);
assert.equal(res.status, 200);
return (await res.json()) as Record<string, unknown>;
}
// --- zero-delta default ------------------------------------------------------
test("flag off => the baseline answers, unchanged contract, honest source tag", async () => {
resetState();
const body = await getBody();
const expected = computeFreeModelTotals();
assert.equal(body.catalogSource, "baseline");
assert.equal(body.catalogUpdatedAt, FREE_CATALOG_CURATED_AT);
assert.equal(body.steadyRecurringTokens, expected.steadyRecurringTokens);
assert.equal(body.modelCount, expected.modelCount);
});
test("excludeTosAvoid still filters on the baseline path", async () => {
resetState();
const res = await GET(new Request("https://omni.test/api/free-tier/summary?excludeTosAvoid=1"));
assert.equal(res.status, 200);
const body = (await res.json()) as Record<string, unknown>;
const expected = computeFreeModelTotals({ excludeTosAvoid: true });
assert.equal(body.catalogSource, "baseline");
assert.equal(body.steadyRecurringTokens, expected.steadyRecurringTokens);
});
// --- community tier: the free public feed serves everyone --------------------
test("community tier, anonymous caller => the overlay answers, honestly dated", async () => {
resetState();
setFeatureFlagOverride("RADAR_ENABLED", "true");
seedCache("community");
const body = await getBody(false);
assert.equal(body.catalogSource, "radar-overlay");
// The honest date is the feed's BUILD date, not this install's download time.
assert.equal(body.catalogUpdatedAt, GEN_AT);
assert.notEqual(body.catalogUpdatedAt, FETCHED_AT);
const baselineSteady = computeFreeModelTotals().steadyRecurringTokens;
assert.equal(
body.steadyRecurringTokens,
(baselineSteady as number) + OVERLAY_TOKENS,
"the feed-only enabled model joins the steady headline"
);
});
test("community tier, authenticated caller => same overlay", async () => {
resetState();
setFeatureFlagOverride("RADAR_ENABLED", "true");
seedCache("community");
const body = await getBody(true);
assert.equal(body.catalogSource, "radar-overlay");
assert.equal(body.catalogUpdatedAt, GEN_AT);
});
test("an entry the feed disables is excluded from the served totals", async () => {
resetState();
setFeatureFlagOverride("RADAR_ENABLED", "true");
seedCache("community");
const body = await getBody(false);
const perModel = body.perModel as Array<{ modelId: string }>;
assert.ok(!perModel.some((m) => m.modelId === "retired-model"));
assert.equal(
body.steadyRecurringTokens,
(computeFreeModelTotals().steadyRecurringTokens as number) + OVERLAY_TOKENS
);
});
test("a pre-migration cache row serves the overlay with an UNKNOWN date, not the fetch time", async () => {
resetState();
setFeatureFlagOverride("RADAR_ENABLED", "true");
seedCache("community", { generatedAt: undefined });
const body = await getBody(false);
assert.equal(body.catalogSource, "radar-overlay");
assert.equal(
body.catalogUpdatedAt,
null,
"unknown must stay unknown — fetchedAt would re-create the confusion generated_at exists to end"
);
});
// --- live tier: paid content stays behind this instance's sessions ----------
test("live tier, ANONYMOUS caller => the baseline answers, never the premium feed", async () => {
resetState();
setFeatureFlagOverride("RADAR_ENABLED", "true");
seedCache("live");
const body = await getBody(false);
assert.equal(body.catalogSource, "baseline");
assert.equal(body.catalogUpdatedAt, FREE_CATALOG_CURATED_AT);
assert.equal(body.steadyRecurringTokens, computeFreeModelTotals().steadyRecurringTokens);
});
test("live tier, authenticated caller => this install's earned overlay", async () => {
resetState();
setFeatureFlagOverride("RADAR_ENABLED", "true");
seedCache("live");
const body = await getBody(true);
assert.equal(body.catalogSource, "radar-overlay");
assert.equal(body.catalogUpdatedAt, GEN_AT);
assert.equal(
body.steadyRecurringTokens,
(computeFreeModelTotals().steadyRecurringTokens as number) + OVERLAY_TOKENS
);
});
// --- resilience --------------------------------------------------------------
test("corrupt cache => baseline fallback with the baseline contract", async () => {
resetState();
setFeatureFlagOverride("RADAR_ENABLED", "true");
radarDb.setRadarCache({
version: "broken",
generatedAt: GEN_AT,
tier: "community",
payload: "{definitely not json",
signature: "test-signature-not-verified-on-read",
fetchedAt: FETCHED_AT,
});
const body = await getBody(false);
assert.equal(body.catalogSource, "baseline");
assert.equal(body.catalogUpdatedAt, FREE_CATALOG_CURATED_AT);
assert.equal(body.steadyRecurringTokens, computeFreeModelTotals().steadyRecurringTokens);
});