/** * Cost reports: per-instance, all-instances, by-template, unattributed. * * Reads ledgers only — never re-parses platform records (FR7.4). Applies * read-time fidelity precedence, then prices weighted usage against the * effective rate table. Every dollar-bearing report names its snapshot. * * Design: design.md §4.5 */ import type { CostConfig, CostFidelity, CostEntry } from './types.js'; export interface PhaseCost { phase: string; microUsd: number | null; unpricedModels: string[]; tokens: number; credits: number; elapsedSeconds: number; /** * Seconds of measured *active* work, or null when nothing in this phase carried * a span (turn-scoped-cost/AC-21). `activePartial` marks a total measured from * only some of the phase's entries — a floor, not a measurement. * * Reported **alongside** `elapsedSeconds`, never instead of it. Both are true and * they answer different questions: elapsed is how long the phase took, active is * how much of that was the agent working. A phase that waited a day for a human * genuinely took a day — `aidlc metrics` reads elapsed for exactly that reason — * while its cost was incurred in minutes. */ activeSeconds: number | null; activePartial: boolean; /** Where this phase's money went — see CostDrivers. */ drivers: CostDrivers; } /** An instance's tokens by counter; they sum to `tokens` (cost-in-tokens/AC-2). */ export interface TokenSplit { input: number; output: number; cacheRead: number; cacheWrite: number; } export interface InstanceCost { instance: string; template: string | null; microUsd: number | null; unpricedModels: string[]; tokens: number; tokenSplit: TokenSplit; credits: number; elapsedSeconds: number; /** Summed active seconds across phases, or null when nothing was measured. */ activeSeconds: number | null; /** True when only some priced entries carried a span — the total is a floor. */ activePartial: boolean; /** Where this instance's money went — see CostDrivers. */ drivers: CostDrivers; fidelityMix: Record; phases: PhaseCost[]; snapshot: string; /** * Why this instance has no cost figure, when the reason is that two platforms * worked it. * * Set here rather than in each printer so all five cost readers agree from one * seam. Patching the printers alone would have left `aidlc metrics --json` and * the published blog frontmatter carrying a figure that `aidlc cost` and * `aidlc status` describe as unmeasured (agent-portability/AC-9, AC-11, AC-35). */ costSkipped: { platforms: string[]; } | null; } /** * The three cost *drivers*, or null for each one that was not measured. * * `$578.45` with no breakdown gives a reader nothing to act on; these say where it * went. Every one is null rather than zero when its input is missing, because the * denominator is a response count that pre-existing entries do not carry — and a * fabricated 0 (or an Infinity from dividing by an absent count) would read as a * measurement. */ export interface CostDrivers { /** Share of dollars spent re-reading the prefix, 0–1. Null when nothing is priced. */ cacheReadShare: number | null; /** Resident prefix per API response, in tokens. Null when responses are uncounted. */ avgContextTokens: number | null; /** Micro-USD per API response. Null when responses are uncounted or nothing is priced. */ microUsdPerResponse: number | null; /** Unique API responses, or null when no entry carried a count. */ responses: number | null; /** True when only some priced entries carried a count — the total is a floor. */ responsesPartial: boolean; } /** * Drivers for a row that has no ledger data at all — a phase with elapsed time and * no records. Every figure null, because none was measured. */ export declare const NO_DRIVERS: CostDrivers; /** Compute the full cost view of one instance. */ export declare function instanceCost(projectRoot: string, instance: string, config: CostConfig | null): InstanceCost; /** All instances with state directories. */ export declare function listInstances(projectRoot: string): string[]; export interface TemplateRollup { template: string; /** Instances in this group. */ count: number; /** * Instances in this group that have a cost figure. * * Reported beside the average so a group is never presented as complete when it * is not. `measuredCount < count` means the average describes a subset, which is * the honest reading — and `avgMicroUsd` is `null` when nothing is measured * rather than a zero that reads as free. */ measuredCount: number; avgMicroUsd: number | null; /** * Mean tokens over the members that used any, or null when none did * (cost-in-tokens/AC-4). Its own denominator: a member whose usage no rate prices * still has tokens, so it counts here and not in `avgMicroUsd`. */ avgTokens: number | null; avgElapsedSeconds: number; } export declare function byTemplate(projectRoot: string, config: CostConfig | null): TemplateRollup[]; /** Unattributed ledger entries (FR7.2 --unattributed). */ export declare function unattributedEntries(projectRoot: string): CostEntry[]; /** * The unattributed pool, priced. On this repo that pool was ~44% of total spend * while every dollar-bearing report ignored it — `--unattributed` printed a bare * entry count. A pool nobody prices is a pool nobody drains * (cost-driver-integrity/AC-8). */ export interface UnattributedSummary { entries: number; /** * Weighted by the same read-time precedence rules as instance ledgers. * * One caveat specific to this file: `applyPrecedence` groups by `session_id`, * and an unattributed entry's `session_id` is often a provenance stamp naming * one arbitrary claimant rather than the session that did the work. So grouping * merges some unrelated sessions and suppresses slightly more than it should — * under-pricing, which is the safe direction, measured at 0.35% of dollars on * this repo's pool. */ microUsd: number | null; unpricedModels: string[]; tokens: number; /** Weighted kiro credits, for a pool no rate table can price in dollars. */ credits: number; /** * Entry counts per fidelity. Counts EVERY entry including unit-less markers * (which are always `unknown` fidelity), so the breakdown sums to `entries` * rather than silently falling short of the headline count. */ fidelity: Record; /** Raw token totals per model (unweighted; labelled raw where printed). */ modelTokens: Record; /** Raw kiro credits per model, kept apart so credits are never printed as tokens. */ modelCredits: Record; } /** Null for an empty or absent pool — silence, never `$0.00` (AC-10). */ export declare function unattributedSummary(projectRoot: string, config: CostConfig | null): UnattributedSummary | null; /** Spend per day for the operator dashboard's SPEND panel (operator-console/AC-18). */ export interface DailySpend { /** Seven local days, oldest first, ending today; null where nothing priced was recorded. */ days: (number | null)[]; todayUsd: number | null; /** Null when no day of the seven was measured — never `0` for "no data". */ weekUsd: number | null; } /** * The project's priced spend for each of the last seven days, from every instance * ledger and the unattributed pool, weighted by the same read-time precedence * `aidlc cost` uses. An entry counts on the day it was appended. Unpriced entries * are left out rather than counted as zero. */ export declare function dailySpend(projectRoot: string, config: CostConfig | null, now?: Date): DailySpend; //# sourceMappingURL=report.d.ts.map