/** * Per-sample quality diagnostics. * * Why this exists * --------------- * `report-diagnostics.ts` answers "what's wrong with the report overall" — * aggregate-level insights about assertions and variant comparisons. This * module answers a complementary question: "which specific samples in my * eval-samples set are problematic and should be fixed before I trust any * conclusion drawn on this report?" * * Senior-engineer pain point: 100 eval-samples typically have 20-40 that * (a) all variants get the same score on (no discriminative power), or * (b) are near-duplicates of another sample (data redundancy inflating N), or * (c) have ambiguous rubric (judge gives wildly different scores on repeats), or * (d) are cost / latency outliers (one sample spikes the budget by itself), or * (e) fail across the board (likely broken sample, not a model deficiency). * * Persisted on the report so studio can surface these to users iterating * the SAMPLE SET (alongside iterating the SKILL). * * Output shape: a flat list of issues, each tagged with severity and the * minimal evidence needed to act ("here are the matching prompts"). Issues are * sorted by severity then by sample_id so the report is stable across runs. */ import type { Report, Sample } from '../types/index.js'; export type SampleIssueKind = 'flat_scores' | 'all_pass' | 'all_fail' | 'near_duplicate' | 'ambiguous_rubric' | 'cost_outlier' | 'latency_outlier' | 'error_prone' | 'rubric_clarity_low' | 'capability_thin'; export interface SampleIssue { sample_id: string; severity: 'error' | 'warning' | 'info'; issueKind: SampleIssueKind; /** Minimal evidence to make the issue actionable. */ evidence: Record; } export interface SampleDiagnosticReport { /** All issues sorted by (severity desc, sample_id asc). */ issues: SampleIssue[]; /** 0-100 quality score for the sample set as a whole. Lower = more issues. */ healthScore: number; /** Sample IDs grouped by issue kind for quick consumption. */ byKind: Partial>; /** Quick-glance counters. */ totals: { samples: number; flagged: number; errors: number; warnings: number; infos: number; }; } export interface DiagnoseOptions { /** Minimum ROUGE-1 between two prompts to flag near-duplicate. Default 0.7. */ duplicateRouge?: number; /** Judge stddev threshold (across judgeRepeat samples) to flag ambiguous. Default 1.0. */ ambiguousStddev?: number; /** Cost outlier multiplier vs median. Default 3 (≥ 3× median is flagged). */ costOutlierK?: number; /** Latency outlier multiplier vs median. Default 3. */ latencyOutlierK?: number; /** Score-spread threshold below which a sample is "flat". Default 0.5. */ flatThreshold?: number; /** * Original Sample objects, used for near-duplicate detection. When omitted * (Report alone) the duplicate check is skipped — Report doesn't carry * prompts, only score/cost/latency. The CLI handler reads samples via * report.meta.request.samplesPath and passes them in. */ samples?: Sample[]; } export declare function diagnoseSamples(report: Report, options?: DiagnoseOptions): SampleDiagnosticReport; /** case-insensitive + dash/camel/underscore normalize: * `api-selection`, `apiSelection`, `API_Selection` 都归到 `apiselection`。 * 让 capability_thin / capabilityCoverage 不受拼写风格差异影响。 */ export declare function normalizeCapability(raw: string): string; type DiagnosticLang = 'zh' | 'en'; export declare function formatSampleIssue(issue: SampleIssue, lang?: DiagnosticLang): string; /** * Plain-text formatter for sample-quality diagnostics output. */ export declare function formatSampleDiagnostics(diag: SampleDiagnosticReport, options?: { topN?: number; lang?: DiagnosticLang; }): string; export {};