/**
 * design/339 — the v3 consolidation WRITE PROTOCOL's engine-side module: active-set derivation
 * (§1.4.3), the gate store / plan store control-plane sidecars (§2.3), option screening (§6.1) and
 * the model-visible wording the read-side supersession treatment mints (§3.4).
 *
 * The derivation here is the ONE predicate every read face consumes (index mechanical rows,
 * memory_search's default filter, memory_get's disclosure, and the v2 retention/recall knives when
 * they land) — a second implementation would be a drift seam, exactly the class the challenge
 * exclusion view closed.
 */
import type { MemoryEntry, MemoryEntryHeader, MemoryEntryOrigin, NotePatch } from "./types.js";
/**
 * Derive the SUPERSEDED set from a committed header listing: superseded entry id → the standing
 * carrier (product) id whose edge suppresses it. `active(x) ⇔ !returned.has(x.id)` over non-
 * tombstoned entries (tombstones never reach a header listing).
 *
 * Edge validity (§1.4.3, the r1-2/r3-2 amended law) — an edge (target, rev) carried by product `p`
 * is VALID ⇔ all of:
 *  - `p` stands in the listing (a tombstoned carrier lists nothing — its edges die with it);
 *  - `p` is not excluded by the local governance overlay (`excluded`: challenge/lineage-latch —
 *    a QUESTIONED replacement must not keep suppressing its net inputs; the inputs revive, the
 *    information never falls into a double black hole). The overlay is deliberately LOCAL (the
 *    challenge ledger does not travel) — a deployment without the account derives from committed
 *    facts alone and shows MORE evidence, the safe direction;
 *  - `p`'s committed rev still equals the block's `carrierRev` (the CARRIER-side rev anchor,
 *    r3-2): a legitimate edit of the product suspends its edges — the edited product may have
 *    rewritten or retracted what it integrated, and the only accurate copy must not hide outside
 *    the default face. Deep-carrying idempotent touches move no rev and keep the edges;
 *  - the TARGET stands in the listing at exactly the edge's anchored rev (the input-side rev
 *    anchor, D-2a): a later legitimate edit of the superseded entry REVIVES it (new information
 *    is never suppressed by an edge frozen over old bytes); an absent/tombstoned target makes the
 *    edge inert (nothing to suppress — the partial-apply direction is safe by the self-containment
 *    law: an edge exists only on a landed product);
 *  - the target lives in the CARRIER'S OWN SCOPE (§3.3 内闭合, read side). The freeze and the retry
 *    enforce "one plan, one scope" on the WRITE side, but every read consumer here is fed a
 *    MULTI-scope listing (the tool face lists a plane's scopes, index rebuild and the collapse fuse
 *    list every mounted scope), and an edge frozen legally inside scope A can later face a target
 *    in scope B: `computeEntryRev` deliberately excludes scope/slug, so a supported cross-scope
 *    MOVE leaves the anchored rev intact, and an adopted carrier (sync/bundle) is validated for its
 *    OWN scope with its edge list checked for SHAPE only. Consolidation authority is per-scope
 *    (seat + lease), so a scope-A carrier must not pull a scope-B entry out of B's default face.
 *    A whole-scope migration moves carrier and target together and keeps this leg satisfied; only
 *    the split/partial case changes, and it degrades toward REVIVAL — this module's stated safe
 *    direction (a deployment shows MORE evidence, never less).
 *
 * CHAIN RULE (§1.4.3, explicit): a carrier that is ITSELF superseded (by a later product) keeps
 * its edges — supersession is convergence, not discredit; the chain p2→p1→x keeps x suppressed.
 * Only integrity questioning (the overlay) and the tombstone suspend a carrier's edges.
 *
 * NON-EMPTINESS (§1.4.3 定理, r2-1): edges only point at a product's own inputs, and inputs are
 * committed before the product exists — the supersession relation is a DAG, its maximal elements
 * are always active, so a non-empty library can never derive an empty active set (pinned by test
 * with the dual-plan full-coverage construction).
 */
