//#region src/analysis.d.ts
/**
 * Core Analysis Loop
 *
 * Debugging from first principles: take the events you care about, take a
 * comparable normal population, and ask which recorded field separates them.
 * The loop is mechanical, so run it in code instead of clicking through a
 * dashboard.
 *
 * `compareCohorts()` scores every field/value pair by how much more often it
 * appears in the outlier group than in the baseline. The top result names the
 * cohort behind a regression, which is the hypothesis you then verify against
 * individual traces.
 *
 * The input is any array of flat records: wide events from
 * `getRequestLogger()`, `TestSpan.attributes` from `autotel/testing`, or rows
 * returned by a backend query.
 *
 * @example Find the cohort behind a latency regression
 * ```typescript
 * import { compareCohorts } from 'autotel/analysis'
 *
 * const slow = events.filter((event) => event['duration_ms'] >= 800)
 * const normal = events.filter((event) => event['duration_ms'] < 800)
 *
 * const [top] = compareCohorts({ outlier: slow, baseline: normal })
 * // { field: 'payment.provider', value: 'bank-beta', difference: 0.94, ... }
 * ```
 */
/** A flat telemetry record. Span attributes and wide events both satisfy it. */
type AnalysisEvent = Record<string, unknown>;
/** How strongly one field/value pair separates the outlier group from the baseline. */
interface CohortDifference {
  /** Attribute name, such as `payment.provider`. */
  field: string;
  /** The value, rendered as a string for display and grouping. */
  value: string;
  /** Share of outlier events carrying this value, 0-1. */
  outlierFraction: number;
  /** Share of baseline events carrying this value, 0-1. */
  baselineFraction: number;
  /** `outlierFraction - baselineFraction`. Positive means over-represented in the outliers. */
  difference: number;
  outlierCount: number;
  baselineCount: number;
}
interface CompareCohortsOptions {
  /** The events you are investigating: the errors, the slow requests, the failed checkouts. */
  outlier: readonly AnalysisEvent[];
  /** A comparable normal population from the same time range. */
  baseline: readonly AnalysisEvent[];
  /** Restrict the scan to these fields. Defaults to every field seen in either group. */
  fields?: readonly string[];
  /** Fields to skip, such as identifiers you already know are unique. */
  ignoreFields?: readonly string[];
  /**
   * Skip a field once it holds more distinct values than this across both
   * groups. Default 50.
   */
  maxValuesPerField?: number;
  /**
   * Skip a field whose distinct values outnumber this share of the combined
   * events. A request id or a raw duration takes a near-unique value per
   * event, so its values never repeat and it cannot describe a cohort. The
   * ratio catches those fields in small populations, where an absolute cap
   * does not. Bucket numeric fields at instrumentation time if you want them
   * ranked. Default 0.5.
   */
  maxUniqueRatio?: number;
  /** Drop pairs whose absolute difference falls below this. Default 0.1. */
  minDifference?: number;
  /** Maximum results to return, strongest first. Default 20. */
  limit?: number;
}
/**
 * Rank the field/value pairs that separate an outlier group from a baseline.
 *
 * Returns an empty array when either group is empty, because a fraction over
 * zero events carries no information.
 *
 * @param options - The two populations and the scan limits
 * @returns Differences sorted by absolute strength, strongest first
 */
declare function compareCohorts(options: CompareCohortsOptions): CohortDifference[];
//#endregion
export { AnalysisEvent, CohortDifference, CompareCohortsOptions, compareCohorts };
//# sourceMappingURL=analysis.d.cts.map