/**
 * design/125 — **SpecContract**:spec→Verifier 闭环的机器可读任务契约(make-real 两周实战纪律的
 * 一等原语化)。本模块 = 纯 core 零件:契约类型 + 三值 oracle 执行器 + frozenPaths 校验/快照/恢复。
 * 装配(policy 组合、stop 把关、outcome 发射)在 `orchestration/run-spec.ts`。
 *
 * 🔴 **信任声明(fable-M3)**:SpecContract 是 **CODE-tier** 输入 —— `oracle[].cmd` 会被亲跑(execFile,
 * 任意命令)。它只能来自部署作者/可信代码路径;LLM 生成的 contract 直接喂 runSpec = 不受信输入获得
 * 命令执行权(越红线),禁止。contract 里的 `spec` **文本**才是 DATA-tier(runSpec 恒围栏置入 objective)。
 * 命令可信 ≠ 它跑的代码可信:门跑的测试会加载模型改过的代码,故门子进程的环境缺省经 `scrubSecretEnv`
 * (`OracleGateSpec.inheritEnv`,与 tool shell 同一三态),凭据名只在部署显式列名 / `"all"` 时交给它;
 * 部署声明的自有凭据名(`declareWithheldEnv`)在任一形下都不交。
 *
 * 🔴 **oracle 三值(fable-M6)**:每门结果 ∈ {green, red, error} —— 判据不满足 = red;基础设施故障
 * (ENOENT/timeout/maxBuffer/parse 解析不出)= **error 非 red**。假红防线:error 绝不冒充"曾经红过"
 * (design/73 红线② 的机器化 —— `oracleHadRedRun` 只由真 red 观察置位)。
 */
import type { EngineNotice } from "./engine-notice.js";
/** Declarative green criteria for one oracle gate. Absent ⇒ `exitCode === 0`. All declared criteria AND. */
export interface OracleGreenSpec {
    /** Expected exit code. Default 0 when no `parse` is declared; with `parse`, exit code is only
     *  checked when explicitly set here (test runners exit non-zero on failures the counts already judge). */
    exitCode?: number;
    /** Regex (source string) that MUST match the combined stdout+stderr. */
    mustMatch?: string;
    /** Regex (source string) that MUST NOT match the combined stdout+stderr. */
    mustNotMatch?: string;
    /**
     * Parsing criteria (fable-M5/B1 一体解): extract pass/fail counts from the output. Each regex's FIRST
     * capture group is the integer count (e.g. `"ℹ pass (\\d+)"`). Either regex failing to match = the gate
     * is **error** (解析不出 ≠ red — a runner that printed nothing proves nothing).
     */
    parse?: {
        passRe: string;
        failRe: string;
    };
    /**
     * Lower bound on the parsed pass count (requires `parse`). `"baseline"` = the pass+fail TOTAL this gate
     * observed at preflight — the anti-「测试消失式走捷径」 gate (the model leaves tests untouched but makes
     * them undiscovered; harness :114 实战门, fable-B1). Numeric default when absent: 1 (a zero-test green
     * is vacuous).
     */
    minPass?: number | "baseline";
}
/** One mechanical adjudicator: a command run via execFile (NO shell) + declarative green criteria. */
export interface OracleGateSpec {
    /** Stable gate name (baseline capture and per-gate reporting key on it). */
    name: string;
    /** argv — `cmd[0]` is the executable, the rest are arguments. execFile, never a shell. */
    cmd: string[];
    /** Working directory, containment-checked against the runSpec root (same rule as frozenPaths). */
    cwd?: string;
    /** Per-gate timeout. Default 60s. */
    timeoutMs?: number;
    green?: OracleGreenSpec;
    /**
     * How much of the engine's environment the gate's command inherits — the tool shell's `inheritEnv`, read the same
     * way. Absent / `"scrub"`: the environment without its credential-shaped variables (`scrubSecretEnv`); the command
     * runs code the model wrote, so the credentials are not handed to it by default. `"all"`: the whole environment.
     * A list: exactly the named variables that are set (a strict allow list — `PATH` too, when the command is looked
     * up on it). Under every form, the deployment's declared own credentials (`declareWithheldEnv`) are withheld, and a
     * list naming one makes the gate `error`. Names only, never values: the contract is serializable data. A value of
     * any other shape makes the gate `error`.
     */
    inheritEnv?: "all" | "scrub" | string[];
}
/** design/125 D1 — the machine-readable task contract (CODE-tier input; see module doc). */
export interface SpecContract {
    /** Task spec text (or a file reference resolved against the runSpec root). runSpec owns the objective
     *  framing; the spec text itself is DATA-tier and is ALWAYS fenced before injection. */
    spec: string | {
        path: string;
    };
    /**
     * Read-only specification surface. **Validation (fable-M2)**: absolute paths and `..` segments are
     * rejected; paths resolve against the runSpec root with a containment check; policy matching uses the
     * RESOLVED path. Exact paths, no globs (v1 收窄).
     */
    frozenPaths: string[];
    /** Mechanical adjudicators (serializable, checkpointable, service-boundary-safe, feed-recordable). */
    oracle: OracleGateSpec[];
    /**
     * 双向验证: preflight runs the full oracle and REQUIRES red (proves the spec has substance), capturing
     * baseline counts for `minPass:"baseline"` (fable-B1: the red gate and the baseline are two faces of the
     * same preflight). Default **true** (the discipline is the default; opting out must be explicit).
     * `{ exempt }` documents WHY this contract legitimately starts green (e.g. pure-refactor spec).
     */
    requireRedStart?: boolean | {
        exempt: string;
    };
    /** design/73 aggregation key. Default: `spec:<sha256(specText) first 16 hex>`. */
    taskSignature?: string;
}
/** Three-value gate verdict — `error` = the adjudicator itself failed to run/parse (NEVER counts as red). */
export type OracleVerdict = "green" | "red" | "error";
export interface OracleGateResult {
    name: string;
    verdict: OracleVerdict;
    /** Process exit code (null when the process did not run/complete — spawn error or timeout kill). */
    exitCode: number | null;
    /** Parsed counts when `green.parse` was declared and both regexes matched. */
    pass?: number;
    fail?: number;
    /** Which criterion failed / what the infrastructure error was (first-party classification string). */
    reason?: string;
    /** Tail of the combined stdout+stderr (UNTRUSTED — the model can influence it via the code under test;
     *  fence with `delimitUntrusted` before any model-facing use). */
    outputTail: string;
}
/** Per-gate preflight counts backing `minPass:"baseline"` (keyed by gate name). */
export type OracleBaseline = Record<string, {
    pass: number;
    fail: number;
}>;
export interface OracleRunReport {
    /** Worst-across-gates: any `error` ⇒ error (fail-loud dominates); else any `red` ⇒ red; else green. */
    verdict: OracleVerdict;
    gates: OracleGateResult[];
}
/**
 * Run every gate of the contract's oracle (sequentially — gates commonly share a working tree) and fold
 * the three-value verdicts: any `error` ⇒ `error` (fail-loud dominates; an unfalsifiable adjudication must
 * never pass silently), else any `red` ⇒ `red`, else `green`.
 *
 * `cwdRoot` is the runSpec root: each gate's `cwd` resolves against it with the same containment rule as
 * frozenPaths (a contract cannot point its adjudicator outside the workcopy).
 */