export declare function deriveSupersededSet(headers: readonly MemoryEntryHeader[], opts?: {
    excluded?: (id: string) => boolean;
}): Map<string, string>;
/** memory_get head note for a superseded entry (delivery proceeds — disclosure, never refusal). */
export declare function memorySupersededNote(carrierId: string): string;
/** The tag suffixed to a search hit line when a superseded entry is retrieved explicitly. */
export declare const MEMORY_SEARCH_SUPERSEDED_TAG = "[superseded]";
/**
 * §1.7/§2.3 — the host-injected GLOBAL lease seat (multi-node deployments). The protocol's SAFETY
 * never depends on it (§1.7 four-independence table) — the lease is COST suppression (one
 * distillation fleet-wide) plus the fencing token that shrinks a stale holder's overlap window to
 * a single applyPatches batch. `acquire` answers `undefined` when the lease is NOT held; a held
 * answer may carry a monotonic `token` whose CURRENT value is re-checked before every apply batch
 * (a changed token aborts the batch — the plan stays replayable under the new holder).
 */
export interface ConsolidationLeaseSeat {
    acquire(scope: string): Promise<{
        token?: string;
    } | undefined> | {
        token?: string;
    } | undefined;
    renew?(scope: string): Promise<{
        token?: string;
    } | undefined> | {
        token?: string;
    } | undefined;
    release?(scope: string): Promise<void> | void;
}
/** design/339 §6.1 — the `MemoryEngineOptions.consolidation` seat (absent = OFF, the v3 default). */
export interface MemoryConsolidationOptions {
    /** Fuse ratio (0,1]: one plan's supersession targets ≤ min(N-1, max(floor, ⌊ratio×N⌋)). */
    supersedeRatioCap?: number;
    /** Small-library floor (positive integer), capped by the N-1 ceiling. */
    supersedeAbsoluteFloor?: number;
    maxProductsPerRun?: number;
    maxInputsPerProduct?: number;
    maxDirectedPatchesPerPlan?: number;
    minRunIntervalMs?: number;
    minSessionsBetweenRuns?: number;
    /** design/376 C-2② — the scan-refusal fuse's ratio leg, in (0, 1]: scan findings refuse the
     *  affected PRODUCT (disclosed beside eligibility drift), and the whole plan refuses only when
     *  more than max(1, ⌊ratio × submitted products⌋) of them fail the scan (the floor keeps the
     *  per-product tolerance alive on 1-4 product plans — the drive lane's common size) — see
     *  {@link scanRefusalCeiling}. Default 0.25. */
    scanRefusalRatioCap?: number;
    /** design/376 C-2② — the fuse's absolute leg (positive integer): the large-batch upper bound on
     *  tolerated scan refusals per plan, so the ratio cannot scale the tolerance without limit.
     *  Default 8 (the point where the 0.25 ratio hands over at 32 submitted products — the family's
     *  "小 N" quantification; below that the ratio leg alone governs). */
    scanRefusalMaxPerPlan?: number;
    /** design/376 C-3 — the EXPLICIT escape hatch for the unconditional instruction-form gate:
     *  instruction-form consolidation products (`type: "feedback"` / v2 hint carriers) are refused
     *  by default REGARDLESS of the visible set's markers — a clean-set instruction product is the
     *  model-reachable privilege route (N ordinary notes in, one instruction entry out). `true` is
     *  the only accepted value (a posture declaration, like {@link multiNode}); it opens the
     *  CLEAN-set arm only — a marked visible set refuses instruction forms under the laundering
     *  hard gate no matter what (privilege and hard gate enter and exit through one door). */
    allowInstructionProducts?: true;
    /** D-13a — the multi-node POSTURE declaration: present ⇒ `lease` must be injected (constructor
     *  refusal otherwise). Multi-node without declaring is OUT OF CONTRACT (structurally
     *  undetectable — the declaration turns a silent omission into an explicit choice). */
    multiNode?: true;
    /** The global lease (§1.7). Absent ⇒ the single-machine plan-seat CAS is the only mutex. */
    lease?: ConsolidationLeaseSeat;
}
/**
 * D-10 — factory defaults. CC-product-default transplants, NOT sema calibrations (178 ①-3): the
 * 24h/5-session cadence mirrors the background-consolidation cadence CC-family products ship;
 * 0.25/floor-4 mirror the mass-deletion fuse family's calibration posture (MASS_DELETION_FUSE_RATIO
 * 0.5 halved — a LOGICAL delete rides on top of the physical fuse, so its单窗 ceiling is stricter);
 * 64/32/32 are the "小 N" ruling's quantification. Hosts can configure every one.
 */
