import { LayoutStoryKind, LayoutStoryLocator } from '../../../contracts/src/index.js'; /** * Which editor coordinate model the host is painting under. The host owns this * choice; the painter never infers editor semantics from the presence of a * number. * * - `legacy-pm`: v1 input — every text-bearing run requires a document-global * `pmStart`/`pmEnd` span. * - `editor-neutral-story`: v2 — body runs still carry compatibility PM spans * during migration, but named stories (headers/footers/notes/textboxes) are * addressed by story identity, not a body PM offset. */ export type PaintCoordinateModel = 'legacy-pm' | 'editor-neutral-story'; /** The coordinate obligation a single run must satisfy, once classified. */ export type RunCoordinateRequirement = 'legacy-pm-required' | 'story-identity-required' | 'visual-only' | 'not-addressable'; /** Console verbosity. `off` is production and the performance `--quiet` mode. */ export type PositionValidationConsolePolicy = 'off' | 'summary' | 'verbose'; /** Which painter produced the observation (kept isolated per painter instance). */ export type PaintKind = 'persistent-page' | 'persistent-page-oracle' | 'semantic'; /** Execution realm, for cross-realm report comparison. */ export type PaintRealm = 'node-headless' | 'browser-inline' | 'browser-worker' | 'product'; export type PositionValidationSection = 'body' | 'header' | 'footer'; export type PositionRunKind = 'text' | 'image' | 'field' | 'math'; /** Structural issue codes. None carry content. */ export type PositionValidationCode = 'missing-start' | 'missing-end' | 'missing-both' | 'invalid-range' | 'identity-missing' | 'story-section-mismatch' | 'unexpected-story'; /** * The content-free structural tuple that keys aggregation and is echoed in * `unexpectedKeys`. Every field is a small enum or boolean — never an id or * text. */ export interface PositionValidationStructuralKey { coordinateModel: PaintCoordinateModel; requirement: RunCoordinateRequirement; storyKind: LayoutStoryKind; storyNamed: boolean; section: PositionValidationSection; runKind: PositionRunKind; code?: PositionValidationCode; } export interface PositionValidationGroupRow extends PositionValidationStructuralKey { checked: number; valid: number; issues: number; } export interface PositionValidationRequirementTally { checked: number; valid: number; issues: number; } /** * Bounded, content-free snapshot of one painter's validation coverage since the * last consume. Safe to serialize into a performance report. */ export interface PositionValidationSummary { enabled: boolean; coordinateModel: PaintCoordinateModel; paintKind: PaintKind; realm: PaintRealm; /** Total runs observed. */ checked: number; /** Runs that met their requirement. */ valid: number; /** Runs that failed their requirement (checked - valid). */ issues: number; issuesByCode: Record; byRequirement: Record; /** Distinct verbose lines withheld after the verbose cap was reached. */ suppressedConsole: number; /** Distinct structural groups seen (<= MAX_GROUPS retained). */ groupCount: number; /** Run observations not retained after MAX_GROUPS distinct keys (still counted in totals). */ groupsOverflowed: number; /** Aggregate rows, capped at MAX_GROUPS, most-issues first. */ groups: PositionValidationGroupRow[]; /** First unexpected (issue-bearing) structural keys, capped and content-free. */ unexpectedKeys: PositionValidationStructuralKey[]; } /** A single run's content-free observation, handed to the collector. */ export interface RunPositionObservation { runKind: PositionRunKind; section: PositionValidationSection; story?: LayoutStoryLocator; pmStart?: number | null; pmEnd?: number | null; /** * True for render-only dynamic display text (PAGE / NUMPAGES / section-page * fields) that mints no editable coordinate. Such runs are `visual-only`. */ renderOnly?: boolean; } export interface PositionValidationOptions { /** Dark by default; the perf harness enables it for its proof. */ enabled?: boolean; /** Host-selected coordinate model. Defaults to the strict `legacy-pm`. */ coordinateModel?: PaintCoordinateModel; /** Console policy. Defaults to `off` (counters only). */ policy?: PositionValidationConsolePolicy; /** Which painter this is; keeps oracle and product coverage separable. */ paintKind?: PaintKind; /** Execution realm for report comparison. */ realm?: PaintRealm; } /** * Derive the story kind used for classification and reporting. The story * locator, when present, is authoritative; otherwise we fall back to the paint * section. Never defaults an absent-yet-non-body story to `body`. */ export declare const resolveStoryKind: (section: PositionValidationSection, story: LayoutStoryLocator | undefined) => LayoutStoryKind; /** * Pure classification: which coordinate obligation does this run carry? * Exported for unit testing. */ export declare const classifyRequirement: (coordinateModel: PaintCoordinateModel, storyKind: LayoutStoryKind, renderOnly: boolean) => RunCoordinateRequirement; /** * Painter-scoped collector. One instance per `DomPainter`. Bounded memory: * counters are O(1), the group map is capped at MAX_GROUPS, and no per-run * event array is ever retained. */ export declare class PositionValidationCollector { private readonly enabled; private readonly coordinateModel; private readonly policy; private readonly paintKind; private readonly realm; private groups; private groupsOverflowed; private checked; private valid; private issues; private issuesByCode; private byRequirement; private unexpectedKeys; private unexpectedKeysSeen; private verboseKeysSeen; private verboseLines; private suppressedConsole; constructor(options?: PositionValidationOptions); get isEnabled(): boolean; record(obs: RunPositionObservation): void; /** Verbose-mode: one content-free warning per NEW structural key, capped. */ private emitVerbose; /** Drain and reset. The documented pass boundary. */ consume(): PositionValidationSummary; /** Read without draining (for assertions / mid-run inspection). */ peek(): PositionValidationSummary; private buildSummary; private reset; } export declare const createPositionValidationCollector: (options?: PositionValidationOptions) => PositionValidationCollector;