Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions PRODUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ Built as part of Nick's Omilia internship; doubles as a portfolio project.
(`src/lib/*/costing.ts`). Per-finding provenance (`rules` / `llm` / `both`),
graceful degradation to rules-only when NIM is unavailable.
- **Trust guarantees**: per-row savings capped at the row's spend, stamped
pricing-table date, ROI footer on AI-augmented reports, deterministic
8-workspace demo (`DEMO_SEED`).
- 90 vitest tests pin the money math; CI runs type-check, lint, format, test.
pricing-table date, ROI footer on AI-augmented reports.
- **Persona demo**: every "sample data" click generates a fresh org — a
sprawling enterprise (every rule fires, compounding growth arc, one
incident month) or a lean startup (1-2 minor findings, on purpose). Each
run is internally coherent across its 6 months; the generators are pure
and clock-free, reproducible via explicit seeds (`DEMO_SEED` in tests).
- 96 vitest tests pin the money math; CI runs type-check, lint, format, test.
- AGPL-3.0.

## Where it's headed
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,11 @@ Pick a vendor, paste the key, click **Analyze**. Then browse findings by
severity, spend by workspace, and history by month. The key is forgotten the
moment you close the tab — TokenPilot has the memory of a goldfish, on purpose.

No key handy? **Try with sample data** generates a seeded 8-workspace demo
org — same org, same numbers, every single run. There's also a `mock-server/`
No key handy? **Try with sample data** conjures a fresh fake org on every
click — pick a sprawling enterprise (every rule fires, spend compounding
month over month, one runaway-agent incident in the middle) or a lean startup
(barely anything to fix, on purpose). Each run stays internally coherent:
one org, one story, across all six months. There's also a `mock-server/`
for developing without burning real API calls.

## 🔩 Under the hood
Expand All @@ -129,9 +132,9 @@ flowchart LR
| ids | ULID | sortable, unique, no coordination needed |

Pre-commit: Husky + lint-staged run Prettier on everything; commitlint guards
the messages. A vitest suite (90 tests) pins the money math — every costing
formula, the consensus merge, and demo determinism. Full architecture notes
live in `CLAUDE.md`.
the messages. A vitest suite (96 tests) pins the money math — every costing
formula, the consensus merge, and the demo generators' purity. Full
architecture notes live in `CLAUDE.md`.

