import type { SessionSigner } from "./crypto.js";
import type { DaSource, DataRef } from "./da.js";
import { type VerifiedTurn } from "./protocol.js";
import { type ToplocActivationBinding, type ToplocSessionEvidence } from "./toploc-evidence.js";
import { type ToplocActivationCommitment, type ToplocDistance, type ToplocTolerance } from "./toploc.js";
import { type ProducerOption } from "./lane-producer.js";
import { type GumbelCheckResult, type GumbelPositionLogits, type GumbelThresholds } from "./toploc-gumbel.js";
import { type Hash } from "./transcript.js";
/** Assignment seed domain (versioned). */
export declare const TOPLOC_CHECKER_ASSIGN_DOMAIN: Uint8Array<ArrayBuffer>;
/**
 * Default BFT fraction as Substrate Perbill parts (`666_666_666 / 1e9` ≈ 2/3),
 * matching runtime `PouiDefaultValidatorAttestationThreshold`.
 */
export declare const DEFAULT_QUORUM_THRESHOLD_PERBILL = 666666666;
/** Default checkers per sampled turn (k). */
export declare const DEFAULT_CHECKERS_PER_TURN = 3;
/** One active validator with stake weight and operator trust domain. */
export interface WeightedValidator {
    /** 32-byte account / sr25519 public key. */
    id: Hash;
    /** Operator / trust-domain id (must differ from miner's for independence). */
    operatorId: Hash;
    /** Stake weight (>0 to be eligible). */
    weight: bigint;
}
export interface CheckerAssignment {
    channelId: Hash;
    turnIndex: number;
    /** Ordered assigned checker validator ids (shard order). */
    checkerIds: Hash[];
}
export declare class SameOperatorRejectedError extends Error {
    readonly validatorId: Hash;
    readonly minerOperatorId: Hash;
    readonly code: "SameOperatorRejected";
    constructor(validatorId: Hash, minerOperatorId: Hash, message?: string);
}
/**
 * Deterministic stake-weighted selection of `k` distinct checkers for one
 * (channel, turn). Eligible pool = weight>0 **and** operatorId ≠ minerOperatorId.
 *
 * Seed: `blake2_256(FLOP/TOPLOC/CHECK/V1 || channelId || turn_u32le || beacon || i_u32le)`.
 * Walk mirrors DA `assign_providers` (u128 BE of first 16 digest bytes % total).
 */
export declare function assignToplocCheckers(args: {
    channelId: Hash;
    turnIndex: number;
    /** Epoch / session VRF beacon (or finalized block hash). */
    beacon: Hash;
    validators: readonly WeightedValidator[];
    minerOperatorId: Hash;
    k?: number;
}): CheckerAssignment;
/**
 * Guard: a validator must not check a session served by its own operator.
 * Throws {@link SameOperatorRejectedError} when operator ids match.
 */
export declare function assertIndependentOperator(validatorOperatorId: Hash, minerOperatorId: Hash, validatorId?: Hash): void;
/** True when `validatorId` is in the assignment for this turn. */
export declare function isAssignedChecker(assignment: CheckerAssignment, validatorId: Hash): boolean;
/** Lean/runtime tags: 0 accept, 1 escalate, 2 slash, 3 unavailable. */
export declare enum BandVerdict {
    Accept = 0,
    Escalate = 1,
    Slash = 2,
    Unavailable = 3
}
export interface ToplocBandConstants {
    kappaProfileHash: Hash;
    bandTauAccept: bigint;
    bandTauSlash: bigint;
    challengeK: number;
    challengeWindowW: bigint;
}
export declare function bandVerdict(tauAccept: bigint | null, tauSlash: bigint | null, dev: bigint): BandVerdict;
export declare function bandVerdictFromConstants(constants: ToplocBandConstants | null | undefined, dev: bigint): BandVerdict;
/** One validator's signed TOPLOC mismatch attestation (legacy quorum path). */
export interface ToplocMismatchAttestation {
    channelId: Hash;
    turnIndex: number;
    activationHash: Hash;
    recomputedHash: Hash;
    distance: ToplocDistance;
    milliExponentError: bigint;
    validatorId: Hash;
    signature: Uint8Array;
}
/**
 * SCALE-encode signable fields of {@link ToplocMismatchAttestation}
 * (`hp_poui::ToplocMismatchAttestation::encode_signable`).
 */
