/**
 * scan-limits.ts — hard resource caps for the customer-side `ai-governance scan`.
 *
 * The scan walks a customer's repository and reads + analyses every source
 * file. Without bounds, pointing it at a pathological tree (millions of files,
 * a multi-GB generated file, a single minified line) could spike CPU / memory
 * on the customer's machine. That violates the product's core promise that
 * nothing we ship can burden client infrastructure (Locked Invariants 2 + 10;
 * Thomas 2026-05-30: "cant allow that for clients").
 *
 * Every walk shares one ScanBudget. It enforces:
 *   - a wall-clock deadline (the scan is bounded in time, never runs away),
 *   - a max visited-file count,
 *   - a max recursion depth,
 *   - a per-file byte ceiling (oversize files are skipped, not read — this also
 *     neutralises any ReDoS-on-one-giant-line risk in the signature matcher).
 *
 * Caps are NEVER silent: when one trips, the budget records it and the scan
 * surfaces it in the JSON summary and on stderr (no silent truncation).
 *
 * All limits are overridable via env for power users / tests.
 */
export interface ScanLimits {
    /** Max files visited (read/analysed) before the walk stops. */
    maxFiles: number;
    /** Max directory recursion depth. */
    maxDepth: number;
    /** Files larger than this many bytes are skipped (not read). */
    maxFileBytes: number;
    /** Wall-clock budget in ms for the entire scan. */
    timeBudgetMs: number;
}
export declare function defaultScanLimits(): ScanLimits;
export interface ScanBudgetReport {
    filesVisited: number;
    filesSkippedOversize: number;
    /** Walk stopped early because the file-count cap was reached. */
    truncatedByFileCap: boolean;
    /** Walk stopped early because the wall-clock budget was exhausted. */
    truncatedByTimeBudget: boolean;
    /** At least one directory was not descended because the depth cap was hit. */
    truncatedByDepthCap: boolean;
    /** True when any cap tripped — the scan did not cover the whole tree. */
    capped: boolean;
    limits: ScanLimits;
}
/**
 * Mutable budget shared across a single scan invocation. Cheap, synchronous,
 * no timers — `expired()` is checked against `Date.now()` at each step so the
 * walk self-terminates without any background handle.
 */
export declare class ScanBudget {
    readonly limits: ScanLimits;
    private readonly deadline;
    private filesVisited;
    private filesSkippedOversize;
    private hitFileCap;
    private hitTimeBudget;
    private hitDepthCap;
    constructor(limits?: ScanLimits, now?: number);
    /** True once the wall-clock budget is exhausted. */
    expired(now?: number): boolean;
    /**
     * Returns true while the walk may keep descending/visiting. Returns false
     * (and latches the matching cap flag) once the file-count cap or the time
     * budget is hit. Callers must stop walking when this returns false.
     */
    canContinue(now?: number): boolean;
    /** True if `depth` is within the recursion cap; records the cap otherwise. */
    withinDepth(depth: number): boolean;
    /**
     * Returns true if a file of `bytes` is small enough to read. Records an
     * oversize skip and returns false otherwise.
     */
    allowFileSize(bytes: number): boolean;
    /** Count one visited (read/analysed) file. */
    countVisit(): void;
    report(): ScanBudgetReport;
}
//# sourceMappingURL=scan-limits.d.ts.map