Skip to content

Commit 1a8eb31

Browse files
ofershapcursoragent
andcommitted
fix: update mock DB to match current schema and data patterns
Aligns mock data generator with live schema: daily_spend PK, epoch ms timestamps for usage events, real API event kinds, new anomaly types (plan_exhausted, users_limited, team_budget), and metadata entries. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 172b657 commit 1a8eb31

2 files changed

Lines changed: 180 additions & 8 deletions

File tree

data/mock.db

4.26 MB
Binary file not shown.

scripts/generate-mock-db.ts

Lines changed: 180 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,27 @@ const MCP_TOOLS = [
196196
{ tool: "query-docs", server: "context7" },
197197
];
198198

199+
const COMMANDS = [
200+
"generate",
201+
"edit",
202+
"explain",
203+
"refactor",
204+
"fix",
205+
"test",
206+
"review",
207+
"document",
208+
"optimize",
209+
"debug",
210+
];
211+
212+
const EVENT_KINDS = [
213+
"Usage-based",
214+
"Included in Business",
215+
"Included in Business",
216+
"Included in Business",
217+
"Errored, Not Charged",
218+
];
219+
199220
const CLIENT_VERSIONS = [
200221
"2.2.36",
201222
"2.2.43",
@@ -461,15 +482,15 @@ function run() {
461482
metric: "spend",
462483
value: rand(5000, 20000),
463484
threshold: rand(2000, 5000),
464-
msg: `${user.name}: daily spend spiked to $${rand(50, 200)} (${rand(3, 6)}.${rand(1, 9)}x their 7-day avg) model: ${user.primaryModel}`,
485+
msg: `${user.name}: daily spend spiked to $${rand(50, 200)} (${rand(3, 6)}.${rand(1, 9)}x their 7-day avg) - model: ${user.primaryModel}`,
465486
},
466487
{
467-
type: "trend",
468-
severity: "warning",
469-
metric: "spend",
470-
value: rand(30000, 100000),
471-
threshold: rand(10000, 30000),
472-
msg: `${user.name}: cycle spend $${rand(300, 1000)} is ${rand(3, 6)}.${rand(1, 9)}x the team median — model: ${user.primaryModel}`,
488+
type: "threshold",
489+
severity: "info",
490+
metric: "plan_exhausted",
491+
value: rand(50, 500),
492+
threshold: 0,
493+
msg: `${user.name}: exceeded included plan usage on day ${rand(3, 14)} of cycle. ${rand(50, 500)} extra requests billed since.`,
473494
},
474495
];
475496
const anomaly = pick(types);
@@ -634,9 +655,150 @@ function run() {
634655
});
635656
cvTx();
636657