export declare const CONSOLIDATION_DEFAULTS: {
    readonly supersedeRatioCap: 0.25;
    readonly supersedeAbsoluteFloor: 4;
    readonly maxProductsPerRun: 64;
    readonly maxInputsPerProduct: 32;
    readonly maxDirectedPatchesPerPlan: 32;
    readonly minRunIntervalMs: number;
    readonly minSessionsBetweenRuns: 5;
    readonly scanRefusalRatioCap: 0.25;
    readonly scanRefusalMaxPerPlan: 8;
};
/**
 * §2.2 — the HARD throttle floor: even a `force` run cannot start a second same-scope run within
 * this window of the previous one (cost floor + double-run suppression; the mutex covers overlap,
 * this covers thrash). The window is `min(minRunIntervalMs, THIS)` — the knob is reused as the
 * cap, never exceeded — because a full-`minRunIntervalMs` hard throttle would make `force`
 * structurally dead (the doc's force-bypassable time gate and its unbypassable throttle share the
 * knob; this floor form is the one reading that keeps both meaningful, disclosed).
 */
export declare const CONSOLIDATION_FORCE_THROTTLE_FLOOR_MS = 60000;
/** The bounded distinct-session ring (§2.3 sessionsSince dedup). */
export declare const CONSOLIDATION_SESSION_RING_MAX = 64;
/**
 * the seat's FREEZE GRACE: reconcile's orphan-release arm treats a seat whose plan file
 * is absent as crashed ONLY once the claim is at least this old. Calibration: the freeze between
 * the seat CAS and the plan file's durable write is committed READS only (headers + a bounded
 * getByIds) — seconds on any healthy store; ten minutes is orders of magnitude past it, while a
 * genuinely crashed claim still self-heals within one recommendation cadence. Inside the window
 * reconcile reports the claim as in-flight instead of releasing it.
 */
export declare const CONSOLIDATION_SEAT_FREEZE_GRACE_MS: number;
export interface ScreenedConsolidationOptions {
    supersedeRatioCap: number;
    supersedeAbsoluteFloor: number;
    maxProductsPerRun: number;
    maxInputsPerProduct: number;
    maxDirectedPatchesPerPlan: number;
    minRunIntervalMs: number;
    minSessionsBetweenRuns: number;
    scanRefusalRatioCap: number;
    scanRefusalMaxPerPlan: number;
    allowInstructionProducts: boolean;
    multiNode: boolean;
    lease?: ConsolidationLeaseSeat;
}
/**
 * Screen the consolidation options at engine construction (#123 bad-value loudness: every bad
 * value refuses with a code, never folds to a default). Two structural refusals beyond values:
 *  - D-12a: `provenance: "off"` × consolidation present is a CONSTRUCTION refusal — off means "no
 *    origin is ever minted", while consolidation's fold law must be able to mint (a marked input's
 *    product would otherwise commit unmarked = the laundering window). Enable carry or disable
 *    consolidation.
 *  - D-13a: `multiNode: true` without an injected lease refuses — the declaration exists exactly
 *    to make that omission explicit.
 */
export declare function screenConsolidationOptions(raw: MemoryConsolidationOptions, provenance: "off" | "carry"): ScreenedConsolidationOptions;
/** §1.2-2 — the supersession fuse ceiling: min(N-1, max(floor, ⌊ratio×N⌋)); N ≤ 1 ⇒ 0 (one plan
 *  may NEVER empty the active set — the N-1 ceiling is unconditional, G21). */
export declare function supersessionFuseCeiling(activeSetSize: number, opts: Pick<ScreenedConsolidationOptions, "supersedeRatioCap" | "supersedeAbsoluteFloor">): number;
/**
 * design/376 C-2② — the scan-refusal fuse ceiling: how many scan-refused products ONE plan may
 * carry before the whole plan refuses instead of committing around them.
 * `min(max(1, ⌊ratio × submitted⌋), absolute max)`; the ratio leg governs small plans, the
 * absolute leg is the large-batch upper bound, and the FLOOR of one keeps C-2①'s per-product
 * tolerance alive at the drive lane's common plan sizes — under the default 0.25 ratio a bare
 * floor answers 0 for every ≤3-product plan, so one stray refused product re-killed the whole
 * plan there, exactly the shape C-2① was adopted to remove (an adopted review finding). The
 * floor is NOT a hole for the fully-refused tiny plan: a plan whose every product is refused
 * (and which carries no directed work) still dies at the freeze-emptied C-2③ backstop, never a
 * quiet mostly-no-op — what the floor tolerates is exactly one refused product beside at least
 * one survivor. Submitted count = the proposal's product count (per THIS plan, never a
 * cross-run tally).
 */