export declare function encodeToplocMismatchSignable(fields: {
    channelId: Hash;
    turnIndex: number;
    activationHash: Hash;
    recomputedHash: Hash;
    distance: ToplocDistance;
    milliExponentError: bigint;
}): Uint8Array;
export declare function signToplocMismatchAttestation(key: SessionSigner, fields: {
    channelId: Hash;
    turnIndex: number;
    activationHash: Hash;
    recomputedHash: Hash;
    distance: ToplocDistance;
    milliExponentError: bigint;
}): ToplocMismatchAttestation;
/** BFT quorum: `ceil(active × thresholdPerbill / 1e9).max(1)` (Substrate mul_ceil). */
export declare function requiredQuorum(activeCount: number, thresholdPerbill?: number): number;
/**
 * Deduplicate + verify a bundle of attestations vouch for identical evidence.
 * Returns distinct signers meeting quorum, or throws.
 */
export declare function aggregateMismatchQuorum(attestations: readonly ToplocMismatchAttestation[], opts: {
    activeCount: number;
    /** Perbill parts (default ≈ 2/3). */
    thresholdPerbill?: number;
    /** Optional: only accept listed active validator ids. */
    activeValidatorIds?: readonly Hash[];
}): {
    distinct: ToplocMismatchAttestation[];
    count: number;
    required: number;
};
/** Inputs needed to independently re-run prefill lane capture. */
export interface PrefillCheckInput {
    /** Prompt / turn input bytes (from transcript DA or session evidence). */
    prompt: Uint8Array;
    taskHash: Hash;
    modelHash: Hash;
    turnIndex: number;
    layerIndex: number;
    seed: Hash;
    producer?: ProducerOption;
    /** TOPLOC-v2 sampling inputs (only set when the commitment carries sampling data). */
    temperatureMilli?: number;
    outputTokenIds?: number[];
}
/**
 * Independent prefill executor. Production injects GPU/engine re-exec;
 * tests use {@link referencePrefillExecutor} (deterministic lane producer).
 *
 * Return `null` when model weights or capacity are unavailable — callers must
 * map this to {@link CheckerOutcomeKind.Unavailable}, never Accept.
 */