export declare function runOracle(gates: OracleGateSpec[], cwdRoot: string, opts?: {
    baseline?: OracleBaseline;
    signal?: AbortSignal;
    /** Receives the once-per-process `config.secret_env_scrubbed` notice when a gate's scrub withholds names (the
     *  tool shell's seat and latch); absent ⇒ the console line. */
    onNotice?: (notice: EngineNotice) => void;
}): Promise<OracleRunReport>;
/** Extract the per-gate baseline counts from a (preflight) report — only gates whose parse succeeded. */
export declare function captureBaseline(report: OracleRunReport): OracleBaseline;
/** A coded error (`config.*` / `spec.*` convention — same shape as goal.ts's reserved-name fail-fast). */
export declare function specError(code: string, message: string): Error & {
    code: string;
};
/**
 * Validate and resolve `frozenPaths` against the runSpec root (fable-M2): absolute paths and `..`
 * segments are rejected outright (`spec.frozen_path_invalid`); the resolved path must stay inside the
 * root. Returns resolved absolute paths (the ONLY form policy matching and snapshots use).
 */
export declare function resolveFrozenPaths(rootDir: string, frozenPaths: string[]): string[];
/**
 * Byte-level snapshot of the frozen surface (fable-M1: a hash can only DETECT tampering — restoring needs
 * the CONTENT, and the snapshot is the restore source; no external seed directory dependency). Missing
 * file ⇒ `spec.frozen_missing` (a frozen path that doesn't exist can't be a specification).
 */
export declare function snapshotFrozenPaths(resolvedPaths: string[]): Map<string, Buffer>;
/**
 * Restore any frozen file whose on-disk bytes differ from the snapshot (belt for `echo > test/x`-style
 * bash writes the Write/Edit deny policy cannot see — fable-MIN2). Returns the number of files restored.
 *
 * Symlink-safe (实现审 B2): a tampered entry that is no longer a regular file (the model swapped
 * it for a symlink pointing outside the root) is REMOVED first — the snapshot bytes are then written to
 * a fresh regular file, never THROUGH a link. When `rootDir` is given, the parent directory's physical
 * path is containment-checked too (a symlinked PARENT dir would also carry the write outside); an entry
 * whose parent escapes is skipped (counted) — the terminal oracle then adjudicates the missing spec
 * files honestly (fail-safe direction) instead of runSpec writing outside its root.
 */
export declare function restoreFrozenPaths(snapshot: Map<string, Buffer>, rootDir?: string): number;
