/** * Cost-tracking domain types. * * The ledger records raw usage units (tokens, credits) — never dollars. * Dollars are computed at report time from a rate table (see rates.ts). * * Design: .aidlc/state/cost-tracking/design.md §2 */ /** Token usage for a single model within a coverage window. */ export interface TokenUnits { kind: 'tokens'; model: string; input_tokens: number; output_tokens: number; cache_read_tokens: number; cache_write_tokens: number; } /** Credit usage (Kiro-style metering) within a coverage window. */ export interface CreditUnits { kind: 'credits'; credits: number; model: string | null; } export type CostUnits = TokenUnits | CreditUnits; /** Provenance of a ledger entry's numbers. */ export type CostFidelity = 'metered' | 'reconciled' | 'estimated' | 'unknown'; /** One line in costs.ndjson / unattributed.ndjson. */ export interface CostEntry { /** ISO 8601 UTC append time. */ timestamp: string; session_id: string | null; /** Phase the usage occurred in; null only in unattributed.ndjson. */ phase: string | null; provider: string; fidelity: CostFidelity; /** Usage window this entry covers. */ coverage: { from: string; to: string; }; /** Provider resume point after this entry (e.g. transcript message uuid). */ cursor: string | null; /** null ⇔ fidelity 'unknown' (attribution interval marker). */ units: CostUnits | null; /** * Milliseconds of *active* work this entry covers — the union of the spans of * the records merged into it (turn-scoped-cost/AC-44). * * Distinct from `coverage`, which is a wall-clock envelope and for 8,427 of * 8,440 priced entries is zero-width. Active time answers "how long was the * agent actually producing this?", which is what makes a 49.7h claim window * reporting ~2h of work legible. * * A union rather than a sum because records sharing a parent overlap. Computed * per bucket at capture time and stored, because it cannot be recovered later: * only 67.1% of existing cursors still resolve to an on-disk transcript. * * Optional and nullable — absent on every entry predating this field, and null * whenever the provider cannot measure it (kiro always). Never zero-filled. */ active_ms?: number | null; /** * Unique API responses merged into this entry. * * The denominator for every per-response figure the report shows — average * context size, cost per round trip. Stored because it cannot be recovered * afterwards: an entry is a merged bucket, so its token totals say nothing * about how many responses produced them. * * Meaningful only since usage became one segment per `message.id`. Before that * a "record" was a transcript *line*, and one response wrote up to seven of * them — so counting pre-fix records would have measured content blocks and * called them responses. * * Optional and nullable, exactly as `active_ms` is: absent on every entry * written before this field existed, and never zero-filled. Absent means "not * counted", which is not the same as "no responses". */ responses?: number | null; } /** One line in sessions.ndjson. */ export interface SessionEvent { event: 'claim' | 'renew' | 'release'; session_id: string; id_source: 'platform' | 'agent'; agent: string; timestamp: string; } /** A resolved session↔instance attribution interval. */ export interface ClaimInterval { session_id: string; id_source: 'platform' | 'agent'; agent: string; from: string; /** Release time, or claim-timeout bound for unreleased claims. */ to: string; /** True when bounded by timeout rather than an explicit release. */ open: boolean; } /** Active-session stash entry (.aidlc/cost/active-sessions/.json). */ export interface ActiveSession { session_id: string; agent: string; cwd: string; transcript_path?: string; started_at: string; } /** A usage segment extracted by a provider, pre-attribution. */ export interface UsageSegment { /** ISO 8601 timestamp of the usage event. */ at: string; units: CostUnits; /** Provider resume point after this segment. */ cursor: string; /** * The interval this record was actually being produced over — its parent * record's timestamp to its own. * * **Endpoints, not a duration**, because active time is a *union* of intervals * and a union cannot be reconstructed from durations. Records that share a * parent have overlapping spans: summing them over-counts by 10.8% on this * repo's corpus (27.76h summed against a 25.05h true union). * * `null` when the provider cannot determine it — the kiro provider always, and * claude-code for a record whose parent chain is broken. A missing span never * reads as zero. */ span?: { from: string; to: string; } | null; /** * API responses this segment represents, set only by a provider that knows its * segment-to-response mapping — claude-code groups by `message.id`, so every * segment it emits is exactly 1. Absent means unknown, never zero: a provider * whose records are not response-shaped (kiro) must not fabricate a count * (cost-driver-integrity/AC-6). */ responses?: number; } /** Validated pointer to a provider's usage records. */ export interface SourceRef { provider: string; path: string; } /** * Why a provider could not hand back a source. * * The distinction is the point: `source-missing` is the ordinary outcome of a * session that produced no usage records (started and ended without writing a * transcript), while `invalid-input` means the input was malformed or pointed * outside the platform's root (FR3.9). Only the latter is surfaced to the user * — conflating them made routine session churn look like a capture failure. */ export type SourceMissReason = 'invalid-input' | 'source-missing'; /** Outcome of `CostProvider.resolveSource`. */ export type ResolveResult = { ok: true; source: SourceRef; } | { ok: false; reason: SourceMissReason; }; /** * Capture-log codes that describe a benign outcome, never a failure. * * `span-coverage-partial` belongs here: some records legitimately have no * measurable span (a chain root, or a background session whose root carries no * `promptId`), so partial coverage is an observation to record, not a capture * failure to surface. Omitting it made a *successful* pass report an error — * intermittently, because `lastCaptureError` suppresses an error only when it is * strictly older than the `ok` line, and both are written in the same pass and can * share a millisecond. Same millisecond failed, different millisecond passed. */ export declare const BENIGN_CAPTURE_CODES: readonly string[]; /** Input to `aidlc cost record` in hook mode (parsed from stdin). */ export interface RecordInput { session_id: string; transcript_path?: string; cwd?: string; /** * The platform event that fired this hook, when the payload names it * (claude-code always does; kiro's `Stop` does not). * * Read for one purpose: recognizing a session *end*, which is when the stash * entry must be removed. Carrying it in the payload rather than only in the * installed command text is what makes the fix reach installs that have not * re-run `aidlc cost hooks install`. */ hook_event_name?: string; } /** Per-model (or per-unit) pricing entry. */ export interface RateEntry { input_per_mtok?: number; output_per_mtok?: number; cache_read_per_mtok?: number; cache_write_per_mtok?: number; /** For unit-priced providers (e.g. kiro-credit). */ per_unit?: number; } /** A rate table snapshot with provenance. */ export interface RateSnapshot { snapshot_version: string; effective_date: string; rates: Record; } /** Cost section of .aidlc/config.yaml. */ export interface CostConfig { rates_url?: string; rates?: Record; /** * Resident-context budget in tokens, checked by `aidlc cost context`. * * A report, never a gate — see DEFAULT_CONTEXT_BUDGET_TOKENS for the default * and the measurement behind it. */ context_budget_tokens?: number; } /** * Default resident-context budget: 150,000 tokens. * * Chosen from measurement, not for looking reasonable. Average cache-read tokens * per capture interval by phase, over 20,920 attributed records: ideation 80k, * requirements 164k, design 173k, implementation 259k, testing 344k, deployment * 395k, maintenance 791k — and `complete` at 76k, which does real work cheaply * only because it runs in its own session. * * 150k sits above every phase's average except testing, deployment and * maintenance, so it constrains exactly the three the evidence indicts. Capping * here simulated at a 31% saving on the same token volume, against 19% at 250k * and 39% at a more disruptive 100k. */ export declare const DEFAULT_CONTEXT_BUDGET_TOKENS = 150000; /** Session-id format shared by validation and path construction (FR3.9). */ export declare const SESSION_ID_RE: RegExp; /** Model-id format allowed in ledger entries. */ export declare const MODEL_ID_RE: RegExp; //# sourceMappingURL=types.d.ts.map