export interface ToplocPrefillExecutor {
    recomputeLanes(input: PrefillCheckInput): Promise<number[] | null>;
    /**
     * TOPLOC-v2 sampling seam. Re-project the LM head at each emitted decode
     * position and return top-k `(tokenId, logit)` candidates plus the emitted
     * token's logit (`null` if it fell below top-k). Return `null` when the model
     * head is unavailable — callers map that to Unavailable, never Accept. Optional
     * so lane-only checkers keep working unchanged.
     */
    recomputeSamplingLogits?(input: PrefillCheckInput): Promise<GumbelPositionLogits[] | null>;
}
/** Deterministic reference executor (lane-producer KAT path). */
export declare function referencePrefillExecutor(producer?: ProducerOption): ToplocPrefillExecutor;
export declare enum CheckerOutcomeKind {
    /** Honest recompute inside band / tolerance. */
    Accept = "Accept",
    /** Band Escalate — second-verifier path; emit escalation, no slash. */
    Escalate = "Escalate",
    /** Out of band / lane flags — fraud path (quorum → slash+refund). */
    Slash = "Slash",
    /**
     * Evidence missing, model/capacity unavailable, expired, or uncalibrated band.
     * **Never** treated as Accept.
     */
    Unavailable = "Unavailable"
}
export type UnavailableReason = "evidence_missing" | "evidence_malformed" | "model_unavailable" | "capacity_unavailable" | "expired" | "band_unavailable" | "sampling_unavailable" | "not_assigned" | "same_operator";
export type CheckerTurnOutcome = {
    kind: CheckerOutcomeKind.Accept;
    activationHash: Hash;
    recomputedHash: Hash;
    distance: ToplocDistance;
    milliExponentError: bigint;
    band: BandVerdict;
    /** TOPLOC-v2 sampling check result when it ran (undefined on lane-only path). */
    sampling?: GumbelCheckResult;
} | {
    kind: CheckerOutcomeKind.Escalate | CheckerOutcomeKind.Slash;
    activationHash: Hash;
    recomputedHash: Hash;
    distance: ToplocDistance;
    milliExponentError: bigint;
    band: BandVerdict;
    commitment: ToplocActivationCommitment;
    /** Set when the verdict was driven (or corroborated) by the sampling check. */
    sampling?: GumbelCheckResult;
} | {
    kind: CheckerOutcomeKind.Unavailable;
    reason: UnavailableReason;
};
export interface ToplocCheckerMetricsSnapshot {
    checked: number;
    accepted: number;
    escalated: number;
    slashed: number;
    unavailable: number;
    retries: number;
    expired: number;
    reorgDrops: number;
    submitted: number;
    sameOperatorRejected: number;
}
export declare class ToplocCheckerMetrics {
    checked: number;
    accepted: number;
    escalated: number;
    slashed: number;
    unavailable: number;
    retries: number;
    expired: number;
    reorgDrops: number;
    submitted: number;
    sameOperatorRejected: number;
    snapshot(): ToplocCheckerMetricsSnapshot;
    record(outcome: CheckerTurnOutcome): void;
}
export interface GovernancePins {
    /** Lane-distance tolerance (legacy path when band constants absent). */
    tolerance?: ToplocTolerance | null;
    /** Derived two-threshold band (preferred when present). */
    band?: ToplocBandConstants | null;
    /**
     * TOPLOC-v2 Gumbel sampling thresholds. When present **and** the commitment
     * carries sampling data, the checker replays the sampling race as an additional
     * gate. A sampling loss escalates/slashes even when the activation lanes match.
     * Absent → sampling is not verified (lane/band gate only, legacy behavior).
     */
    gumbel?: GumbelThresholds | null;
    /**
     * Optional milli-exponent-error from projection path. When omitted, band path
     * uses L1 distance scaled as a stand-in for unit tests; production injects
     * measured milli_exponent_error from secret projections.
     */
    milliExponentError?: bigint;
}
export interface CheckTurnArgs {
    da: DaSource;
    binding: ToplocActivationBinding;
    /** Prompt / input bytes for independent prefill. */
    prompt: Uint8Array;
    executor: ToplocPrefillExecutor;
    pins: GovernancePins;
    /** When true, binding is a batch blob entry. */
    batch?: boolean;
    batchRef?: DataRef | null;
    /** Ephemeral evidence expiry (unix ms); past → Unavailable expired. */
    expiresAtMs?: number;
    nowMs?: () => number;
}
/**
 * Fetch DA evidence, independently re-prefill, compute distance + band verdict.
 * When a Gumbel gate is configured and the commitment carries TOPLOC-v2 sampling
 * data, the sampling race is verified as an additional gate (worst-of merge).
 * Unavailable paths never return Accept.
 */
export declare function checkToplocTurn(args: CheckTurnArgs): Promise<CheckerTurnOutcome>;
export interface ToplocWatchtowerConfig {
    /** This validator's account id (32 bytes). */
    validatorId: Hash;
    /** This validator's operator / trust domain. */
    operatorId: Hash;
    /** Active weighted validator set (order preserved). */
    validators: readonly WeightedValidator[];
    minerOperatorId: Hash;
    beacon: Hash;
    checkersPerTurn?: number;
    pins: GovernancePins;
    executor: ToplocPrefillExecutor;
    metrics?: ToplocCheckerMetrics;
    /** Challenge-window end (ms); evidence after this is expired. */
    challengeEndMs?: number;
    nowMs?: () => number;
    /** Finality watermark: only act on sessions finalized at/below this block. */
    finalizedBlock?: bigint;
}
/** Every-turn checking remains the default until governance chooses a mode. */
export type ToplocSessionAuditMode = {
    mode: "all";
} | {
    mode: "sampled";
    epochId: Hash;
    alphaPpm: number;
    /** Full ordered session, not just turns with published activations. */
    verifiedTurns: readonly VerifiedTurn[];
    /** Key, root and extent from the same authenticated channel/settlement. */
    enclaveKey: Uint8Array;
    finalRoot: Hash;
    nTurns: number;
    aggregateGn: bigint;
};
export interface PendingMismatch {
    channelId: Hash;
    turnIndex: number;
    outcome: Extract<CheckerTurnOutcome, {
        kind: CheckerOutcomeKind.Slash | CheckerOutcomeKind.Escalate;
    }>;
    attestation: ToplocMismatchAttestation;
    /** Block height observed when signed (reorg guard). */
    observedBlock: bigint;
}
/**
 * Per-validator TOPLOC watchtower: assign → fetch DA → re-prefill → verdict →
 * sign. Aggregation/submit is separate so multiple validators can pool.
 */