export declare function scanRefusalCeiling(submittedProducts: number, opts: Pick<ScreenedConsolidationOptions, "scanRefusalRatioCap" | "scanRefusalMaxPerPlan">): number;
/** §3.1 — the type axis of the eligibility predicate: episodic entries are read-only evidence
 *  (never candidates, never supersession/directed targets, A-7); procedural promotion is a v3
 *  follow-on ticket. Unknown/absent types are ordinary semantic notes — eligible. */
export declare function consolidationTypeEligible(type: string | undefined): boolean;
export declare const CONSOLIDATION_GATE_FILE = "consolidation-gate.json";
export declare const CONSOLIDATION_PLANS_DIR = "consolidation-plans";
export declare const CONSOLIDATION_INTENTS_FILE = "consolidation-intents.json";
export interface ConsolidationGateRow {
    /** Last COMPLETED run's settle time (ms epoch). */
    lastRunAt?: number;
    /** Distinct terminal-harvest sessions since the last run (count + bounded dedup ring). */
    sessions: {
        count: number;
        ring: string[];
    };
    /** The plan-seat mutex: the one non-terminal (or conflict-parked) plan of this scope. */
    openPlanId?: string;
    /** When the seat was claimed (ms epoch) — the reconcile orphan-release arm's staleness anchor
     *  (a freeze legitimately computes for a while between the seat CAS and the plan
     *  file's durable write; an absent file alone must never read as a crash). */
    seatClaimedAt?: number;
    /** §1.4.5 collapse-fuse baseline (last observed active-set size). */
    activeSetBaseline?: number;
    /** Once-per-crossing edge for the recommendation notice. */
    lastRecommendedAt?: number;
    /** The last force requestId whose FORCED announcement was enqueued (additive; design/376 §1.1-4):
     *  a RUN-scoped force carries ONE requestId across every cycle of a multi-cycle run, and the
     *  audit announcement is deduplicated on it — one disclosure per run, never one per cycle (a
     *  cold start would otherwise flood the next session's injection face with a dozen identical
     *  lines). A NEW requestId re-arms the disclosure. The dedup is the ONLY record: this row keeps
     *  just the LAST id (no history structure exists — the gate row is mutated in place, the
     *  announcement queue is drained destructively, and plan files do not mark forced-ness), so
     *  per-force facts beyond the one announcement are not persisted, and a caller that reuses a
     *  fixed requestId across runs keeps the disclosure silent for as long as it does. */
    lastForcedRequestId?: string;
    /** Run watermark: increments on every completed/discarded settlement (the stale-proposal gate). */
    epoch: number;
    /** §1.2-1 — the last COMPLETED run's full-eligible-set fingerprint (id → committed rev):
     *  change-driven increments diff against THIS — a candidate is an eligible entry that is new
     *  to the map or whose rev moved (eligibility flips INTO the set read as "new": the map only
     *  ever holds eligible entries). Absent/lost ⇒ full candidates (conservative: 多看不少看). */
    fingerprint?: Record<string, {
        rev: string;
    }>;
    /** The last snapshot taken for this scope (the engine's visible-set account, §1.2-2 r3-1: the
     *  fold/instruction authority is what the engine actually SERVED — recorded here, keyed by the
     *  cycle token; a newer snapshot replaces it, and commit refuses a token that no longer
     *  matches). `candidates`: the served (incremental) id → rev set — the edge-target legality
     *  domain; `eligible`: the FULL eligible id → rev map at snapshot time (the next fingerprint on
     *  completion); `marked`: any served candidate carried a committed external-origin marker;
     *  `markedIds` (additive, design/376-C1 D-1b): WHICH served candidates carried it — the
     *  attested freeze's world-movement baseline (a candidate marked NOW but absent here turned
     *  marked after the snapshot ⇒ the mint's clean-arm premise is stale). Absent on rows written
     *  before the field existed: an attested freeze over such a row takes the conservative arm
     *  (ANY currently-marked served candidate refuses stale — no baseline means no proof the mark
     *  predates the mint, and refusing to re-mint beats guessing). */
    snapshot?: {
        token: string;
        at: number;
        epoch: number;
        candidates: Record<string, string>;
        eligible: Record<string, string>;
        marked: boolean;
        markedIds?: string[];
    };
}
interface ConsolidationGateFile {
    v: 1;
    scopes: Record<string, ConsolidationGateRow>;
}
/** Locked, journaled gate update (the strict family's exact discipline). */
export declare function updateConsolidationGate<T>(controlDir: string, fn: (file: ConsolidationGateFile) => {
    next?: ConsolidationGateFile;
    result: T;
}): T;
/** Lock-less journal-aware gate read (corrupt ⇒ throws — the verbs' fail-closed arm). */
export declare function readConsolidationGateFile(controlDir: string): ConsolidationGateFile;
/** True ⇔ the gate store file exists at all (G1's zero-file pin reads this negatively). */
export declare function consolidationGateFileExists(controlDir: string): boolean;
/**
 * design/376 slice ③ (#437②) — the gate read face's DISCRIMINATED answer
 * ({@link import("./engine.js").MemoryEngine.readConsolidationGateState}): `present` carries the
 * row; `absent` means the store is readable and simply has no row for the scope (a never-run
 * scope, or no gate file at all); `corrupt` means the store cannot be trusted and carries the
 * refusal detail. The undiscriminated `readConsolidationGate` face folds corrupt into `undefined`
 * — an operator (or a driver's scheduling read) could not tell a healthy never-run scope from a
 * store every verb will refuse fail-closed.
 */
