/** * Core telemetry + step-decision machinery for the stacked compression pipeline, extracted * from `strategySelector.ts` so that god-file stays bounded. This module is a leaf: it depends * only on the shared compression types, so it never participates in a cycle. * * It holds the per-run accumulator (`StackAccumulator` + `createStackAccumulator`), the TV1 * bail-out config + advance decision (`BailoutConfig` + `decideStep`), and the per-step * telemetry fold (`mergeStackStep`). The sync/async stacked loops in `strategySelector.ts` * consume these. */ import type { CompressionResult, CompressionStats } from "./types.ts"; /** * TV1 — Opt-in bail-out configuration for the stacked pipeline. * When enabled: a step that throws is silently skipped (verbatim kept); a step whose gain is * below `minGainPercent` is also skipped. DEFAULT = disabled (byte-identical to pre-TV1). */ export interface BailoutConfig { enabled: boolean; /** Minimum savings percent required to advance currentBody. Default: 10. */ minGainPercent?: number; } /** Accumulates per-step telemetry across a stacked run (shared sync/async). */ export interface StackAccumulator { techniques: Set; rules: Set; breakdown: NonNullable; rtkRawOutputPointers: NonNullable; validationWarnings: Set; validationErrors: Set; fallbackApplied: boolean; } export function createStackAccumulator(): StackAccumulator { return { techniques: new Set(), rules: new Set(), breakdown: [], rtkRawOutputPointers: [], validationWarnings: new Set(), validationErrors: new Set(), fallbackApplied: false, }; } /** * TV1 — Pure helper that decides whether a completed step should advance `currentBody`. Called * only when bail-out is ENABLED; the loops bypass it on the default-off path (zero cost). Returns * `{ advance: true }` to accept the step, or `{ advance: false }` to skip it (verbatim kept). */ export function decideStep( result: CompressionResult, bailout: BailoutConfig ): { advance: boolean } { if (!result.compressed) return { advance: false }; // Clamp: a negative minGainPercent would mean "always advance" (invalid state). const minGain = Math.max(0, bailout.minGainPercent ?? 10); const gain = result.stats?.savingsPercent ?? 0; if (gain < minGain) return { advance: false }; return { advance: true }; } /** Folds one engine result into the accumulator (telemetry + breakdown entry). */ export function mergeStackStep( acc: StackAccumulator, engineId: string, result: CompressionResult ): void { if (!result.stats) return; result.stats.techniquesUsed.forEach((technique) => acc.techniques.add(technique)); result.stats.rulesApplied?.forEach((rule) => acc.rules.add(rule)); result.stats.rtkRawOutputPointers?.forEach((pointer) => acc.rtkRawOutputPointers.push(pointer)); result.stats.validationWarnings?.forEach((warning) => acc.validationWarnings.add(warning)); result.stats.validationErrors?.forEach((error) => acc.validationErrors.add(error)); acc.fallbackApplied = acc.fallbackApplied || result.stats.fallbackApplied === true; acc.breakdown.push({ engine: engineId, originalTokens: result.stats.originalTokens, compressedTokens: result.stats.compressedTokens, savingsPercent: result.stats.savingsPercent, techniquesUsed: result.stats.techniquesUsed, ...(result.stats.rulesApplied ? { rulesApplied: result.stats.rulesApplied } : {}), ...(result.stats.durationMs !== undefined ? { durationMs: result.stats.durationMs } : {}), }); }