export declare class ToplocCheckerWatchtower {
    private readonly cfg;
    readonly metrics: ToplocCheckerMetrics;
    private pending;
    /** Dedupe key → true for already-submitted (channel|turn). */
    private submittedKeys;
    /** Mutable finality watermark (reorg handling). */
    private finalizedBlock;
    constructor(cfg: ToplocWatchtowerConfig);
    /**
     * Run one turn check if this validator is assigned and independent.
     * Same-operator → Unavailable(same_operator) + metric, never Accept.
     */
    processTurn(args: {
        evidence: ToplocSessionEvidence;
        binding: ToplocActivationBinding;
        prompt: Uint8Array;
        da: DaSource;
        /** Optional signing key (must match cfg.validatorId). */
        key?: SessionSigner;
        observedBlock?: bigint;
    }): Promise<CheckerTurnOutcome>;
    /**
     * Process all activations by default, or only the value-planned set in explicit
     * sampled mode. Sampled leaves must cover the authenticated session extent and
     * match the independently authenticated settlement `finalRoot`, never a root
     * taken from the miner's evidence package, which may include an unacked tail.
     * Missing selected activation evidence is Unavailable. `prompts` keyed by turn
     * must contain the exact request input bytes authenticated by each leaf's hIn.
     */
    processSession(args: {
        evidence: ToplocSessionEvidence;
        prompts: ReadonlyMap<number, Uint8Array>;
        da: DaSource;
        key?: SessionSigner;
        observedBlock?: bigint;
        auditMode?: ToplocSessionAuditMode;
    }): Promise<CheckerTurnOutcome[]>;
    /** Pending signed mismatches (not yet submitted). */
    pendingMismatches(): readonly PendingMismatch[];
    /**
     * Drop pending items observed above the new finality watermark (reorg).
     * Call when finalized head rewinds or a fork invalidates observed blocks.
     */
    onFinalityReorg(newFinalized: bigint): number;
    /**
     * Aggregate external + local attestations for one turn and return a
     * deduplicated quorum bundle ready for chain submit.
     *
     * Building does **not** mark the turn submitted or drop local pending: this
     * method only shapes a bundle and cannot observe chain inclusion. A transient
     * RPC/dispatch failure after submit must stay retryable, so the caller marks
     * the turn done via {@link markSubmitted} only after a successful included
     * extrinsic. Returns `[]` once the turn has been confirmed submitted.
     */
    buildQuorumSubmission(channelId: Hash, turnIndex: number, attestations: readonly ToplocMismatchAttestation[], activeCount: number, thresholdPerbill?: number): ToplocMismatchAttestation[];
    /**
     * Confirm a turn's mismatch report was successfully included on-chain: make
     * future {@link buildQuorumSubmission} calls idempotent, count the submission,
     * and drop local pending. Call **only** after the extrinsic is included; a
     * failed or dropped submit must leave the turn retryable.
     */
    markSubmitted(channelId: Hash, turnIndex: number): void;
    /**
     * Retry wrapper for transient DA/capacity faults. Does **not** convert
     * Unavailable into Accept after retries exhaust.
     */
    withRetry<T>(fn: () => Promise<T>, maxRetries?: number): Promise<T>;
}
/**
 * Extrinsic arg shape for `report_toploc_mismatch` (snake_case for pallet).
 */
export declare function toExtrinsicToplocMismatchAttestation(att: ToplocMismatchAttestation): Record<string, unknown>;
//# sourceMappingURL=toploc-checker.d.ts.map