export type ConsolidationGateRead = {
    state: "present";
    row: ConsolidationGateRow;
} | {
    state: "absent";
} | {
    state: "corrupt";
    detail: string;
};
/**
 * §2.2 — does the row hold a recommendation no COMPLETED run has consumed? `true` ⇔ a crossing was recorded
 * (`lastRecommendedAt`) and no run has settled since. The recommendation EDGE in {@link recordConsolidationSession}
 * is exactly this fact's negation, and the settle-tail auto-run trigger asks this same function of the gate row:
 * ONE source for "is a run owed", so the edge can never sit disarmed while the trigger believes nothing is owed.
 */
export declare function recommendationUnconsumed(row: Pick<ConsolidationGateRow, "lastRecommendedAt" | "lastRunAt">): boolean;
/** §2.2 — the ONE reading of "how many distinct sessions has this scope banked since its last completed run", for every gate comparing it against `minSessionsBetweenRuns` and every sentence reporting it. The stored `count` includes the most recent harvest's session, and that one is never material to a decision taken on its own behalf: this bookkeeping also runs on the suspend path, so it may still be running, and at a terminal harvest its notes are the ones just written. Banked is one less than stored; an absent row banks nothing.
 *  Never re-derived — two gates comparing two numbers is how a run is admitted for a crossing that was never minted, and how a refusal reports a figure the recommendation notice contradicts. */
export declare function sessionsSinceExcludingCurrent(row: Pick<ConsolidationGateRow, "sessions"> | undefined): number;
/**
 * §2.2 — the engine-minted session count (harvest-tail bookkeeping; ≤1 row write per terminal
 * harvest; the OFF mode never calls this — D-9a zero-write). Returns the recommendation edge:
 * `recommended` is true exactly ONCE per threshold crossing (once-per-越线沿; a completed run
 * resets the edge).
 *
 * The ring records the calling session (dedup), so `count` INCLUDES the caller; the gate here and the number beside it are {@link sessionsSinceExcludingCurrent}, which takes it back out.
 */
export declare function recordConsolidationSession(controlDir: string, scope: string, sessionId: string, opts: ScreenedConsolidationOptions, now: () => number): {
    recommended: boolean;
    sessionsSince: number;
};
/**
 * §1.4.5 — the active-set COLLAPSE fuse: record the freshly derived active-set size against the
 * stored baseline; a single-window shrink beyond the ratio cap answers the collapse fact (the
 * caller discloses via incident + announcement — the read face NEVER refuses service over it).
 * Baseline loss ⇒ re-baseline silently (conservative: one extra disclosure at worst next window).
 */
export declare function recordActiveSetBaseline(controlDir: string, scope: string, size: number, ratioCap: number, _now: () => number): {
    collapsed?: {
        from: number;
        to: number;
    };
};
/** §1.5 — a directed-change intent (TERMINAL-STATE form: the intent names the target end state,
 *  never an increment — the precondition for replay/re-judgment converging at any interleaving). */
