/** * Extraction Quality Benchmarking (O-006) * * Provides an offline corpus-based regression suite for content extraction and table parsing. * Compares actual extraction results against expected results to measure quality. */ import { ContentExtractor } from './content-extractor.js'; import { ConfidenceLevel } from '../types/field-confidence.js'; /** * Expected extraction results for a corpus entry */ export interface ExpectedExtractionResult { /** Expected title text */ title?: string; /** Expected title source (og_title, title_tag, h1, etc.) */ titleSource?: 'og_title' | 'title_tag' | 'h1' | 'unknown'; /** Content expectations */ content?: { /** Expected minimum content length */ minLength?: number; /** Expected maximum content length */ maxLength?: number; /** Phrases that must appear in the content */ mustContain?: string[]; /** Phrases that must NOT appear (navigation, ads, etc.) */ mustNotContain?: string[]; /** Sample text to fuzzy match */ sampleText?: string; }; /** Expected tables */ tables?: ExpectedTable[]; /** Expected confidence levels */ confidence?: { title?: ConfidenceLevel; content?: ConfidenceLevel; overall?: ConfidenceLevel; }; /** Links expectations */ links?: { minCount?: number; mustInclude?: string[]; }; } export interface ExpectedTable { /** Expected headers (partial match OK) */ headers?: string[]; /** Expected row count */ rowCount?: number; /** Expected minimum row count */ minRowCount?: number; /** Sample rows for validation */ sampleRows?: string[][]; /** Expected caption */ caption?: string; /** Expected table ID */ id?: string; } /** * Corpus entry with HTML and expected results */ export interface CorpusEntry { /** Unique ID for the entry */ id: string; /** Name/description of the test case */ name: string; /** HTML content to extract from */ html: string; /** URL to use for extraction context */ url: string; /** Expected extraction results */ expected: ExpectedExtractionResult; /** Tags for categorization */ tags?: string[]; /** Whether this is an edge case */ isEdgeCase?: boolean; } /** * Result of benchmarking a single corpus entry */ export interface BenchmarkResult { /** Corpus entry ID */ id: string; /** Corpus entry name */ name: string; /** Whether all checks passed */ passed: boolean; /** Detailed metrics */ metrics: ExtractionMetrics; /** List of failures */ failures: BenchmarkFailure[]; /** Extraction timing in milliseconds */ durationMs: number; } export interface BenchmarkFailure { /** What was being checked */ check: string; /** Expected value */ expected: unknown; /** Actual value */ actual: unknown; /** Severity: error means hard failure, warning means quality issue */ severity: 'error' | 'warning'; /** Human-readable message */ message: string; } /** * Metrics for extraction quality */ export interface ExtractionMetrics { /** Title metrics */ title: { exactMatch: boolean; fuzzyScore: number; sourceMatch: boolean; confidenceScore: number; confidenceLevel: ConfidenceLevel; }; /** Content metrics */ content: { length: number; lengthInRange: boolean; containsAllRequired: boolean; excludesAllForbidden: boolean; fuzzyMatchScore: number; confidenceScore: number; confidenceLevel: ConfidenceLevel; }; /** Table metrics */ tables: { expectedCount: number; actualCount: number; matchedTables: number; headerAccuracy: number; rowCountAccuracy: number; sampleRowsMatch: boolean; }; /** Link metrics */ links: { count: number; meetsMinimum: boolean; includesRequired: boolean; }; /** Overall score (0-100) */ overallScore: number; } /** * Aggregate results for a full benchmark run */ export interface BenchmarkSummary { /** Total entries processed */ totalEntries: number; /** Number that passed all checks */ passed: number; /** Number with at least one failure */ failed: number; /** Pass rate (0-1) */ passRate: number; /** Average overall score */ averageScore: number; /** Average extraction time in ms */ averageDurationMs: number; /** Per-category results */ byCategory: Record; /** Individual results */ results: BenchmarkResult[]; /** Timestamp */ timestamp: string; } export interface CategorySummary { total: number; passed: number; averageScore: number; } export declare class ExtractionBenchmark { private extractor; private corpus; constructor(extractor?: ContentExtractor); /** * Add a corpus entry for benchmarking */ addEntry(entry: CorpusEntry): void; /** * Add multiple corpus entries */ addEntries(entries: CorpusEntry[]): void; /** * Load corpus from a manifest object */ loadCorpus(entries: CorpusEntry[]): void; /** * Get corpus entry count */ getEntryCount(): number; /** * Get corpus entries (for inspection) */ getEntries(): readonly CorpusEntry[]; /** * Run benchmark on a single entry */ benchmarkEntry(entry: CorpusEntry): Promise; /** * Run benchmark on all corpus entries */ runBenchmark(options?: { tags?: string[]; }): Promise; /** * Calculate metrics comparing actual vs expected results */ private calculateMetrics; /** * Simple fuzzy match score (0-1) */ private fuzzyMatch; /** * Find a table matching expected criteria */ private findMatchingTable; /** * Check if actual confidence level meets or exceeds expected */ private confidenceLevelMatches; /** * Format a benchmark summary as a human-readable report */ formatReport(summary: BenchmarkSummary): string; } /** * Standard corpus entries for common extraction scenarios */ export declare function getStandardCorpus(): CorpusEntry[]; //# sourceMappingURL=extraction-benchmark.d.ts.map