/**
 * Per-lesson compile cache (Proposal 281 — Per-Lesson Hash Stability).
 *
 * Short-circuits `totem lesson compile` for lessons whose source content is
 * unchanged across compile runs. Eliminates the per-lesson hash rotation on
 * unrelated lessons when a single lesson is added or modified.
 *
 * Cache key is layered (not composite):
 *   1. `stableId` (when present — reserved for P280; P281 never writes it)
 *   2. `sourceHash` — sha256 of normalized lesson source content
 *   3. `fingerprint` — compile_worker_fingerprint from Proposal 278; mismatch
 *      invalidates the entry (e.g., model bump rotates every entry once)
 *
 * `cli_version` is intentionally NOT part of the cache key — including it
 * would invalidate every cohort bump, defeating the purpose. Per the impl
 * contract § Cache key composition.
 *
 * Storage: `.totem/cache/compile-lesson/<sourceHash-first-16-chars>.json`,
 * one entry per file, flat directory for v1 (see follow-on for fan-out
 * cutover at ~1000 lessons).
 *
 * Emergency escape: set `TOTEM_DISABLE_COMPILE_CACHE=1` to bypass the
 * cache entirely (lookup always returns null; write becomes a no-op).
 * Emergency only — not a long-term flag.
 */
import { z } from 'zod';
import type { CompileLessonResult } from './compile-lesson.js';
/**
 * Cache entry for one lesson's compile output.
 *
 * `stableId` is reserved for P280 (Wind-Tunnel Decoupling). P281 does not
 * populate or query it. Reserving the slot from day one avoids a full cache
 * re-key event when P280 lands; with the reservation, P280's integration is
 * an additive lookup extension, not a refactor. Per
 * `mmnto-ai/totem-strategy#387` § Dependencies (load-bearing).
 */