export type ConsolidationIntent = {
    requestId: string;
    kind: "forget";
    entryId: string;
} | {
    requestId: string;
    kind: "rewrite";
    entryId: string;
    body: string;
    name?: string;
    description?: string;
    type?: string;
};
/** §1.1 — one proposed product (driver output = DATA, zero carriage authority: origin/distilled
 *  in a proposal do not exist as fields — the engine computes both at freeze). The design/376-C1
 *  attestation does not breach this invariant: `mintExposure` on the PROPOSAL declares how the
 *  prompts were composed, it carries no origin value and can never set one — the engine still
 *  computes every origin itself (per product under attestation, run-level otherwise). */
export interface ConsolidationProductProposal {
    name?: string;
    description?: string;
    type?: string;
    body: string;
    /** The product's COMPLETE input attribution; `supersede: true` rows are the proposed edges. */
    inputs: Array<{
        id: string;
        supersede?: boolean;
    }>;
}
export interface ConsolidationProposal {
    scope: string;
    products: ConsolidationProductProposal[];
    intents?: ConsolidationIntent[];
    /**
     * design/376-C1 D-2 — the HOST-CODE attestation about prompt composition: `"partitioned"`
     * declares that the proposal was minted under exposure-partitioned calls, i.e. every all-clean
     * declared product's authoring chain was served NO byte of any committed-origin (marked) entry
     * (the clean arm's grouping/writing calls saw the clean subset only — mechanical isolation,
     * auditable from the archived transcript). The freeze folds origin PER PRODUCT only under this
     * attestation; absent (or any other spelling — refused structurally, closed set), the freeze
     * keeps the run-level single-value fold: any marked candidate in the served set marks EVERY
     * product (today's safe default, and the permanent default for foreign minters).
     *
     * Trust plane, stated in full: this is a host-code attestation, NOT driver/model output — the
     * drive re-assembles the proposal it commits (`{ scope, products, mintExposure }`), so model
     * output can never populate it. Attesting falsely is a HOST defect outside the threat model,
     * the same plane as a mis-declared `ToolSpec.contentOrigin` — and unlike most host mistakes it
     * stays auditable after the fact: the archived clean-arm grouping prompt must contain zero
     * marked-entry bytes, a mechanical check any reader can re-run against any plan that claims
     * this attestation.
     */
    mintExposure?: "partitioned";
}
export type ConsolidationDirectedState = "pending" | "applied" | "satisfied" | "conflict";
export interface ConsolidationDirectedPatch {
    intentRequestId: string;
    op: "update" | "delete";
    id: string;
    baseRev: string;
    /** update: computeEntryRev of the frozen terminal entry (the satisfied-judgment anchor, r2-4);
     *  absent for delete (the delete terminal is ABSENCE — probed, not hashed). */
    plannedPostRev?: string;
    entry?: MemoryEntry;
    state: ConsolidationDirectedState;
    /** delete only (§1.5-2): who reached the terminal — "self" when THIS plan's apply landed it,
     *  "unattributed" when a replay found the terminal already standing (the F9 crash micro-window:
     *  audit degrades, the judgment never does). */
    attribution?: "self" | "unattributed";
}
export type ConsolidationPlanState = "open" | "applying" | "completed" | "conflict" | "discarded";
export interface ConsolidationPlanFile {
    /** Plan schema version. `2` ⇔ the plan carries {@link freezeRefusedInputIds} — that member is a
     *  LOAD-BEARING settle input (C-2④ keeps the named ids out of the completion fingerprint), and
     *  a reader that predates it would accept the file as v1, ignore the member, and settle a
     *  fingerprint that stamps the refused members (silently blinding the incremental face — the
     *  exact hole the field closes). Version-gating the member makes such a reader answer its
     *  "unrecognized version" corrupt arm instead: the plan parks loudly for the valve, never
     *  settles wrong (mixed-fleet crash window between the durable plan write and gate settlement).
     *  Plans without the member stay v1 — zero noise on the common path. */
    v: 1 | 2;
    planId: string;
    scope: string;
    requestId: string;
    createdAt: number;
    cycleToken?: string;
    epoch: number;
    /** r3-1 — the ENGINE-VISIBLE-SET fold fact this run froze under (authority = what the engine
     *  served, never the proposal's declaration). */
    visibleMarked: boolean;
    /** The RUN-LEVEL single-value fold, when it applied (design/376-C1 D-6): present ⇔ this plan
     *  froze UN-attested over a marked served set, and this one value rides every product. An
     *  attested (per-product) plan omits it — each product's origin lives in its own frozen bytes
     *  below, and a single plan-level value would misdescribe a mixed plan. */
    foldedOrigin?: MemoryEntryOrigin;
    /** design/376-C1 D-6 — the proposal's accepted attestation, echoed for audit (informational:
     *  apply is byte-faithful to `products` and never re-reads this; a reader that predates the
     *  field ignores it and replays correctly, which is why the plan version does NOT bump). */
    mintExposure?: "partitioned";
    /** Frozen products — FULL entry bytes (id/frontmatter incl. distilled + origin/body/rev). */
    products: MemoryEntry[];
    productStates: Record<string, "pending" | "applied" | "conflict">;
    /** design/376 C-2④ — the declared input ids of every product the FREEZE refused (scan findings
     *  and eligibility drift alike). Settlement keeps these ids OUT of the completion fingerprint:
     *  a scan-refused input's rev never moved, so stamping it would make every later incremental
     *  snapshot read it as unchanged and never offer it again — the refused member must stay a
     *  candidate. Absent on plans frozen before the field existed, and on plans with nothing
     *  refused (either way the settle filter simply has nothing extra to exclude). */
    freezeRefusedInputIds?: string[];
    directed: ConsolidationDirectedPatch[];
    intents: Array<{
        requestId: string;
        state: "pending" | "settled" | "abandoned";
    }>;
    state: ConsolidationPlanState;
    audit: Array<{
        at: number;
        event: string;
        requestId?: string;
        detail?: string;
    }>;
}
/**
 * Plan ids are ENGINE-MINTED uuids, but the host-facing verbs (`resolveConsolidationPlan`,
 * `reconcileConsolidation` via the gate row) echo them back as ARGUMENTS — and the id doubles as a
 * control-plane FILE NAME, so a crafted spelling (`../…`, an absolute path) would escape the plans
 * directory on the read AND on the corrupt-custody RENAME (an outside pass's security finding,
 * adopted). One grammar (the entry-id family's shape), judged before any path join — the 幽灵行
 * guard's refusal posture: an invalid spelling reads as absent/refused, never as a path.
 */