```bash
npm run dev # dev server
Expand Down
221 changes: 176 additions & 45 deletions src/__tests__/demo-determinism.test.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
import { describe, it, expect } from "vitest";
import { demoAnthropic, demoOpenAI, DEMO_SEED } from "@/lib/demo";
import {
demoAnthropic,
demoOpenAI,
DEMO_SEED,
type DemoPersona,
} from "@/lib/demo";
import { agg, findIssues } from "@/lib/anthropic/analysis";
import { aggOpenAI, findIssuesOpenAI } from "@/lib/openai/analysis";
import { tc } from "@/lib/anthropic/pricing";
import { tcOpenAI } from "@/lib/openai/pricing";

// Fixed base period so the test itself is clock-independent. Mirrors
// startDemo's loop: the base month plus the 5 months before it.
// startDemo's loop: the base month plus the 5 months before it, oldest
// first, with monthsAgo counting down to 0 at the base month.
const BASE_YEAR = 2026;
const BASE_MONTH = 6; // July (0-indexed)

function demoMonths(): { y: number; m: number }[] {
const out: { y: number; m: number }[] = [];
// Two arbitrary but fixed seeds — the generators must behave for any seed,
// these just make the assertions reproducible.
const SEED_A = 1234567;
const SEED_B = 89101112;

function demoMonths(): { y: number; m: number; monthsAgo: number }[] {
const out: { y: number; m: number; monthsAgo: number }[] = [];
for (let i = 5; i >= 0; i--) {
let m = BASE_MONTH - i;
let y = BASE_YEAR;
while (m < 0) {
m += 12;
y--;
}
out.push({ y, m });
out.push({ y, m, monthsAgo: i });
}
return out;
}

// Same report-building pipeline startDemo runs per month (rule engine path).
function runAnthropicDemo() {
return demoMonths().map(({ y, m }) => {
const d = demoAnthropic(y, m, DEMO_SEED);
function runAnthropicDemo(seed: number, persona: DemoPersona) {
return demoMonths().map(({ y, m, monthsAgo }) => {
const d = demoAnthropic(y, m, seed, persona, monthsAgo);
const bk = agg(d.bk);
const bm = agg(d.bm);
const src = bk.length ? bk : bm;
Expand All @@ -49,13 +60,17 @@ function runAnthropicDemo() {
savings: findings.reduce((s, f) => s + f.sav, 0),
tokens: ti + to,
findings,
cacheWrites: d.bw.reduce(
(s, b) => s + (b.cache_creation_input_tokens || 0),
0
),
};
});
}

function runOpenAIDemo() {
return demoMonths().map(({ y, m }) => {
const d = demoOpenAI(y, m, DEMO_SEED);
function runOpenAIDemo(seed: number, persona: DemoPersona) {
return demoMonths().map(({ y, m, monthsAgo }) => {
const d = demoOpenAI(y, m, seed, persona, monthsAgo);
const rows = aggOpenAI(d.usage);

let spend = 0;
Expand All @@ -81,56 +96,172 @@ function runOpenAIDemo() {
});
}

describe("demo mode determinism", () => {
it("two runs of the full 6-month Anthropic demo produce byte-identical reports", () => {
expect(JSON.stringify(runAnthropicDemo())).toBe(
JSON.stringify(runAnthropicDemo())
);
describe("demo purity and determinism", () => {
const personas: DemoPersona[] = ["enterprise", "startup"];

it("two calls with identical (year, month, seed, persona, monthsAgo) are byte-identical", () => {
for (const persona of personas) {
expect(
JSON.stringify(demoAnthropic(BASE_YEAR, BASE_MONTH, SEED_A, persona, 2))
).toBe(
JSON.stringify(demoAnthropic(BASE_YEAR, BASE_MONTH, SEED_A, persona, 2))
);
expect(
JSON.stringify(demoOpenAI(BASE_YEAR, BASE_MONTH, SEED_A, persona, 2))
).toBe(
JSON.stringify(demoOpenAI(BASE_YEAR, BASE_MONTH, SEED_A, persona, 2))
);
}
});

it("two runs of the full 6-month OpenAI demo produce byte-identical reports", () => {
expect(JSON.stringify(runOpenAIDemo())).toBe(
JSON.stringify(runOpenAIDemo())
it("two runs of the full 6-month demo produce byte-identical reports (both vendors)", () => {
expect(JSON.stringify(runAnthropicDemo(DEMO_SEED, "enterprise"))).toBe(
JSON.stringify(runAnthropicDemo(DEMO_SEED, "enterprise"))
);
expect(JSON.stringify(runOpenAIDemo(DEMO_SEED, "enterprise"))).toBe(
JSON.stringify(runOpenAIDemo(DEMO_SEED, "enterprise"))
);
});

it("all 6 months of a run come from the same org", () => {
const anth = runAnthropicDemo();
expect(new Set(anth.map((r) => r.org.name)).size).toBe(1);
const oai = runOpenAIDemo();
expect(new Set(oai.map((r) => r.org.name)).size).toBe(1);
it("a different seed produces a different org with different data", () => {
const a = demoAnthropic(BASE_YEAR, BASE_MONTH, SEED_A);
const b = demoAnthropic(BASE_YEAR, BASE_MONTH, SEED_B);
expect(JSON.stringify(a.bm)).not.toBe(JSON.stringify(b.bm));
expect(a.org.name).not.toBe(b.org.name);
expect(a.org.id).not.toBe(b.org.id);

const oa = demoOpenAI(BASE_YEAR, BASE_MONTH, SEED_A);
const ob = demoOpenAI(BASE_YEAR, BASE_MONTH, SEED_B);
expect(JSON.stringify(oa.usage)).not.toBe(JSON.stringify(ob.usage));
expect(oa.org.name).not.toBe(ob.org.name);
});

it("a different seed produces different data", () => {
const a = demoAnthropic(BASE_YEAR, BASE_MONTH, DEMO_SEED);
const b = demoAnthropic(BASE_YEAR, BASE_MONTH, DEMO_SEED + 1);
expect(JSON.stringify(a.bm)).not.toBe(JSON.stringify(b.bm));
it("all 6 months of a run come from the same org (both personas)", () => {
for (const persona of personas) {
const anth = runAnthropicDemo(SEED_A, persona);
expect(new Set(anth.map((r) => r.org.name)).size).toBe(1);
const oai = runOpenAIDemo(SEED_A, persona);
expect(new Set(oai.map((r) => r.org.name)).size).toBe(1);
}
});
});

it("the demo org has 8 workspaces plus busy default-workspace traffic", () => {
const d = demoAnthropic(BASE_YEAR, BASE_MONTH, DEMO_SEED);
describe("enterprise persona", () => {
it("has 8 workspaces plus busy default-workspace traffic", () => {
const d = demoAnthropic(BASE_YEAR, BASE_MONTH, SEED_A, "enterprise", 0);
expect(d.ws).toHaveLength(8);
// Some traffic deliberately carries no workspace_id → default workspace.
expect(d.bw.some((b) => !b.workspace_id)).toBe(true);
expect(d.bw.some((b) => b.workspace_id === "ws_prod")).toBe(true);
});

it("the demo's varied workloads fire most rule categories", () => {
const cats = new Set(
runAnthropicDemo().flatMap((r) => r.findings.map((f) => f.cat as string))
);
for (const expected of [
"Model Downgrade → Haiku",
"Model Downgrade → Sonnet",
"RAG Optimization",
"Prompt Caching",
"Batch API Migration",
"Model Upgrade",
"Workspace Organization",
]) {
expect(cats, `expected category "${expected}" to fire`).toContain(
expected
it("fires at least 6 distinct Anthropic categories in the current month", () => {
for (const seed of [SEED_A, SEED_B, DEMO_SEED]) {
const [current] = runAnthropicDemo(seed, "enterprise").slice(-1);
const cats = new Set(current.findings.map((f) => f.cat as string));
for (const expected of [
"Model Downgrade → Haiku",
"Model Downgrade → Sonnet",
"RAG Optimization",
"Prompt Caching",
"Batch API Migration",
"Model Upgrade",
"Workspace Organization",
]) {
expect(cats, `expected category "${expected}" to fire`).toContain(
expected
);
}
expect(cats.size).toBeGreaterThanOrEqual(6);
}
});

it("fires at least 6 distinct OpenAI categories in the current month", () => {
for (const seed of [SEED_A, SEED_B, DEMO_SEED]) {
const [current] = runOpenAIDemo(seed, "enterprise").slice(-1);
const cats = new Set(current.findings.map((f) => f.cat as string));
for (const expected of [
"Model Downgrade → GPT-4o-mini",
"RAG Optimization",
"Prompt Caching",
"Batch API Migration",
"Reasoning Model Overkill",
"Model Upgrade",
"Prompt Optimization",
"High-Impact Opportunity",
]) {
expect(cats, `expected category "${expected}" to fire`).toContain(
expected
);
}
expect(cats.size).toBeGreaterThanOrEqual(6);
}
});

it("6-month spend is strictly increasing, except around the incident month", () => {
// monthsAgo 2 → index 3 in the oldest-first array. The incident bumps
// that month's spend, so the following month may legitimately dip.
const incidentIdx = 3;
for (const seed of [SEED_A, SEED_B, DEMO_SEED]) {
const months = runAnthropicDemo(seed, "enterprise");
for (let i = 0; i < months.length - 1; i++) {
if (i === incidentIdx) continue;
expect(
months[i + 1].spend,
`seed ${seed}: spend should grow from month ${i} to ${i + 1}`
).toBeGreaterThan(months[i].spend);
}
// The incident month itself must sit visibly above the prior month.
expect(months[incidentIdx].spend).toBeGreaterThan(
months[incidentIdx - 1].spend * 1.1
);
}
});

it("the incident month's cache-write volume spikes vs its neighbors", () => {
const incidentIdx = 3;
for (const seed of [SEED_A, SEED_B, DEMO_SEED]) {
const months = runAnthropicDemo(seed, "enterprise");
const spike = months[incidentIdx].cacheWrites;
expect(spike).toBeGreaterThan(months[incidentIdx - 1].cacheWrites * 2.5);
expect(spike).toBeGreaterThan(months[incidentIdx + 1].cacheWrites * 2.5);
}
});
});

describe("startup persona", () => {
it("produces at most 3 findings per vendor, with modest savings", () => {
for (const seed of [SEED_A, SEED_B, DEMO_SEED]) {
const [anth] = runAnthropicDemo(seed, "startup").slice(-1);
expect(anth.findings.length).toBeGreaterThanOrEqual(1);
expect(anth.findings.length).toBeLessThanOrEqual(3);
expect(anth.savings).toBeLessThan(anth.spend * 0.3);

const [oai] = runOpenAIDemo(seed, "startup").slice(-1);
expect(oai.findings.length).toBeGreaterThanOrEqual(1);
expect(oai.findings.length).toBeLessThanOrEqual(3);
expect(oai.savings).toBeLessThan(oai.spend * 0.3);
}
});

it("is a small org: 3 Anthropic workspaces, 2 OpenAI projects", () => {
const d = demoAnthropic(BASE_YEAR, BASE_MONTH, SEED_A, "startup", 0);
expect(d.ws).toHaveLength(3);
// All startup traffic is properly workspace-tagged — no default-workspace
// mess, so no workspace-organization finding.
expect(d.bw.every((b) => !!b.workspace_id)).toBe(true);

const o = demoOpenAI(BASE_YEAR, BASE_MONTH, SEED_A, "startup", 0);
expect(o.projects).toHaveLength(2);
});

it("keeps the startup's findings minor — no critical severity", () => {
for (const seed of [SEED_A, SEED_B, DEMO_SEED]) {
const [anth] = runAnthropicDemo(seed, "startup").slice(-1);
const [oai] = runOpenAIDemo(seed, "startup").slice(-1);
for (const f of [...anth.findings, ...oai.findings]) {
expect(f.sev).not.toBe("critical");
}
}
});
});
Loading
Loading