658+
const eventStmt = db.prepare(
659+
`INSERT INTO usage_events (user_email, timestamp, model, kind, max_mode, requests_cost_cents,
660+
total_cents, total_tokens, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,
661+
is_chargeable, is_headless) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
662+
);
663+
const eventTx = db.transaction(() => {
664+
for (let d = 0; d < DAYS; d++) {
665+
const date = dateStr(DAYS - 1 - d);
666+
for (const user of userProfiles) {
667+
const eventsPerDay =
668+
user.activityLevel === "high"
669+
? rand(10, 40)
670+
: user.activityLevel === "medium"
671+
? rand(3, 15)
672+
: rand(0, 5);
673+
for (let e = 0; e < eventsPerDay; e++) {
674+
const model =
675+
Math.random() < 0.8 ? user.primaryModel : weightedPick(MODELS, MODEL_WEIGHTS);
676+
const kind = pick(EVENT_KINDS);
677+
const isMax = model.includes("-max") ? 1 : 0;
678+
const inputTokens = rand(500, 50000);
679+
const outputTokens = rand(100, 20000);
680+
const cacheRead = rand(0, inputTokens);
681+
const cacheWrite = rand(0, Math.floor(inputTokens * 0.3));
682+
const totalCents = +(
683+
((inputTokens + outputTokens) * 0.001 + (isMax ? 2 : 0.3)) *
684+
(0.5 + Math.random())
685+
).toFixed(2);
686+
const hour = rand(7, 22);
687+
const minute = rand(0, 59);
688+
const ts = String(
689+
new Date(
690+
`${date}T${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}:${String(rand(0, 59)).padStart(2, "0")}Z`,
691+
).getTime(),
692+
);
693+
eventStmt.run(
694+
user.email,
695+
ts,
696+
model,
697+
kind,
698+
isMax,
699+
totalCents,
700+
totalCents,
701+
inputTokens + outputTokens,
702+
inputTokens,
703+
outputTokens,
704+
cacheRead,
705+
cacheWrite,
706+
1,
707+
0,
708+
);
709+
}
710+
}
711+
}
712+
});
713+
eventTx();
714+
715+
const cmdStmt = db.prepare(
716+
"INSERT INTO analytics_commands (date, command_name, usage) VALUES (?, ?, ?)",
717+
);
718+
const cmdTx = db.transaction(() => {
719+
for (let d = 0; d < DAYS; d++) {
720+
const date = dateStr(DAYS - 1 - d);
721+
for (const cmd of COMMANDS) {
722+
cmdStmt.run(date, cmd, rand(5, 150));
723+
}
724+
}
725+
});
726+
cmdTx();
727+
728+
const planStmt = db.prepare("INSERT INTO analytics_plans (date, model, usage) VALUES (?, ?, ?)");
729+
const planTx = db.transaction(() => {
730+
for (let d = 0; d < DAYS; d++) {
731+
const date = dateStr(DAYS - 1 - d);
732+
for (let m = 0; m < Math.min(5, MODELS.length); m++) {
733+
planStmt.run(date, MODELS[m], rand(1, 30));
734+
}
735+
}
736+
});
737+
planTx();
738+
637739
const metaStmt = db.prepare("INSERT INTO metadata (key, value, updated_at) VALUES (?, ?, ?)");
638740
metaStmt.run("cycle_start", CYCLE_START, now);
639741
metaStmt.run("cycle_end", CYCLE_END, now);
742+
metaStmt.run("limited_users_count", "3", now);
743+
metaStmt.run("team_budget_threshold", "15000", now);
744+
745+
const teamAnomalyDetected = `${dateStr(1)} 09:00:00`;
746+
const teamAnomalyAlerted = `${dateStr(1)} 09:00:05`;
747+
const teamResult = anomalyStmt.run(
748+
"team",
749+
"threshold",
750+
"warning",
751+
"users_limited",
752+
3,
753+
0,
754+
"3 team members are limited and unable to make requests. Review team spend limits on the Cursor dashboard.",
755+
teamAnomalyDetected,
756+
null,
757+
teamAnomalyAlerted,
758+
null,
759+
null,
760+
null,
761+
);
762+
incidentStmt.run(
763+
Number(teamResult.lastInsertRowid),
764+
"team",
765+
"open",
766+
teamAnomalyDetected,
767+
teamAnomalyAlerted,
768+
null,
769+
null,
770+
2,
771+
null,
772+
null,
773+
);
774+
775+
const budgetResult = anomalyStmt.run(
776+
"team",
777+
"threshold",
778+
"warning",
779+
"team_budget",
780+
1310982,
781+
1500000,
782+
"Team spend $13,110 has reached the $15,000 budget threshold (87%).",
783+
`${dateStr(0)} 10:00:00`,
784+
null,
785+
`${dateStr(0)} 10:00:05`,
786+
null,
787+
null,
788+
null,
789+
);
790+
incidentStmt.run(
791+
Number(budgetResult.lastInsertRowid),
792+
"team",
793+
"open",
794+
`${dateStr(0)} 10:00:00`,
795+
`${dateStr(0)} 10:00:05`,
796+
null,
797+
null,
798+
1,
799+
null,
800+
null,
801+
);
640802

641803
db.close();
642804
console.log(`Mock database generated at ${DB_PATH}`);
@@ -706,7 +868,7 @@ function createSchema(db: Database.Database) {
706868
CREATE TABLE IF NOT EXISTS daily_spend (
707869
date TEXT NOT NULL, email TEXT NOT NULL, spend_cents INTEGER NOT NULL DEFAULT 0,
708870
cycle_start TEXT NOT NULL, collected_at TEXT NOT NULL DEFAULT (datetime('now')),
709-
PRIMARY KEY (date, email, cycle_start)
871+
PRIMARY KEY (date, email)
710872
);
711873
CREATE INDEX IF NOT EXISTS idx_daily_spend_email ON daily_spend(email);
712874
CREATE INDEX IF NOT EXISTS idx_daily_spend_date ON daily_spend(date);
@@ -756,6 +918,16 @@ function createSchema(db: Database.Database) {
756918
percentage REAL NOT NULL DEFAULT 0, collected_at TEXT NOT NULL DEFAULT (datetime('now')),
757919
PRIMARY KEY (date, version)
758920
);
921+
CREATE TABLE IF NOT EXISTS analytics_commands (
922+
date TEXT NOT NULL, command_name TEXT NOT NULL, usage INTEGER NOT NULL DEFAULT 0,
923+
collected_at TEXT NOT NULL DEFAULT (datetime('now')),
924+
PRIMARY KEY (date, command_name)
925+
);
926+
CREATE TABLE IF NOT EXISTS analytics_plans (
927+
date TEXT NOT NULL, model TEXT NOT NULL, usage INTEGER NOT NULL DEFAULT 0,
928+
collected_at TEXT NOT NULL DEFAULT (datetime('now')),
929+
PRIMARY KEY (date, model)
930+
);
759931
CREATE TABLE IF NOT EXISTS metadata (
760932
key TEXT PRIMARY KEY, value TEXT NOT NULL,
761933
updated_at TEXT NOT NULL DEFAULT (datetime('now'))

0 commit comments

Comments
 (0)