import { z } from 'zod';
/** The spine subdirectory + filename the authoring-ledger lives at, under `.totem/`. */
export declare const AUTHORING_LEDGER_DIR = "spine";
export declare const AUTHORING_LEDGER_FILE = "authoring-ledger.ndjson";
/**
 * ADR-112 §8 — one authoring-ledger row. `.strict()` so a malformed/extra-field
 * row fails the read loudly (the attestation chain must not silently degrade).
 */
export declare const AuthoringLedgerEntrySchema: z.ZodObject<{
    ruleId: z.ZodEffects<z.ZodString, string, string>;
    author: z.ZodEffects<z.ZodString, string, string>;
    /** Identity component — `ruleId` is seeded from `sha256(author·targetDefect)`; recorded so the upsert index can resolve a re-read to its persisted id. */
    targetDefect: z.ZodEffects<z.ZodString, string, string>;
    authoredAt: z.ZodEffects<z.ZodString, string, string>;
    declaredEngine: z.ZodEnum<["regex", "ast", "ast-grep"]>;
    splitRef: z.ZodEffects<z.ZodString, string, string>;
    authoredAfterSplit: z.ZodLiteral<true>;
    heldOutNonInspectionAttestation: z.ZodLiteral<true>;
    structuralEligibility: z.ZodObject<{
        decidable: z.ZodBoolean;
        basis: z.ZodEffects<z.ZodString, string, string>;
        judgedBy: z.ZodEffects<z.ZodString, string, string>;
    }, "strip", z.ZodTypeAny, {
        decidable: boolean;
        basis: string;
        judgedBy: string;
    }, {
        decidable: boolean;
        basis: string;
        judgedBy: string;
    }>;
    origin: z.ZodUnion<[z.ZodObject<{
        kind: z.ZodLiteral<"from-scratch">;
    }, "strip", z.ZodTypeAny, {
        kind: "from-scratch";
    }, {
        kind: "from-scratch";
    }>, z.ZodObject<{
        kind: z.ZodLiteral<"mined-accelerant">;
        sourceRunId: z.ZodEffects<z.ZodString, string, string>;
        suggestionHash: z.ZodEffects<z.ZodString, string, string>;
    }, "strip", z.ZodTypeAny, {
        kind: "mined-accelerant";
        sourceRunId: string;
        suggestionHash: string;
    }, {
        kind: "mined-accelerant";
        sourceRunId: string;
        suggestionHash: string;
    }>]>;
    /**
     * The train-side `positiveFixtures` PRs bound by this rule — the §5(2) leakage-guard
     * attestation. Every positive fixture must resolve to the train slice (the matcher was
     * authored against it); the ledger is the CI-observable FM(e) artifact that enumerates
     * them so C can verify train-side membership.
     *
     * The §5(2) attestation is POSITIVES-ONLY (strategy#770 + the Q-C ruling): a §6 negative
     * control is a SILENCE-ONLY near-miss with no `pr`. A synthetic `kind:'lesson'` exemplar
     * has no corpus position, so there is nothing to train-side-leak-check — §5(2)'s guard
     * targets *corpus-drawn* fixtures, and only `positiveFixtures` are mandated train-side.
     * Enumerating negative PRs was an impl-extra beyond the contract; the attestation drops it.
     * (A future `kind:'commit'` near-miss DOES have a corpus position; its train-side
     * `commitSha` attestation returns WITH the deferred commit-source fallback — parallel to
     * the commit-pair preimage deferral.)
     */
    positiveFixturePrs: z.ZodArray<z.ZodNumber, "many">;
    /**
     * LEGACY READ-COMPAT ONLY (pre-#770) — NOT an attestation. `totem rule author` ≤1.81.1
     * wrote `negativeFixturePrs: []` on every row, and `runRuleAuthor` re-reads the FULL
     * existing ledger before writing, so this `.strict()` reader must still PARSE those rows
     * rather than throw on upgrade (greptile-P1 / CR). It is NEVER written by the current
     * intake (the attestation is positives-only, above), so the ledger self-heals to the new
     * shape on the next revision write. Optional + tolerated, never read for leakage-checking.
     */
    negativeFixturePrs: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
    /**
     * ADR-112 §5.1/§8 R1 — the frozen split's `freezeCommitment`
     * (`sha256(splitRef · frozenAt · corpusIntegrity)`), chained from the frozen
     * artifact into every entry authored under it (the (b) tamper-evidence leg:
     * a re-freeze changes the commitment, the commitment is INSIDE the
     * `authoringContentHash` material, so every downstream entry reads
     * would-revise — orphaned loudly, never silently current). Optional: rows
     * authored before R1 (or under a legacy free-text splitRef) omit it; the R1
     * materialize path fail-louds when a frozen-artifact run meets an
     * uncommitted entry.
     */
    freezeCommitment: z.ZodOptional<z.ZodString>;
    /**
     * Fingerprint of the MATERIAL author input (engine / class / matcher /
     * fixtures / origin) — identity (`author`/`targetDefect`/`ruleId`) AND
     * `authoredAt` EXCLUDED, so a pure timestamp refresh is a no-op (§8: a
     * timestamp drift must not churn the rule) while a matcher/fixture edit
     * appends a new revision row under the SAME `ruleId`. Equal hash on re-read ⇒
     * no append.
     */
    contentHash: z.ZodEffects<z.ZodString, string, string>;
}, "strict", z.ZodTypeAny, {
    contentHash: string;
    author: string;
    authoredAt: string;
    targetDefect: string;
    ruleId: string;
    origin: {
        kind: "from-scratch";
    } | {
        kind: "mined-accelerant";
        sourceRunId: string;
        suggestionHash: string;
    };
    structuralEligibility: {
        decidable: boolean;
        basis: string;
        judgedBy: string;
    };
    declaredEngine: "regex" | "ast" | "ast-grep";
    splitRef: string;
    authoredAfterSplit: true;
    heldOutNonInspectionAttestation: true;
    positiveFixturePrs: number[];
    freezeCommitment?: string | undefined;
    negativeFixturePrs?: number[] | undefined;
}, {
    contentHash: string;
    author: string;
    authoredAt: string;
    targetDefect: string;
    ruleId: string;
    origin: {
        kind: "from-scratch";
    } | {
        kind: "mined-accelerant";
        sourceRunId: string;
        suggestionHash: string;
    };
    structuralEligibility: {
        decidable: boolean;
        basis: string;
        judgedBy: string;
    };
    declaredEngine: "regex" | "ast" | "ast-grep";
    splitRef: string;
    authoredAfterSplit: true;
    heldOutNonInspectionAttestation: true;
    positiveFixturePrs: number[];
    freezeCommitment?: string | undefined;
    negativeFixturePrs?: number[] | undefined;
}>;
export type AuthoringLedgerEntry = z.infer<typeof AuthoringLedgerEntrySchema>;
/**
 * Deterministic fingerprint of the MATERIAL author fields (§8 idempotency).
 * SELF-normalizes newlines (CRLF→LF) on every string it hashes, so a Windows-
 * authored and an LF-authored identical rule hash identically REGARDLESS of the
 * caller — the determinism is single-homed in the hash, not the reader (Tenet-20,
 * gemini diff-review). Identity + `authoredAt` are NOT part of the material (see
 * `AuthoringLedgerEntrySchema.contentHash`).
 *
 * The file-level ATTESTATIONS (`splitRef` + the booleans) ARE part of the material
 * (greptile-P1 + CR diff-review): they are what this command records, so an
 * attestation-only change (e.g. the split was re-frozen) must trigger a revision
 * row — otherwise the rule reads `unchanged`, no row is appended, and the ledger
 * keeps the STALE split. `authoredAt` stays excluded (a timestamp refresh is a
 * no-op, §8); every OTHER ledger-attested mutable field is covered here.
 */
