/**
 * Structural validator for per-action LLM output (DR3 of the L3 proposal).
 *
 * The L2 convention matcher produces deterministic TypeScript snippets
 * for spec steps it can match. Those pre-baked snippets are passed to the
 * LLM as scaffolding (DR3-A). The LLM emits a coherent method body that
 * weaves the pre-baked snippets together with [WRITE]-step code it
 * authors itself.
 *
 * The structural validator is the trust-but-verify counterpart to that
 * pattern: after the LLM emits, we diff the output against the pre-baked
 * snippets. Every pre-baked snippet must appear in the LLM's body
 * verbatim (modulo whitespace + trailing punctuation). If a snippet is
 * missing — i.e. the LLM rewrote a deterministic piece — the realize
 * pipeline fails loudly with a diff showing what was preserved + what
 * was dropped.
 *
 * Why "verbatim modulo whitespace": pre-baked snippets are already
 * idiomatic TS. Letting the LLM reformat them silently undermines
 * "deterministic" — we'd lose reproducibility across runs. But forcing
 * exact byte-for-byte match would fail on innocuous LLM behaviours
 * (re-indenting a single line of pre-baked code to match the surrounding
 * indentation it adopted). We compare on the canonical form: the
 * snippet's "code essence" stripped of leading whitespace and trailing
 * comment-only lines.
 *
 * This validator is orthogonal to the parse-check (esbuild) and the
 * tsc-check (per-action-llm-emit's surgical retry loop). All three
 * gates compose: parse-fail → surgical retry; structural-fail → loud
 * fail (LLM rewrote a deterministic piece); tsc-fail → fall through to
 * γ stub.
 */
/** A single pre-baked snippet to verify is preserved in the LLM output. */
export interface PrebakedSnippet {
    /** Step number (1-indexed) the snippet came from — for error messages. */
    stepNum: number;
    /** Human-readable step text — for error messages. */
    stepText: string;
    /** The pre-baked TypeScript snippet. The matcher's `.call` string. */
    snippet: string;
}
/** Outcome of the structural-preservation check.
 *
 *  `ok: true` with a non-empty `warnings` array means the LLM dropped
 *  SOME pre-baked snippets but stayed at or under the drop-fraction
 *  threshold — the output is accepted (no γ-fallback) but the dropped
 *  snippets are surfaced so the caller can log them. `ok: false` means
 *  the drop fraction exceeded the threshold: the LLM substantially
 *  ignored the scaffolding and the owner should γ-fall-back. */
export type StructuralValidationResult = {
    ok: true;
    warnings?: MissingSnippet[];
} | {
    ok: false;
    missing: MissingSnippet[];
    reason: string;
};
/** Per-snippet failure detail. */
export interface MissingSnippet {
    stepNum: number;
    stepText: string;
    /** The original pre-baked snippet (canonicalised). */
    expected: string;
    /** The closest match found in the LLM body, or null when no near-match. */
    closestMatch: string | null;
}
/**
 * Default drop-fraction threshold: an owner may drop up to (and
 * including) HALF of its pre-baked snippets and still be accepted
 * (with the drops surfaced as warnings). Above half → γ-fallback.
 *
 * Rationale (2026-05-14, Phase 5 first target of
 * `2026-05-13-VERIFIER-DIAGNOSTIC-TREATMENT-SPLIT.md`): pre-fix the
 * validator rejected an ENTIRE owner if it dropped a SINGLE snippet.
 * For sonnet this rarely fires; for openai-compatible models (Ollama
 * qwen3-coder:30b, MarrBox) it fired on ~13/36 owners in the idle-meta
 * trial — every paraphrased snippet nuked the whole owner to γ-stub.
 * The post-emit feedback loop then recovered those owners anyway via
 * context-complete reemit (which does NOT run this validator), so the
 * strictness bought an extra LLM round-trip and STILL lost determinism.
 * A threshold keeps the gross-failure guard ("the LLM basically
 * ignored the scaffolding") while letting a minority of paraphrases
 * through — they ride the normal tsc + stub-completeness gates instead.
 *
 * Overridable via `SPECVERSE_REALIZE_STRUCTURAL_DROP_THRESHOLD`.
 */
export declare const DEFAULT_STRUCTURAL_DROP_THRESHOLD = 0.5;
/**
 * Validate that every pre-baked snippet appears in the LLM-emitted body.
 *
 * The check is substring containment on the canonical form (whitespace +
 * leading-comment normalised). For each missing snippet we surface the
 * step number, step text, and the closest near-match found in the body
 * (or `null` if there's no token-overlap candidate).
 *
 * `dropThreshold` is the fraction of countable snippets that may be
 * dropped before the result flips to `ok: false`. At or below the
 * threshold, the result is `ok: true` with the dropped snippets in
 * `warnings`. Above it, `ok: false` with the full `missing` list.
 *
 * Empty `prebakedSnippets` is a vacuous pass — when no convention
 * matched, there's nothing to preserve.
 */
export declare function validateLlmOutputPreservesConventions(llmBody: string, prebakedSnippets: PrebakedSnippet[], dropThreshold?: number): StructuralValidationResult;
//# sourceMappingURL=structural-validator.d.ts.map