Graph pipeline cost metrics: capture naming spend, fold all channels, cost pill + panel

- Cluster namer bills the money channel now: per-step usage + model
  captured via onStep, persisted as NamingRunUsage records to
  data/graph/naming-runs.jsonl (idempotent per startedAt; failed/aborted
  runs persist too — money spent either way). callUsage promoted to
  extraction.ts module scope for reuse.
- core/cost-summary.ts: the pure fold behind the pill — chat runs,
  notes-source runs, and naming runs into stage totals (extraction /
  audit / naming) + newest-first recent runs. Dollars INFERRED read-time
  via prices.ts, never stored; unpriced models excluded-but-counted
  (render '—', never a silent zero); tokens always sum.
- GET /api/graph/costs (src/server graphCosts composition, thin route).
- Graph view: bottom-left cost pill (cumulative dollars headline) +
  expandable breakdown panel (stage rows with tokens secondary, recent
  runs with time/title/merged/cost); fetched on mount, refetched when a
  pipeline run finishes; merged into one bottom-left stack with the
  running-pipeline pills.
- Tests: pure-fold suite, naming capture wiring (full importNotes ->
  naming path), store idempotency + strict reads.
This commit is contained in:
amosblomqvist
2026-09-19 20:55:35 +03:00
parent c32915b232
commit 3e263a18cc
14 changed files with 666 additions and 37 deletions
+3
View File
@@ -115,6 +115,9 @@ export const LEDGER_FILES = {
coverage: path.join(PATHS.graph, "coverage.jsonl"),
/** LLM-named community records (contracts/graph.ts ClusterLabeling). */
clusterLabels: path.join(PATHS.graph, "cluster-labels.jsonl"),
/** Cluster-naming run usage (contracts/graph.ts NamingRunUsage) — the
* money channel's third stage; graph-global, so its own ledger. */
namingRuns: path.join(PATHS.graph, "naming-runs.jsonl"),
} as const;
/**