export declare function authoringContentHash(material: {
    declaredEngine: string;
    structuralClass: string;
    dslSource: string;
    positiveFixtures: unknown;
    negativeFixtures?: unknown;
    origin: unknown;
    splitRef: string;
    authoredAfterSplit: boolean;
    heldOutNonInspectionAttestation: boolean;
    /** The producer VERDICT (CR diff-review) — incl. `judgedBy`/`basis`; a verdict change must revise. */
    structuralEligibility: unknown;
    /**
     * ADR-112 R1 — the frozen split's freeze commitment, INSIDE the material
     * (codex fold-2: adjacent-to-the-hash would let a re-frozen split read
     * `unchanged`). Absent (legacy / free-text splitRef) ⇒ the key is dropped by
     * canonicalStringify, so every pre-R1 hash is byte-identical — additive.
     */
    freezeCommitment?: string;
}): string;
/**
 * Read the full authoring-ledger (append order = revision order; the LAST entry
 * per `ruleId` is effective). FAIL-LOUD on a malformed/invalid row — a corrupt
 * attestation chain must never be silently skipped. Returns `[]` if the ledger
 * does not exist yet (first author).
 */
export declare function readAuthoringLedger(totemDir: string): AuthoringLedgerEntry[];
/**
 * Append one §8 entry, FAIL-LOUD + READ-BACK-VERIFIED. Validates the entry
 * (throws on an incomplete row — FM(e)), appends canonically, then re-reads the
 * ledger and asserts the last row round-trips byte-identically. Any failure
 * THROWS so the caller never lets the rule reach compile feed on an unpersisted
 * attestation. (Distinct from `appendLedgerEvent`'s warn-and-continue.)
 *
 * Semantics are APPEND-ONLY, not transactional (codex diff-review): a read-back
 * mismatch on a row that did persist correctly is a report/state mismatch, not a
 * corrupt record — the next run reads the (valid) row as effective state. The
 * throw is the honest signal that THIS write could not be confirmed; it is never
 * a path to an invalid record (an actually-wrong row fails the schema re-read). A
 * heavier temp-file/lock/transaction story is deferred unless the cert demands it.
 */
