/** * Friction detection over journal entries. * * Two cluster types, because the two halves of "DX" fail differently: * * - `error` — the caller fought the tool and it pushed back. This is the * classic retry loop (guessed a flag, got an error, tried again). * - `repetition` — the caller ran the same thing repeatedly and it WORKED * every time. No error is ever raised, so an error-keyed detector is blind * to it, yet it is friction: the caller didn't know the first run had * already given them what they needed. The reported case that motivated * this file was exactly that shape — repeated `preview` runs, each one * succeeding, each one minting a fresh link. * * Detection is deliberately loose. A false positive costs a line in a report a * human is already reading; a miss costs a DX gap nobody ever hears about. */ import type { JournalEntry } from "./journal.js"; export type ClusterKind = "error" | "repetition"; export interface Cluster { kind: ClusterKind; skeleton: string; entries: JournalEntry[]; /** Wall time from the first to the last call in the run, in ms. */ spanMs: number; errors: number; /** True when the run ended on a success — the caller got there eventually. */ recovered: boolean; } /** * Group consecutive same-skeleton entries and keep the runs that look like * friction. Entries are expected in chronological order. */ export declare function findClusters(entries: JournalEntry[]): Cluster[]; /** * Rank by cost × recurrence: a cluster's cost is the calls it wasted, and a * skeleton seen across several clusters is a recurring gap rather than a bad * afternoon. Error clusters outrank repetition ones at equal weight — the * caller was actively blocked rather than merely inefficient. */ export declare function rankClusters(clusters: Cluster[]): Cluster[];