/**
 * UnjustifiedStopGate — the sole decision authority for whether a Stop
 * event represents a drift-induced context-death self-stop, and if so,
 * whether to continue (block the stop with a reminder) or allow it.
 *
 * Spec: docs/specs/context-death-pitfall-prevention.md § (b)
 *
 * Threat model: drift-correction, NOT security boundary. A deliberately
 * adversarial agent can bypass this gate; we don't claim otherwise.
 *
 * Structural constraints (defense-in-depth against LLM drift):
 *
 *   1. Rule must come from a FIXED enumerated set (nine ids total).
 *      Invented rule ids → invalidRule, fail-open.
 *   2. Evidence pointer values (plan_file, plan_commit_sha,
 *      incremental_commit_sha) must match verbatim strings in
 *      evidence_metadata.artifacts. The authority CANNOT hallucinate
 *      file paths or commit shas — only select from the hook-enumerated
 *      set. Invented pointers → invalidEvidence, fail-open.
 *   3. untrusted_content (stop_reason + recent_turns) is passed as
 *      structured JSON with a system-instruction to treat it as data,
 *      never as instructions. Evidence MUST come from evidence_metadata,
 *      never from untrusted_content extraction.
 *   4. Server-assembled reminder text — the authority returns only a
 *      rule id + pointer; the server builds reminder prose from a
 *      fixed template. No free-text leak path to the agent.
 *   5. Hard client-side AbortController 2000ms; server LLM budget
 *      1400ms + 400ms post-verification = 1800ms total; timeouts
 *      fail-open with DegradationReport.
 *
 * This module owns the LLM call + parsing only. HTTP routing,
 * persistence, post-verification, and reminder assembly live in
 * `src/server/stopGate.ts` (PR0a plumbing) and `src/server/routes.ts`.
 */
