Part 2 of what #1917 asked. A module and its test; nothing in the server, MCP, the terminal or any page calls it yet (#1918 does that).
Done looks like:
[ ] src/core/usage_count.ts exports createUsageCounter(db) returning {count, flush, stop}, and readUsage(db, sinceHour). count({pattern, method, status, role, surface}) refuses a role outside anon|user|admin|agent, a surface outside api|mcp|web, an unknown method, a status outside 200–599, and an empty or over-200-character pattern; status is kept as its class.
[ ] count is one in-memory increment and runs no query. flush writes every pending key in one transaction as an upsert that adds to n. It flushes on its own about a second after the first pending count, once 500 keys are pending (deferred, never inside count), and on stop(). Its timer is unref'd so it never holds a process or a test open.
[ ] test/usage-count.test.ts, on a fresh in-memory or temp database: three counts of one key are one row of 3 after a flush; no row before the flush; two hours make two rows; a refused role writes nothing. Under 1 s a test. It is named in GATE in scripts/gate.ts in the same commit.
Files: src/core/usage_count.ts, test/usage-count.test.ts, scripts/gate.ts. Run bun x tsc --noEmit, the new test and test/check-list.test.ts before pushing. A failure elsewhere that also fails on main is named in the pull with its sha, not fixed here.
Part 2 of what #1917 asked. A module and its test; nothing in the server, MCP, the terminal or any page calls it yet (#1918 does that).
Done looks like:
src/core/usage_count.tsexportscreateUsageCounter(db)returning{count, flush, stop}, andreadUsage(db, sinceHour).count({pattern, method, status, role, surface})refuses a role outsideanon|user|admin|agent, a surface outsideapi|mcp|web, an unknown method, a status outside 200–599, and an empty or over-200-character pattern; status is kept as its class.countis one in-memory increment and runs no query.flushwrites every pending key in one transaction as an upsert that adds ton. It flushes on its own about a second after the first pending count, once 500 keys are pending (deferred, never insidecount), and onstop(). Its timer isunref'd so it never holds a process or a test open.test/usage-count.test.ts, on a fresh in-memory or temp database: three counts of one key are one row of 3 after a flush; no row before the flush; two hours make two rows; a refused role writes nothing. Under 1 s a test. It is named inGATEinscripts/gate.tsin the same commit.Files: src/core/usage_count.ts, test/usage-count.test.ts, scripts/gate.ts. Run
bun x tsc --noEmit, the new test andtest/check-list.test.tsbefore pushing. A failure elsewhere that also fails on main is named in the pull with its sha, not fixed here.