/** * `src/services/observability/repair-cycle-metric.ts` * * WHY THIS MODULE EXISTS — the measured defect that forced the metric to * change. * * The repair-cycle counter that used to live in `aggregation-helpers.ts` * counted every slice-transition event whose `detail.artifactRole === 'qa'`. * That is not a repair-cycle count: it counts QA's OWN internal state * transitions, and it counts every transition TWICE because * `peaks request transition` emits one event without `detail.from` and a * second one with it. Measured over this repo's own recorded history * (10 session dirs, 108 slices, 1102 slice-transition events) the old * counter put 82 of the 108 slices at or over the cap of 3, while exactly * ONE slice ever really reworked — and it reworked FIVE times. * The other 81 alarms were a measurement artifact, not rework. * * So the metric is VERSIONED. Version 1 is the qa-event count — it is kept, * under the name `legacyQaEventCount`, so the old number and the new number * can be read side by side instead of being compared by accident. Version 2 * is the repair-cycle count computed here. * * THE v2 DEFINITION. A repair cycle = the slice's artifact RETURNS to an RD * work state (`draft` | `spec-locked` | `implemented`) after it had entered a * QA phase (`running` | `verdict-issued`). The state vocabulary is the one * `ALLOWED_STATES_PER_ROLE` declares in * `src/services/artifacts/request-artifact-state-helpers.ts`: `qa-handoff` * is an RD state, so the normal closing hops `verdict-issued → qa-handoff` and * `qa-handoff → handed-off` are the happy path, not rework. * * This is NOT the same measurement as * `src/services/artifacts/repair-cycle-service.ts`, which counts the * `QA return-to-rd cycle N` notes inside a request artifact. That one is the * artifact contract's own record; this one is reconstructed from the * observability event stream. The two are reported separately and are never * merged. */ import { type RepairCycleReport } from './aggregation-types.js'; import type { ObservabilityEvent } from './observability-service.js'; /** * Version 1 was never versioned — it silently counted qa-role events. * Version 2 is the repair-cycle count. A consumer that reads * `metricVersion` can therefore tell which convention produced the numbers * printed next to it. */ export declare const REPAIR_CYCLE_METRIC_VERSION = 2; /** What the v2 number counts, in one sentence, for every consumer that prints it. */ export declare const REPAIR_CYCLE_METRIC_DEFINITION: string; /** What the v1 number counts, and why it must never be read as a repair-cycle count. */ export declare const LEGACY_QA_EVENT_COUNT_NOTE: string; /** The three numbers one slice carries. */ export type SliceRepairMetrics = { /** v2: how many times the slice came back to an RD work state after a QA phase. */ repairCycles: number; /** v2: how many QA phases the slice entered. */ qaRounds: number; /** v1: how many qa-role slice-transition events the slice emitted. */ legacyQaEventCount: number; }; /** The three numbers, per slice, over the whole event stream. */ export declare function computeSliceRepairMetrics(events: readonly ObservabilityEvent[]): Map; /** * The repair-cycle report. `capHitCount` is computed from the v2 metric; the * v1 count rides along under its own name so the two conventions can be * compared rather than confused. */ export declare function buildRepairCycleReport(events: readonly ObservabilityEvent[]): RepairCycleReport;