/** * The month, ended on a measured position — the 1.67 arc's one answer. * * The product refuses to forecast, and that refusal stays. But "refuses to * forecast" and "cannot say where the month stands" are different sentences: * the measured burn, the days measured, and the arithmetic distance to each * configured ceiling are all measurements — and before this module they were * scattered across `profile`, `budgetPositions` and `watch` rather than * answerable as one question. * * **One source, named.** Everything here is measured from a usage log — the * record of what was called, priced record by record. The store's monthly * standing (provider-billed buckets, the number `serve` and `store` report) * is a different measurement of a different thing, and folding the two into * one figure would be the two-doors defect with extra steps. The document * says `source: "usage-log"` so no reader has to guess which this is. * * **The distance is division, labelled as division.** "At this measured * rate, the limit is N days away" is `remaining ÷ (measured ÷ days * measured)` — arithmetic on the past, stated with its own denominators. It * is absent, not zeroed, when the rate stands on fewer measured days than * `MIN_SCALE_DAYS`, the same floor every scaled figure in this product * respects; absent when nothing was measured; and absent on an `over`, * because the distance to a place you have already passed is not a number * this tool prints. There is no field naming a date, here or anywhere. */ import type { BudgetPeriod } from './budget.js'; import type { UsageRecord } from './usage.js'; import type { PricingCatalogue } from './pricing.js'; import type { LimitsConfig, SpendConfig } from './config-schema.js'; /** What a position is measured against, and over which window. */ export type PositionScope = 'month' | 'day' | 'label'; export interface PositionDistance { /** `remainingUsd ÷ usdPerDay`. Division on the past, not a prediction. */ daysAway: number; /** The measured rate: month-to-date spend over the days that measured it. */ usdPerDay: number; /** The denominator of the rate — how many measured days stand behind it. */ overDays: number; /** Always `division`: what this number is, stated in the number. */ arithmetic: 'division'; } export interface PositionStanding { scope: PositionScope; /** Which label, when the scope is `label`. Null otherwise. */ label: string | null; limitUsd: number; /** Priced from the log's own records. Never an estimate. */ measuredUsd: number; remainingUsd: number; /** The window the measured figure covers. */ window: { fromMs: number; toMs: number; }; /** Distinct UTC days inside the window carrying any measurement. */ daysMeasured: number; /** Days of the window already elapsed when this was computed. */ daysElapsed: number; verdict: 'within' | 'over' | 'cannot-tell'; /** * Present only when it means something: a `within` verdict standing on at * least `MIN_SCALE_DAYS` measured days and a non-zero rate. Null is "this * arithmetic would mislead", never "we forgot". */ distance: PositionDistance | null; } /** * What a position document deliberately does not answer. * * Codes rather than prose, like every other document here: a consumer can * branch on them, and each rendering carries the sentence in its own * language. */ export type PositionCaveat = 'session-limit-at-the-doors' | 'no-ceiling-configured'; /** A configured ceiling this log cannot measure, with the reason stated. */ export interface UnmeasuredPosition { scope: PositionScope; label: string | null; limitUsd: number; why: 'no-clock' | 'no-labels' | 'nothing-recorded' | 'label-unseen'; } export interface PositionDocument { schemaVersion: 1; /** Where every figure below was measured from. */ source: 'usage-log'; month: BudgetPeriod; positions: PositionStanding[]; /** Configured ceilings the log cannot answer for, each with the reason. */ unmeasured: UnmeasuredPosition[]; /** * What this document deliberately does not answer, stated rather than * implied. The per-session ceiling is judged per call at the doors — a * session is not a calendar scope, and a "session position for the month" * would be an average wearing a limit's name. */ cannotSay: PositionCaveat[]; /** Records whose model the catalogue cannot price — money nobody can see. */ unpricedRecords: number; } /** * The position, measured from one parsed usage log. * * Pure over its inputs, like `judgeLimits` and for the same reason: the * same function answers at the CLI, in the HTML door and over MCP, so the * surfaces cannot disagree about where the month stands. */ export declare function positionReport(records: readonly UsageRecord[], config: { spend?: SpendConfig; limits?: LimitsConfig; }, options: { catalogue: PricingCatalogue; on?: Date; }): PositionDocument; //# sourceMappingURL=position-report.d.ts.map