import type { IntelligenceProvider } from './types.js';
export type ContinueRule = 'U1_DURABLE_ARTIFACT_CONTINUATION_SAFE' | 'U2_PLAN_FILE_NEXT_STEP_EXPLICIT' | 'U3_RECENT_COMMIT_PROVES_INCREMENTAL';
export type AllowRule = 'U_LEGIT_DESIGN_QUESTION' | 'U_LEGIT_MISSING_INFO' | 'U_LEGIT_ERROR' | 'U_LEGIT_COMPLETION' | 'U_META_SELF_REFERENCE';
export type EscalateRule = 'U_AMBIGUOUS_INSUFFICIENT_SIGNAL';
export type Rule = ContinueRule | AllowRule | EscalateRule;
export declare const CONTINUE_RULES: readonly ContinueRule[];
export declare const ALLOW_RULES: readonly AllowRule[];
export declare const ESCALATE_RULES: readonly EscalateRule[];
export declare const ALL_RULES: ReadonlySet<Rule>;
export declare function isContinueRule(rule: string): rule is ContinueRule;
export declare function isAllowRule(rule: string): rule is AllowRule;
export declare function isEscalateRule(rule: string): rule is EscalateRule;
export interface ArtifactMetadata {
    /** Repo-relative path. */
    path: string;
    /** Git commit SHA that added the file (`introducingCommit`). */
    introducingCommit?: string | null;
    /** Most recent commit SHA that modified the file this session, if any. */
    latestCommit?: string | null;
    /** Whether this artifact was created during the current session. */
    createdThisSession: boolean;
    /** Whether this artifact was modified during the current session. */
    modifiedThisSession: boolean;
}
export interface EvidenceMetadata {
    /** Hook-enumerated, server-collected artifact set. The authority
     *  can ONLY cite values that appear verbatim here. */
    artifacts: ArtifactMetadata[];
    /** Detector signals — which context-preservation phrasings fired. */
    signals: Record<string, boolean>;
    /** SessionStart timestamp in ms. Null if unknown (server was down). */
    sessionStartTs: number | null;
    /** Hint set by the self-reference pre-check when canonical paths were
     *  touched incidentally but did NOT trigger the full exemption. */
    metaSelfReferenceHint?: boolean;
}
export interface UntrustedContent {
    /** The stop-reason text from Claude Code's Stop hook input. */
    stopReason: string;
    /** Last ≤10 conversation turns (user + agent). Treated strictly as data. */
    recentTurns: Array<{
        source: 'user' | 'agent';
        topicId?: string;
        ts?: string;
        text: string;
    }>;
}
export interface EvaluateInput {
    evidenceMetadata: EvidenceMetadata;
    untrustedContent: UntrustedContent;
}
export interface EvidencePointer {
    plan_file?: string;
    plan_commit_sha?: string;
    incremental_commit_sha?: string;
}
export type Decision = 'continue' | 'allow' | 'escalate';
export interface AuthorityResult {
    /** The authority's judgment. */
    decision: Decision;
    /** Enumerated rule id; validated to be in ALL_RULES. */
    rule: Rule;
    /** Evidence pointer — required for `continue`, optional otherwise. */
    evidencePointer: EvidencePointer;
    /** Free-text rationale from the authority (logged only, never sent to agent). */
    rationale: string;
    /** Wall-clock ms for the LLM call. */
    latencyMs: number;
}
export interface GateFailure {
    kind: 'timeout' | 'malformed' | 'invalidRule' | 'invalidEvidence' | 'missingPointer' | 'llmUnavailable' | 'breakerOpen';
    detail: string;
    latencyMs: number;
}
export type AuthorityOutcome = {
    ok: true;
    result: AuthorityResult;
} | {
    ok: false;
    failure: GateFailure;
};
export interface UnjustifiedStopGateConfig {
    intelligence: IntelligenceProvider;
    /** Client-side hard AbortController budget (spec: 2000ms). */
    clientTimeoutMs?: number;
    /** Server-side LLM call budget (spec: 1400ms). */
    llmTimeoutMs?: number;
    /** Max tokens for the response. */
    maxTokens?: number;
    /** Circuit breaker: number of consecutive provider failures (timeout /
     *  llmUnavailable) before the gate stops spawning LLM subprocesses and
     *  fail-opens immediately for a cooldown. Default 3. Set 0 to disable. */
    breakerThreshold?: number;
    /** Circuit breaker cooldown: how long the breaker stays open before the gate
     *  retries the LLM path once (half-open). Default 5 min. */
    breakerCooldownMs?: number;
    /** Injectable clock (for tests). Defaults to Date.now. */
    now?: () => number;
}
/**
 * Evaluate a Stop event. Returns an authority result OR a structured
 * failure that the caller fail-opens on.
 *
 * The caller (`/internal/stop-gate/evaluate` route) is responsible for:
 *   - Self-reference exemption pre-check (short-circuits before this).
 *   - Server-side post-verifier (validates evidence_pointer against
 *     git object DB + filesystem + descendant checks).
 *   - SQLite persistence of decisions + failures.
 *   - Reminder template assembly for `continue` decisions.
 *   - Kill-switch / mode=off short-circuit.
 */
export declare class UnjustifiedStopGate {
    private config;
    /** Circuit-breaker state: consecutive provider failures + open-until clock. */
    private consecutiveProviderFailures;
    private breakerOpenUntil;
    constructor(config: UnjustifiedStopGateConfig);
    /** Breaker telemetry (for /health + tests). open=true ⇒ short-circuiting. */
    breakerState(): {
        open: boolean;
        consecutiveFailures: number;
        openUntil: number;
    };
    /** Record a completed LLM response (provider reachable): reset the breaker. */
    private onProviderReachable;
    /** Record a provider failure (timeout/unavailable); open the breaker at threshold. */
    private onProviderFailure;
    evaluate(input: EvaluateInput): Promise<AuthorityOutcome>;
    private callWithTimeout;
    private validateResponse;
}
export declare function assembleReminder(rule: Rule, pointer: EvidencePointer): string;
//# sourceMappingURL=UnjustifiedStopGate.d.ts.map