export declare function isValidConsolidationPlanId(value: string): boolean;
export declare function writeConsolidationPlan(controlDir: string, plan: ConsolidationPlanFile): void;
export type ConsolidationPlanRead = {
    state: "ok";
    plan: ConsolidationPlanFile;
} | {
    state: "absent";
} | {
    state: "corrupt";
    detail: string;
};
export declare function readConsolidationPlan(controlDir: string, planId: string): ConsolidationPlanRead;
export declare function listConsolidationPlanIds(controlDir: string): string[];
/** F5 custody — a corrupt plan file the valve DISCARDS is moved aside (never deleted: the bytes
 *  are the only record of what the plan was). Returns the custody file name. */
export declare function quarantineCorruptPlan(controlDir: string, planId: string): string | undefined;
export interface ConsolidationIntentCredentialRow {
    requestId: string;
    state: "settled" | "abandoned";
    planId: string;
    at: number;
    patches: Array<{
        op: "update" | "delete";
        id: string;
        attribution?: "self" | "unattributed";
    }>;
}
/**
 * Record intent credentials — IDEMPOTENT on requestId (F10: two plans racing one intent cannot
 * double-settle; the first credential row stands, a later contradictory write is dropped with the
 * losing verdict returned to the caller for audit). Returns the requestIds actually written.
 */
export declare function recordIntentCredentials(controlDir: string, rows: readonly ConsolidationIntentCredentialRow[]): string[];
export declare function readIntentCredentials(controlDir: string): Record<string, ConsolidationIntentCredentialRow>;
/** Derive a product's slug from its proposed name (memory filename charset; collisions are the
 *  backend's deterministic -n suffix). */
export declare function deriveProductSlug(name: string | undefined, fallback: string): string;
/** The refusal error every consolidation verb throws (structured: stable `code` + the per-item
 *  disclosure list — G5/G7/G14's "结构化拒+披露" shape). */