export declare const CacheEntrySchema: z.ZodObject<{
    sourceHash: z.ZodString;
    stableId: z.ZodOptional<z.ZodString>;
    fingerprint: z.ZodString;
    output: z.ZodDiscriminatedUnion<"status", [z.ZodObject<{
        status: z.ZodLiteral<"compiled">;
        rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
        status: z.ZodLiteral<"compiled">;
        rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
        status: z.ZodLiteral<"compiled">;
        rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, z.ZodTypeAny, "passthrough">>, z.ZodObject<{
        status: z.ZodLiteral<"skipped">;
        hash: z.ZodString;
        reasonCode: z.ZodString;
    }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
        status: z.ZodLiteral<"skipped">;
        hash: z.ZodString;
        reasonCode: z.ZodString;
    }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
        status: z.ZodLiteral<"skipped">;
        hash: z.ZodString;
        reasonCode: z.ZodString;
    }, z.ZodTypeAny, "passthrough">>, z.ZodObject<{
        status: z.ZodLiteral<"failed">;
    }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
        status: z.ZodLiteral<"failed">;
    }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
        status: z.ZodLiteral<"failed">;
    }, z.ZodTypeAny, "passthrough">>, z.ZodObject<{
        status: z.ZodLiteral<"noop">;
    }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
        status: z.ZodLiteral<"noop">;
    }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
        status: z.ZodLiteral<"noop">;
    }, z.ZodTypeAny, "passthrough">>]>;
    compiledAt: z.ZodString;
}, "strip", z.ZodTypeAny, {
    compiledAt: string;
    output: z.objectOutputType<{
        status: z.ZodLiteral<"compiled">;
        rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, z.ZodTypeAny, "passthrough"> | z.objectOutputType<{
        status: z.ZodLiteral<"skipped">;
        hash: z.ZodString;
        reasonCode: z.ZodString;
    }, z.ZodTypeAny, "passthrough"> | z.objectOutputType<{
        status: z.ZodLiteral<"failed">;
    }, z.ZodTypeAny, "passthrough"> | z.objectOutputType<{
        status: z.ZodLiteral<"noop">;
    }, z.ZodTypeAny, "passthrough">;
    sourceHash: string;
    fingerprint: string;
    stableId?: string | undefined;
}, {
    compiledAt: string;
    output: z.objectInputType<{
        status: z.ZodLiteral<"compiled">;
        rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
    }, z.ZodTypeAny, "passthrough"> | z.objectInputType<{
        status: z.ZodLiteral<"skipped">;
        hash: z.ZodString;
        reasonCode: z.ZodString;
    }, z.ZodTypeAny, "passthrough"> | z.objectInputType<{
        status: z.ZodLiteral<"failed">;
    }, z.ZodTypeAny, "passthrough"> | z.objectInputType<{
        status: z.ZodLiteral<"noop">;
    }, z.ZodTypeAny, "passthrough">;
    sourceHash: string;
    fingerprint: string;
    stableId?: string | undefined;
}>;
export type CacheEntry = Omit<z.infer<typeof CacheEntrySchema>, 'output'> & {
    output: CompileLessonResult;
};
/**
 * Discrete cache decisions, emitted per lesson per compile run as
 * telemetry. Maps to the `compile_cache_decision` ledger event's
 * `activity_name` field.
 */
export type CacheDecision = 'cache_hit' | 'cache_miss_source_changed' | 'cache_miss_fingerprint_changed' | 'cache_miss_force' | 'cache_miss_no_prior_record';
/**
 * Compute the cache key for a lesson source. SHA-256 of the content with
 * line endings normalized to `\n` — same normalization as
 * `generateInputHash` in compile-manifest.ts so both surfaces produce
 * identical hashes for identical inputs.
 */
export declare function computeLessonSourceHash(lessonSource: string): string;
/**
 * Compose the hashable lesson source from a parsed lesson's heading and body.
 * Use this from any call site that has a parsed `LessonInput`-shaped object to
 * ensure runtime and migration paths produce identical hashes for the same
 * lesson. Without a shared composition helper, the runtime hash (computed from
 * `lesson.heading` + `lesson.body`) and a migration hash (computed from raw
 * file content with `## Lesson — ` framing) would diverge — exactly the bug
 * GCA R2 surfaced on `#1983`.
 */
export declare function composeLessonSourceForHash(heading: string, body: string): string;
/**
 * Resolve the on-disk cache file path for a given source hash. Pure;
 * does not check existence. Callers handle missing files.
 */
export declare function cacheEntryPath(totemDir: string, sourceHash: string): string;
interface LookupResult {
    entry: CacheEntry | null;
    decision: CacheDecision;
}
/**
 * Look up a cache entry by `(sourceHash, fingerprint)`. Returns the entry
 * with `decision: 'cache_hit'` on a clean hit, or `null` with a
 * decision discriminating the miss reason.
 *
 * `stableId` parameter is reserved for P280 wiring — when present, the
 * lookup tries the stable-id-indexed entry first, falling back to
 * `sourceHash` on miss. v1 (this PR) never receives a non-undefined
 * value here.
 */
export declare function lookupCacheEntry(totemDir: string, sourceHash: string, fingerprint: string, options?: {
    force?: boolean;
    stableId?: string;
}): LookupResult;
/**
 * Persist a cache entry after a successful compile. Idempotent — writing
 * the same `(sourceHash, fingerprint, output)` twice is a no-op-shaped
 * overwrite. Fire-and-forget: I/O failures are surfaced via `onWarn` and
 * never propagate (a failed cache write should not crash a compile).
 *
 * Returns `true` when the entry was successfully persisted, `false` on any
 * I/O failure or when the cache is disabled via env var. Callers that need
 * to track migration outcomes (e.g., `migrateFromCompiledRules`) inspect
 * the return; callers that don't care can ignore it.
 */
export declare function writeCacheEntry(totemDir: string, entry: CacheEntry, onWarn?: (msg: string) => void): boolean;
/**
 * Construct a `CacheEntry` from the inputs of a fresh compile. Pure;
 * callers persist via `writeCacheEntry`.
 */
export declare function buildCacheEntry(sourceHash: string, fingerprint: string, output: CompileLessonResult): CacheEntry;
interface MigrationSeedInput {
    /** Canonical lesson hash (rotation-prone). Carried for diagnostics only. */
    lessonHash: string;
    /**
     * Parsed lesson heading — the `## Lesson — …` heading-text minus the
     * leading `##` markdown. MUST match what `readAllLessons` (or equivalent
     * parser) provides at runtime to the compile path. Composed with `body`
     * via `composeLessonSourceForHash` to produce the same sourceHash the
     * runtime cache lookup will compute.
     */
    heading: string;
    /**
     * Parsed lesson body — the content between the heading and the next
     * lesson heading. MUST match what `readAllLessons` provides at runtime.
     */
    body: string;
    /** The compile output to seed into the cache. */
    output: CompileLessonResult;
}
interface MigrationResult {
    seeded: number;
    skipped: number;
}
/**
 * One-shot seed migration: walk an existing compiled-rules.json + lesson
 * sources, materialize the cache entries that would have been produced
 * if the cache had existed from day one. After this step, the first
 * post-migration compile run produces 100% cache hits and `compiled-
 * rules.json` byte-for-byte matches its prior state.
 *
 * Idempotent — running twice with the same inputs writes the same entries
 * a second time (overwrite). Per the impl contract § Migration sequence.
 *
 * Heading + body are taken separately (rather than a single raw-source
 * string) to enforce the canonical `composeLessonSourceForHash` call shape.
 * If migration accepted a free-form `lessonSource` string, the migration
 * and runtime hash paths could diverge (per GCA R2 critical on `#1983`).
 */
export declare function migrateFromCompiledRules(totemDir: string, fingerprint: string, inputs: MigrationSeedInput[], onWarn?: (msg: string) => void): MigrationResult;
/**
 * List all cache-entry filenames currently on disk. Returns the file basenames
 * (not full paths). Useful for `totem cache --prune-orphans` (out of scope for
 * v1) and for test isolation cleanup.
 */
export declare function listCacheEntries(totemDir: string): string[];
export {};
//# sourceMappingURL=compile-cache.d.ts.map