export declare function appendAuthoringLedgerEntry(totemDir: string, entry: AuthoringLedgerEntry): void;
/**
 * Fold the ledger to its EFFECTIVE state: the LAST entry per `ruleId` (append
 * order = revision order, so a later revision supersedes). Returned in each
 * ruleId's FIRST-appearance order (Map insertion order, stable). The D5 authored
 * freeze/cert gates read these — a superseded revision must never gate the run.
 */
export declare function foldEffectiveLedgerEntries(entries: readonly AuthoringLedgerEntry[]): AuthoringLedgerEntry[];
/**
 * The effective state of one authored rule, folded from its ledger lineage: the
 * persisted `ruleId` + the latest material `contentHash`. Keyed by the identity
 * pair so the reader can upsert a re-read `(author,targetDefect)` onto its
 * existing id instead of self-colliding to a fresh `-N`.
 */
export interface AuthoredIdentity {
    ruleId: string;
    contentHash: string;
}
/**
 * The upsert identity key. Uses the SAME injective encoding as mintAuthoredRuleId's seed
 * (JSON.stringify of [author, targetDefect]) so the upsert key and the minted id agree on
 * what "one identity" is. A naive author-space-targetDefect join is NON-injective: a space
 * in either free-text field aliases distinct identities -- ('alice','off by one') and
 * ('alice off','by one') collapse onto one key (the #2259 CR-major class the mint already
 * fixed; strategy-claude flagged the upsert-key inconsistency on the slice-B seam review).
 * JSON.stringify of the pair can never collide across distinct inputs.
 */
export declare function identityKey(author: string, targetDefect: string): string;
/**
 * Fold the ledger into the upsert index: `(author,targetDefect)` → the effective
 * `{ruleId, contentHash}` (append order means the LAST row per identity wins —
 * the latest revision). Also returns every persisted `ruleId` so a genuinely NEW
 * identity mints against the full set. FAIL-LOUD on BOTH uniqueness violations
 * (codex diff-review): one `(author,targetDefect)` mapping to two `ruleId`s, AND
 * one `ruleId` shared by two distinct identities — the reverse would let one
 * authoring run materialize two records sharing an authored identity (both with
 * `authoringLedgerRef = ruleId`), which the fail-loud reader must reject too.
 */
export declare function buildAuthoredIdentityIndex(entries: readonly AuthoringLedgerEntry[]): {
    byIdentity: Map<string, AuthoredIdentity>;
    allRuleIds: Set<string>;
};
//# sourceMappingURL=authoring-ledger.d.ts.map