Skip to main content

UsageStore

@forge/monorepo


@forge/monorepo / backend/src / UsageStore

Interface: UsageStore

Defined in: backend/src/persistence/index.ts:712

Append-only usage ledger (docs/12). Events are never edited or deleted; corrections are new compensating events. Rollups are derived from events, never a second source of truth. Appends are idempotent on (runId, stepId) (or id) so a recovered run never double-counts.

Methods

append()

append(input): Promise<void>

Defined in: backend/src/persistence/index.ts:713

Parameters

input

TenantScope & object

Returns

Promise<void>


breakdown()

breakdown(input): Promise<readonly object[]>

Defined in: backend/src/persistence/index.ts:727

Consumption grouped by model or by conversation, over a bounded range (#140).

From the ledger, not the rollups, and that is a deliberate trade rather than an oversight. Rollups are keyed on (tenant, period, bucket); adding a model and a conversation dimension would multiply the row count by the product of both cardinalities to serve a panel nobody opens per second. A breakdown over one period is a bounded scan served by the (tenant_id, occurred_at) index — where the headline total, which is read on every page load and every quota check, comes from a rollup.

limit because a tenant can have thousands of conversations and a breakdown of all of them is not a breakdown. Returned largest-first so the truncation drops what matters least.

Parameters

input

TenantScope & object

Returns

Promise<readonly object[]>


listByRun()

listByRun(input): Promise<Page<UsageEvent>>

Defined in: backend/src/persistence/index.ts:714

Parameters

input

TenantScope & PageRequest & object

Returns

Promise<Page<UsageEvent>>


totals()

totals(input): Promise<UsageTotals>

Defined in: backend/src/persistence/index.ts:773

Running totals, optionally scoped to a run or conversation — used by reserve() and rollups.

Parameters

input

TenantScope & object

Returns

Promise<UsageTotals>


totalsBetween()

totalsBetween(input): Promise<{ earliestAt: string | null; totals: UsageTotals; }>

Defined in: backend/src/persistence/index.ts:763

Totals over an exact half-open interval [from, to), and the earliest record inside it — #181.

The rollups cannot answer this. They are keyed on (tenant, period, bucket), and a rolling window has no bucket: a five-hour allowance that began at 09:37 spans parts of six hourly buckets, and summing those over-counts at both edges by whatever fell outside the window. An approximate spend limit is worse than none, because the number is used to refuse people.

So this reads the ledger, over the same (tenant_id, occurred_at) index breakdown uses, and the scan is bounded by the window rather than by history. breakdown was not reused because its limit truncates — fine for a panel, wrong for a total that decides admission.

earliestAt is null when nothing was spent in the window, and otherwise the occurredAt of the oldest record in it. A sliding window never "resets", so this is what makes a true statement possible about when headroom returns: at earliestAt + length that record leaves the window. Deriving it here rather than in the caller keeps it consistent with the totals it came from — computed from two queries, they could disagree about a record that arrived between them.

modelId scopes it to one model (#182). principalId scopes it to one person; absent means the whole tenant, not "unknown principal" — a rolling tenant limit has to see everyone's spend.

Parameters

input

TenantScope & object

Returns

Promise<{ earliestAt: string | null; totals: UsageTotals; }>