/** * The persisted accounting format is deliberately separate from the dashboard wire format. * * SCHEMA NOTE (2026-08-22, Stage 4 spend): `spend` grew from a hard-typed `null` into real * aggregate cells, and `requestSpend`/`partiallyPricedRequests` were added beside it as an * optional pair. This is an ADDITIVE change and the schema constant stays `accounting.day.v1`: * the guards below accept BOTH shapes — a pre-spend shard's `spend: null` loads as empty cells * rather than quarantining a day of real traffic. Nothing rewrites old shards on read: the * guards tolerate absence and every reader defaults it (`?? 0`, `mergeSpend(undefined)`), so a * legacy shard reads correctly and gains the new fields only when new facts fold into it. A * bump would have discarded every existing day shard for no gain. */ export declare const ACCOUNTING_STORE_VERSION: 1; export declare const ACCOUNTING_DAY_SCHEMA: "accounting.day.v1"; export declare const ACCOUNTING_MINUTE_SCHEMA: "accounting.minute.v1"; export declare const ACCOUNTING_RECENT_SCHEMA: "accounting.recent.v1"; export declare const ACCOUNTING_LIFETIME_SCHEMA: "accounting.lifetime.v1"; export declare const ACCOUNTING_DEDUP_SCHEMA: "accounting.dedup.v1"; export declare const ACCOUNTING_MAX_SAMPLES = 25; export declare const ACCOUNTING_MAX_ROWS_PER_CELL = 512; export declare const ACCOUNTING_MAX_MINUTE_CELLS = 1440; /** Aggregate rows across all UTC minute cells in one day. */ export declare const ACCOUNTING_MAX_DAY_ROWS = 4096; export declare const ACCOUNTING_MAX_MONTHS = 720; export declare const ACCOUNTING_MAX_RECENT_ROWS = 100; export declare const ACCOUNTING_MAX_DETAIL_ATTEMPTS = 32; export declare const ACCOUNTING_MAX_DEDUP_IDS = 16384; export declare const ACCOUNTING_MAX_LOSS_MARKERS = 32; export declare const ACCOUNTING_MAX_PACKET_ATTEMPTS = 10000; export declare const ACCOUNTING_MAX_METHOD_BYTES = 256; export declare const ACCOUNTING_MAX_COUNTER: number; /** Maximum JSON UTF-8 size accepted for any persisted shard/document. */ export declare const ACCOUNTING_MAX_FILE_BYTES: number; export type AccountingOutcome = "success" | "error" | "cancelled" | "unknown"; export type AccountingFailureKind = "timeout" | "provider_error" | "auth_error" | "rate_limit" | "aborted" | "protocol" | "unknown"; export type AccountingAttribution = "relay_held" | "caller_operated" | "unknown"; export type AccountingAttemptRole = "serve" | "repair"; export type AccountingParseResult = { readonly ok: true; readonly value: Readonly; } | { readonly ok: false; readonly error: string; }; export type AccountingAggregateKind = "request" | "attempt"; export type AccountingDimension = "provider" | "model" | "client" | "credential"; export type AccountingCoverageState = "complete" | "partial" | "unavailable" | "stale" | "empty"; export type AccountingCoverageReason = "retention_pruned" | "row_cap" | "detail_cap" | "dedup_cap" | "counter_overflow" | "corrupt_recovery" | "unknown" | null; export type AccountingLossKind = "unknown" | "overflow" | "truncated" | "dedup" | "corrupt"; export interface AccountingAggregateTokenCellV1 { readonly value: number | null; readonly known: number; readonly unknown: number; readonly lost: number; readonly overflow: boolean; readonly observedAt: string | null; } export interface AccountingEstimatedTokenCellV1 extends AccountingAggregateTokenCellV1 { /** A safe method label, or the explicit aggregate states mixed/unknown. */ readonly method: string | null; } export interface AccountingAggregateTokenTotalsV1 { readonly reported: { readonly reportedInput: AccountingAggregateTokenCellV1; readonly reportedOutput: AccountingAggregateTokenCellV1; readonly reportedCachedInput: AccountingAggregateTokenCellV1; readonly cacheCreationInputTokens: AccountingAggregateTokenCellV1; readonly cacheReadInputTokens: AccountingAggregateTokenCellV1; }; readonly estimated: { readonly estimatedInput: AccountingEstimatedTokenCellV1; readonly estimatedOutput: AccountingEstimatedTokenCellV1; }; } export interface AccountingMetricCellV1 { readonly sumMs: number | null; readonly known: number; readonly unknown: number; readonly lost: number; readonly overflow: boolean; readonly samples: readonly number[]; readonly samplesDropped: number; readonly observedAt: string | null; } /** * PER-MILLION prices actually used to compute one spend figure, carried so every * amount stays re-derivable from its own record. Dollars-per-million-tokens equals * micro-dollars-per-token, so `tokens x perMillionIn` IS the micro-USD amount. */ export interface AccountingSpendPricesV1 { readonly perMillionIn: number | null; readonly perMillionOut: number | null; } /** * Coverage of ONE priced spend: which token kinds went into the amount and which * rode beside it unpriced. * - "full": every reported token kind was priced at a published price. * - "input_only": estimated-basis pricing intentionally covers input alone; * separate estimated-output metering never silently widens spend. * - "partial": at least one present token kind was left out (cache kinds, or one of * in/out unpublished). The amount is a lower bound. * * The list is the ONE declaration: the validator below reads it and the type derives from it, * so a coverage the ledger accepts can never be refused by the store, or the reverse. * `accounting.ts` imports and re-exports both — it restated the union by hand until 2026-09-04 * (audit DR-004, found by `test/one-declaration.test.ts`); this module is the home because * `accounting.ts` already imports it, and the other direction would be a cycle. */ export declare const ACCOUNTING_SPEND_COVERAGES: readonly ["full", "input_only", "partial"]; export type AccountingSpendCoverage = (typeof ACCOUNTING_SPEND_COVERAGES)[number]; /** Token kinds observed but NOT priced, per kind; null when the kind itself was absent. */ export interface AccountingUnpricedTokensV1 { readonly cacheRead: number | null; readonly cacheCreation: number | null; readonly cachedInput: number | null; } /** * One attempt's spend in exact integer micro-USD with full provenance. `null` spend * means UNPRICED (no published price resolved, or nothing to price) — never $0. * Amounts are integer micro-USD, rounded half-up once per token kind, summed as * integers, so no floating-point error can accumulate across requests. */ export interface AccountingSpendV1 { readonly amountMicrousd: number; readonly priceSource: "provider_published" | "reference"; readonly tokenBasis: "reported" | "estimated"; readonly source: "provider_reported" | "relay_estimated"; readonly coverage: AccountingSpendCoverage; readonly unpricedTokens: AccountingUnpricedTokensV1; readonly pricesUsed: AccountingSpendPricesV1; readonly observedAt: string; } /** Summing accumulator behind one wire spend cell inside an aggregate. */ export interface AccountingAggregateSpendCellV1 { /** Sum of integer micro-USD contributions; null once any contributor is uncertain or it overflows. */ readonly amountMicrousd: number | null; /** How many spends were summed into this cell. */ readonly known: number; /** Latest observation across contributors; non-null exactly when known > 0. */ readonly observedAt: string | null; } /** The four price-source x token-basis cells one aggregate carries for its scope. */ export interface AccountingAggregateSpendV1 { readonly providerPublishedReported: AccountingAggregateSpendCellV1; readonly providerPublishedEstimated: AccountingAggregateSpendCellV1; readonly referenceReported: AccountingAggregateSpendCellV1; readonly referenceEstimated: AccountingAggregateSpendCellV1; } export interface AccountingAggregateV1 { readonly requests: number; readonly attempts: number; readonly served: number; readonly errored: number; readonly cancelled: number; /** Attempt-side totals. Request-side totals are kept separately below. */ readonly tokens: AccountingAggregateTokenTotalsV1; readonly requestTokens: AccountingAggregateTokenTotalsV1; readonly latency: AccountingMetricCellV1; readonly commit: AccountingMetricCellV1; /** * Attempt-side spend cells: every completed attempt priced at PUBLISHED prices, * summed as integers. `null` is the LEGACY pre-spend shape, tolerated on read and * defaulted to empty cells by readers — it never means "zero spend". */ readonly spend: AccountingAggregateSpendV1 | null; /** * Request-side spend cells (winning serve attempt only), kept apart from * `spend` for the same reason `requestTokens` is kept apart from `tokens`: * a retried-elsewhere request must not double-count its failed attempts. * Absent entirely on legacy shards. */ readonly requestSpend?: AccountingAggregateSpendV1 | null; /** * Spend on serve attempts the RELAY abandoned — a hedge loser (owner decision D3, 2026-08-30). * * ⚠ Kept apart from `requestSpend` rather than folded into it, and the reason is a MEASUREMENT, * not tidiness: an abandoned attempt is estimated-basis with coverage "input_only", so folding it * would set `partiallyPricedRequests` — the LOWER-BOUND marker — on essentially every hedged * request without one amount changing. Winner and loser are also priced from the SAME * request-level estimated input count, so a merged figure would double-count one measurement. * * ⚠ It participates in NO counter. `unpricedRequests + partiallyPricedRequests <= requests` is * enforced below, and breaching it does not throw — the snapshot build returns null and the store * silently stops persisting. * * "What the answer you received cost" is `requestSpend`. "What this request cost" is * `requestSpend + abandonedSpend`. Absent entirely on legacy shards, and on every request that * ran no hedge. */ readonly abandonedSpend?: AccountingAggregateSpendV1 | null; /** * Requests whose spend figure exists but left present token kinds unpriced * (cache kinds, or one of in/out unpublished) — i.e. every amount above is a * lower bound while this is > 0. Absent (= 0) on legacy shards. */ readonly partiallyPricedRequests?: number; /** Requests with NO spend figure at all: unserved, or a deployment publishing no price. */ readonly unpricedRequests: number; } interface AccountingDimensionRowBaseV1 extends AccountingAggregateV1 { readonly kind: AccountingAggregateKind; readonly role: "request" | AccountingAttemptRole; /** Full compound tuple. P2 derives provider/model/client/credential views later. */ readonly provider: string | null; readonly model: string | null; readonly client: string | null; readonly credentialId: string | null; readonly attribution: AccountingAttribution; readonly outcome: AccountingOutcome; readonly failureKind: AccountingFailureKind | null; } export interface AccountingRequestDimensionRowV1 extends AccountingDimensionRowBaseV1 { readonly kind: "request"; readonly role: "request"; } export interface AccountingAttemptDimensionRowV1 extends AccountingDimensionRowBaseV1 { readonly kind: "attempt"; readonly role: AccountingAttemptRole; } export type AccountingDimensionRowV1 = AccountingRequestDimensionRowV1 | AccountingAttemptDimensionRowV1; export type AccountingCompoundDimensionRowV1 = AccountingDimensionRowV1; /** Compatibility alias used by the store implementation. */ export type AccountingAggregateRowV1 = AccountingDimensionRowV1; export type AccountingAggregate = AccountingAggregateV1; export type AccountingAggregateRow = AccountingDimensionRowV1; export type AggregateTokenCell = AccountingAggregateTokenCellV1; export type AggregateTokenTotals = AccountingAggregateTokenTotalsV1; export type AggregateMetric = AccountingMetricCellV1; export interface AccountingLossMarkerV1 { readonly kind: AccountingLossKind; readonly count: number; readonly field: string | null; } export interface AccountingCoverageV1 { readonly state: AccountingCoverageState; readonly reason: AccountingCoverageReason; readonly droppedRows: number; readonly droppedRecent: number; readonly droppedDetails: number; readonly droppedDedup: number; readonly retentionFrom: string | null; readonly retentionDays: number | null; readonly losses: readonly AccountingLossMarkerV1[]; } export type AccountingCellCoverageV1 = Pick; export interface AccountingMinuteShardV1 { readonly schema: "accounting.minute.v1"; readonly version: typeof ACCOUNTING_STORE_VERSION; readonly date: string; readonly minute: string; readonly from: string; readonly to: string; readonly aggregate: AccountingAggregateV1; readonly rows: readonly AccountingDimensionRowV1[]; readonly coverage: AccountingCellCoverageV1; } /** Compatibility name for callers that call a minute a cell. */ export type AccountingMinuteCellV1 = AccountingMinuteShardV1; export type AccountingMinuteCell = AccountingMinuteShardV1; export interface AccountingCompletedRequestDedupV1 { readonly schema: typeof ACCOUNTING_DEDUP_SCHEMA; readonly version: typeof ACCOUNTING_STORE_VERSION; readonly date: string; /** Sorted, unique IDs retained for exact replay suppression. */ readonly requestIds: readonly string[]; /** IDs older than the bounded set are not claimed to be deduplicated. */ readonly dropped: number; readonly complete: boolean; } /** Compatibility alias for a store's per-day dedup index. */ export type AccountingDedupMetadataV1 = AccountingCompletedRequestDedupV1; export interface AccountingDayShardV1 { readonly schema: typeof ACCOUNTING_DAY_SCHEMA; readonly version: typeof ACCOUNTING_STORE_VERSION; readonly date: string; /** Sparse UTC minute cells; absent keys mean no observed data. */ readonly cells: Readonly>; readonly dedup: AccountingCompletedRequestDedupV1; readonly coverage: AccountingCoverageV1; } export type AccountingDayShard = AccountingDayShardV1; export interface AccountingMonthAggregateV1 { readonly month: string; readonly aggregate: AccountingAggregateV1; readonly coverage: AccountingCoverageV1; } export interface AccountingLifetimeV1 { readonly schema: typeof ACCOUNTING_LIFETIME_SCHEMA; readonly version: typeof ACCOUNTING_STORE_VERSION; readonly firstRequestAt: string | null; readonly lastRequestAt: string | null; readonly aggregate: AccountingAggregateV1; readonly months: Readonly>; readonly coverage: AccountingCoverageV1; } export type AccountingLifetime = AccountingLifetimeV1; export interface AccountingAttemptPacketV1 { readonly requestId: string; readonly attemptId: string; readonly role: AccountingAttemptRole; readonly startedAt: string; readonly endedAt: string; readonly outcome: AccountingOutcome; readonly failureKind: AccountingFailureKind | null; readonly attribution: AccountingAttribution; readonly latencyMs: number | null; readonly commitMs: number | null; readonly provider: string | null; readonly model: string | null; readonly credentialId: string | null; readonly tokens: AccountingAggregateTokenTotalsV1; /** This attempt's priced spend, or LEGACY/absent. `null` = unpriced, never $0. */ readonly spend: AccountingSpendV1 | null; } export type AccountingAttemptPacket = AccountingAttemptPacketV1; export interface AccountingDetailAttemptMetadataV1 { readonly total: number; readonly stored: number; readonly dropped: number; } export interface AccountingRequestPacketV1 { readonly requestId: string; readonly startedAt: string; readonly endedAt: string; readonly client: string | null; readonly attribution: AccountingAttribution; readonly outcome: AccountingOutcome; readonly failureKind: AccountingFailureKind | null; readonly attemptCount: number; readonly repairIncluded: boolean; readonly winningAttemptId: string | null; readonly commitAttemptId: string | null; readonly latencyMs: number | null; readonly commitMs: number | null; readonly provider: string | null; readonly model: string | null; readonly credentialId: string | null; readonly tokens: AccountingAggregateTokenTotalsV1; /** * The WINNING SERVE attempt's spend, mirroring `tokens`. Repair spend stays on * its own attempt rows (C1) so a later `--include-repair` roll-up can add it * back without double-counting the serve. */ readonly spend: AccountingSpendV1 | null; readonly attempts: readonly AccountingAttemptPacketV1[]; readonly attemptMetadata: AccountingDetailAttemptMetadataV1; } export type AccountingRequestPacket = AccountingRequestPacketV1; export interface AccountingRecentV1 { readonly schema: typeof ACCOUNTING_RECENT_SCHEMA; readonly version: typeof ACCOUNTING_STORE_VERSION; readonly rows: readonly AccountingRequestPacketV1[]; readonly details: Readonly>; readonly coverage: AccountingCoverageV1; } export declare function accountingSerializedBytes(value: unknown): number | null; /** * Will the LOADER accept this string? * * Exported because the ACCEPT side must not be laxer than the load side. `isDashboardSafeId` * bounds length and bytes but permits C0/C1 control characters, while `isSafeId` below rejects * them — so a value admitted at record time could be merged into a cell, written to a day shard, * and then fail `parseAccountingDayShardV1` on the next load, QUARANTINING that shard and losing * the day's ledger. Latent rather than live (the one production caller passes a literal, and * `JSON.stringify` escapes control characters), but the asymmetry is the defect: a persisted * value's admission test belongs to whoever will have to read it back. */ export declare function isLoadableId(value: unknown): value is string; /** The one deep-freeze for the accounting modules; shared, not re-implemented. */ export declare function freezeDeep(value: T): T; export declare const isAccountingAggregateTokenCellV1: (value: unknown) => value is AccountingAggregateTokenCellV1; export declare const isAccountingAggregateTokenTotalsV1: (value: unknown) => value is AccountingAggregateTokenTotalsV1; export declare const isAccountingMetricCellV1: (value: unknown) => value is AccountingMetricCellV1; export declare const isAccountingAggregateV1: (value: unknown) => value is AccountingAggregateV1; export declare const isAccountingDimensionRowV1: (value: unknown) => value is AccountingDimensionRowV1; export declare const isAccountingCompletedRequestDedupV1: (value: unknown) => value is AccountingCompletedRequestDedupV1; export declare const isAccountingDayShardV1: (value: unknown) => value is AccountingDayShardV1; export declare const isAccountingLifetimeV1: (value: unknown) => value is AccountingLifetimeV1; export declare const isAccountingAttemptPacketV1: (value: unknown) => value is AccountingAttemptPacketV1; export declare const isAccountingRequestPacketV1: (value: unknown) => value is AccountingRequestPacketV1; export declare const isAccountingRecentV1: (value: unknown) => value is AccountingRecentV1; export declare const parseAccountingAggregateTokenCellV1: (value: unknown) => AccountingParseResult; export declare const parseAccountingDayShardV1: (value: unknown) => AccountingParseResult; export declare const parseAccountingLifetimeV1: (value: unknown) => AccountingParseResult; export declare const parseAccountingAttemptPacketV1: (value: unknown) => AccountingParseResult; export declare const parseAccountingRequestPacketV1: (value: unknown) => AccountingParseResult; export declare const parseAccountingRecentV1: (value: unknown) => AccountingParseResult; /** Checked addition for counters. null means the exact safe-integer domain overflowed. */ export declare function checkedAddAccountingCounter(left: number, right: number): number | null; /** * Sum two aggregate SPEND cells: integer micro-USD amounts, contributor counts, * latest observation. Amounts stay null once any side is uncertain (overflow), * mirroring how token cells degrade — a lost sum is never silently re-guessed. */ export declare function mergeAccountingSpendCells(left: AccountingAggregateSpendCellV1, right: AccountingAggregateSpendCellV1): AccountingAggregateSpendCellV1 | null; export declare function emptyAccountingSpendCell(): AccountingAggregateSpendCellV1; export declare function emptyAccountingAggregateSpend(): AccountingAggregateSpendV1; export declare function mergeAccountingTokenCells(left: AccountingAggregateTokenCellV1, right: AccountingAggregateTokenCellV1): AccountingAggregateTokenCellV1 | null; export declare function mergeAccountingEstimatedTokenCells(left: AccountingEstimatedTokenCellV1, right: AccountingEstimatedTokenCellV1): AccountingEstimatedTokenCellV1 | null; export declare function mergeAccountingMetricCells(left: AccountingMetricCellV1, right: AccountingMetricCellV1): AccountingMetricCellV1 | null; export {};