/**
 * The run loop's CLOCK and LIMIT machinery — the pieces that turn a budget, a deadline or a ceiling into
 * something a lane can act on, shared by the turn boundary, the run body and the end-of-task lane:
 *  · the limit-approach frames (budget-measured, advisory) and the turn-cap read;
 *  · the governance-read budget against the environment's suspend deadline, the chunked absolute-deadline
 *    race that enforces it, and the never-abandoned ledger charge with its slow-settle disclosure;
 *  · the typed terminal for an external stop cause that could not be suspended durably;
 *  · the once-per-task disclosure of an auto-compaction trigger that cannot be evaluated (a WeakSet keyed
 *    on the task's `Prepared`, so the latch dies with the task and never touches the contract surface);
 *  · the hard walltime backstop timer, chunked past the largest delay a timer honours.
 *
 * Every clock read is `Date.now()` or a timer; every host read is through the arguments a caller hands in.
 * Layer-1 machinery rather than a driven lane — initial-run-state.ts says why no run-loop machinery module
 * wears a family prefix.
 */
import { type AgentHarness } from "../../internal/harness.js";
import type { PlatformLimitReason } from "../checkpoint-store.js";
import type { TaskSpec } from "../types.js";
import type { Prepared } from "./contracts.js";
/**
 * The LIMIT-APPROACH frames, the successor to the retired deadline-nudge family. Two facts
 * make them a different mechanism, not a rename:
 *  - they are measured in BUDGET (the tightest armed axis's fill ratio), not in wall-clock, so they need
 *    no throughput estimate and cannot mis-fire on a starved event loop;
 *  - they are ADVISORY. Neither frame stops anything; the run ends when a ceiling is actually crossed.
 *
 * Rendered by {@link limitApproachFrames}; registered in the prompt-assembly event registry under
 * `limit_approach_converge` / `limit_approach_deliver`.
 */
export declare const LIMIT_APPROACH_DEFAULT_THRESHOLDS: readonly [number, number];
/** The output-token figure the pre-call worst-case assumes when the model declares no cap of its own.
 *  Shared by the $ and token arms so the two gates cannot disagree about the same hypothetical call. */
export declare const DEFAULT_PRECALL_OUTPUT_TOKENS = 4096;
/** The two frame bodies, indexed by how many have already been sent (0 → converge, 1 → deliver now). */
export declare function limitApproachFrames(index: 0 | 1, axis: string, percent: number, mark: string | undefined): string;
/**
 * Resolve the effective turn cap. `undefined` = no turn cap; `0` (explicit) = unbounded.
 *
 * This is now a pure read of what the caller wrote. The two clauses it used to carry —
 * "a wall-clock bound was set, so drop the turn cap" and "neither was set, so apply the engine's
 * safety net" — are both gone: the axes no longer interact (each binds on its own), and there is no
 * engine-side net to apply. A task with no `maxTurns` has no turn ceiling.
 */
export declare function resolveMaxTurns(limits?: {
    maxTurns?: number;
}): number | undefined;
/**
 * How long past the environment's suspend deadline the turn-boundary lane will keep waiting for the
 * usage ledger's READ.
 *
 * The precedence ruling (usage_window > env_lifetime) means the ledger must be read BEFORE the env
 * cause can be adopted — you cannot rank a cause you have not read. But that read is store I/O with no
 * bound of its own, and past this instant every millisecond it spends is spent out of the margin that
 * exists to mint the env checkpoint. A stalled ledger must not cost a deployment the checkpoint it
 * could still have had, so the read runs against an ABSOLUTE deadline (`envLifetimeSuspendAt + this`)
 * and a run that gets no answer by then stops for the cause it can still prove.
 *
 * 5s against the 60s suspend margin: two orders of magnitude above any healthy ledger read (in-memory
 * and file stores answer in ms; a remote one in tens of ms), and it still leaves 55s — more than the
 * margin was sized for — to pause the workspace, mint the checkpoint and commit it. Not a knob: it is a
 * fraction of an engine constant, and a deployment that wants a wider band declares a shorter lifetime.
 *
 * ABSOLUTE, never a fresh per-boundary allowance: a boundary that finds the deadline one millisecond
 * away must not hand a stalled ledger the whole margin, and a boundary that is already overdue must get
 * LESS than the budget, not the same. {@link raceUntilDeadline} is what keeps that true for a deadline
 * of any distance, without an unrepresentable timer.
 */
export declare const ENV_DUE_GOVERNANCE_READ_BUDGET_MS = 5000;
export declare const GOVERNANCE_READ_STALLED: unique symbol;
/** Await a ledger charge, firing `onSlow` ONCE if it has not settled after
 *  {@link CHARGE_SETTLE_DISCLOSE_MS}. The charge itself is always awaited to completion. */
export declare function awaitChargeWithSlowDisclosure<T>(charge: Promise<T>, onSlow: () => void, discloseAfterMs?: number): Promise<T>;
/**
 * Await `p` until the absolute epoch `deadline`, then give up with {@link GOVERNANCE_READ_STALLED}.
 *
 * Chunked, and deliberately so: the deadline is derived from a caller-declared environment lifetime, so
 * the distance to it can exceed {@link MAX_TIMER_DELAY_MS} — a single timer armed for that distance
 * would fire at once and abandon a perfectly healthy read. Each chunk re-reads the wall clock, so the
 * decision is always made against the deadline itself rather than against an allowance computed once.
 *
 * Exported for its own unit pin (the same posture as the brain-call guardrail primitive): the
 * behaviors below are clock behaviors, and only a virtual clock can assert them without spending the
 * wall-clock time they describe. Not re-exported from the package index.
 *
 * An already-overdue deadline still gets ONE zero-delay pass: a promise that is settled (or settles in a
 * microtask, which is every in-process store) must be allowed to win, because giving up on an answer we
 * already hold would be a fabricated stall. The second pass is what makes the loop terminate.
 */
export declare function raceUntilDeadline<T>(p: Promise<T>, deadline: number): Promise<T | typeof GOVERNANCE_READ_STALLED>;
/**
 * The TYPED terminal for an external stop cause that could NOT be suspended durably.
 * Carried on `rs.limits.platformTerminal` and adopted as the run's `threw`, so the caller reads the cause
 * on `TaskResult.errorCode` (`errorCodeOf` lifts `.code`) instead of the anonymous error an abort produces.
 * `retryAfterMs` rides the error object because a wait hint has no `TaskResult` seat — a host reads it from
 * the `RunnerDeps.onError` sink this is also delivered to.
 */
export declare function platformLimitTerminal(reason: PlatformLimitReason, retryAfterMs: number | undefined, moment?: "entry" | "turn_boundary" | "resume"): Error & {
    code: string;
    retryAfterMs?: number;
};
export declare function discloseUnevaluableWindow(u: {
    estTokens: number;
    windowField: string;
    windowValue?: number;
    modelId?: string;
}, prepared: Prepared, tracer: TaskSpec["tracer"], taskId: string, onError: ((err: unknown, context: {
    phase: "config";
    sessionId: string;
}) => void) | undefined): void;
/** 1.296 件2a — report the hard-abort timer's lateness on `task.end` only above this bar: sub-5s
 *  jitter is ordinary scheduling noise (GC pauses, sync work) and would only add trace lint. */
export declare const TIMER_LATENESS_REPORT_MS = 5000;
export declare function startTimeout(harness: AgentHarness, abortController: AbortController, remainingMs?: number, softSuspendable?: boolean): {
    fired: boolean;
    latenessMs?: number;
    clear: () => void;
};