export declare class ConsolidationRefusedError extends Error {
    readonly code: string;
    readonly reasons: string[];
    /**
     * #495 — THIS refusal's own occurrence identity, minted where the fact is created (one throw, one
     * id) rather than at whatever face later describes it. The notice dialect
     * ({@link import("./engine.js").memoryConsolidationRefusedNotice}) reads it off the error, so the
     * throw and its announcement name the same event however many times a host renders it: a repeated
     * gate refusal (same `code`, same `scope`, byte-identical `message`) is otherwise indistinguishable
     * from one refusal logged twice.
     *
     * Per-occurrence by construction, and correctly so: a refusal is a pure in-process event with no
     * durable seat — nothing persists it, so nothing replays it, and two refusals ARE two facts. (The
     * fail-open shape #476 rejected is a per-DELIVERY mint for families whose occurrences do return
     * from a durable store and must answer the same id each time; this is the opposite geometry.)
     */
    readonly occurrenceId: string;
    constructor(code: string, message: string, reasons?: string[]);
}
/** A NotePatch list for one frozen product (the §1.3 add-only arm's one spelling). */
export declare function productAddPatch(product: MemoryEntry): NotePatch;
/**
 * Why a driver run stopped — ONE closed set shared verbatim by the run receipt and the
 * `memory.consolidation_incomplete` notice (two vocabularies for the same fact would let an
 * operator-facing channel and the host-facing receipt drift). Non-`converged` values mark a
 * library in a PARTIAL fold — a transitional state the readings show is worse than unfolded, so
 * it must never pass silently:
 *  - `converged`      — nothing left to fold (the only completed-run value; includes the
 *                       empty-plan no-op: a model that proposes nothing commits nothing);
 *  - `fuse_residue`   — the supersession fuse admits no remaining product; the residue is named
 *                       and the next run's full snapshot re-distills the shrunken library;
 *  - `max_cycles`     — the cycle bound elapsed before a fixpoint;
 *  - `parked`         — a plan settled conflict (or a corrupt plan holds the seat); the host
 *                       valve `resolveConsolidationPlan` is the only way forward;
 *  - `refused`        — an engine verb refused and the drive could not continue this run;
 *  - `driver_failed`  — the DRIVER half could not complete. Two grains, one verdict: a failed
 *                       MINT (model unreachable/unreadable/over the repair budget) settles with
 *                       zero writes, zero seat and an unburned time gate; a run whose surviving
 *                       plan reached its fixpoint while the driver left groups unfolded (writing
 *                       failures, or products dropped stale against inputs edited mid-run) settles
 *                       here TOO — committed cycles stand (add-only), the residue is named, and a
 *                       fresh run re-mints over current bytes. `converged` never covers a residue;
 *  - `mint_invalidated` — design/376-C1 D-1b: the mint's served-world ROSTER failed the
 *                       cross-cycle re-check — a served candidate moved rev, flipped its marked
 *                       flag, or left the candidate set without a fold this run's own plans
 *                       attest. The cached plan is discarded (its prompts were composed over a
 *                       world that no longer stands, and replaying it could publish clean products
 *                       whose authoring chain absorbed the moved row's influence); committed
 *                       cycles stand, and the host re-runs to re-mint over the current bytes.
 *  - `purity_violation` — design/383 §1.3 (S-1): the minted plan carries a product that will
 *                       commit UNMARKED while containing bytes only the MARKED arm was shown. The
 *                       exposure partition's isolation premise is falsified, so the whole mint is
 *                       discarded with ZERO writes and the transcript is archived (a security
 *                       event's only evidence). DELIBERATELY DISTINCT from `driver_failed`: that
 *                       one says the model half could not finish, this one says the safety
 *                       topology did not hold — a host that folds them loses the ability to tell
 *                       "the model was flaky" from "content crossed a boundary it must not cross",
 *                       and only the second is an incident.
 * Extending this set is a consumer-visible closed-set expansion (release-note duty: every
 * downstream that pinned the enumeration becomes a named party — `mint_invalidated` was the
 * design/376-C1 add, `purity_violation` the design/383 片1 add, each named on its release).
 *
 * The type DERIVES from the array (never `satisfies` beside it): the array exists precisely for
 * downstream enumeration, and two independent declarations would let a new union arm skip the
 * array with no compile error — the derived form makes an edit to either side a type error at
 * the other.
 */
export declare const CONSOLIDATION_RUN_STOP_REASONS: readonly ["converged", "fuse_residue", "max_cycles", "parked", "refused", "driver_failed", "mint_invalidated", "purity_violation"];
/** See the doc on {@link CONSOLIDATION_RUN_STOP_REASONS} — the single source this derives from. */
export type ConsolidationRunStopReason = (typeof CONSOLIDATION_RUN_STOP_REASONS)[number];
export {};
