/**
 * Pure, testable logic extracted from VerificationHarness.
 *
 * These functions contain no I/O, no class state, and no side-effects —
 * they operate only on their arguments and return deterministic results.
 */
import type { GateSignal, GateSignalStep } from "./gate-store.js";
import type { VerifyStep } from "./workflow-store.js";
/**
 * Literal substring patterns that indicate a transient/infrastructure failure
 * worth retrying. Matched via `output.includes(pattern)`.
 *
 * For LLM streaming/tool-argument glitches (malformed JSON from
 * `input_json_delta` accumulation, schema-validation failures), prefer the
 * regex list `TRANSIENT_ERROR_REGEXES` below — it catches every V8/Node
 * `SyntaxError` variant in one place instead of chasing new substrings as
 * they're discovered.
 */
export declare const TRANSIENT_ERROR_PATTERNS: string[];
/**
 * Regex patterns that indicate a provider overload / rate-limit / quota
 * throttle. Distinct from the JSON-glitch regexes — these warrant
 * effectively unbounded retry with long backoff rather than a bounded
 * burst of 3 attempts.
 */
export declare const PROVIDER_BACKOFF_REGEXES: RegExp[];
/**
 * Regex patterns for LLM streaming / tool-argument JSON glitches.
 *
 * Fresh runs of these almost always succeed — the model's streamed
 * `input_json_delta` just accumulated into something that didn't parse. We
 * treat the whole V8/Node `SyntaxError` family, plus pi-ai's wrapper
 * messages, as one class. `maxAttempts` caps blast radius if a model is
 * reliably broken.
 *
 * Known concrete variants this covers:
 *   - "Expected ',' or '}' after property value in JSON at position 320"
 *   - "Expected double-quoted property name in JSON at position 42"
 *   - "Expected property name or '}' in JSON at position 1"
 *   - "Unexpected token 'x', \"...\" is not valid JSON"
 *   - "Unexpected character ... in JSON at position 5"
 *   - "Unexpected end of JSON input"
 *   - "Unexpected end of input while parsing JSON"
 *   - "Unexpected non-whitespace character after JSON at position ..."
 *   - anything else ending in "in JSON at position <n>"
 */
export declare const TRANSIENT_ERROR_REGEXES: RegExp[];
/**
 * Return the matched JSON/validation error substring (roughly one line of
 * context around the match) if `output` looks like an LLM tool-argument
 * glitch, otherwise null. Used to craft a targeted retry prompt.
 */
export declare function detectJsonValidationError(output: string): string | null;
/**
 * Patterns that are transient for LLM reviews but NOT for agent-qa steps.
 * "Agent did not call verification_result" means the agent burned its budget
 * without producing results — retrying will just waste more time/cost.
 */
export declare const QA_NON_TRANSIENT_PATTERNS: string[];
/** Check if an LLM review error output matches a transient failure pattern. */
export declare function isTransientReviewError(output: string): boolean;
/**
 * Narrow classifier for provider overload / rate-limit / quota throttle
 * conditions that warrant an effectively unbounded retry with long backoff
 * (capped at 5 min) rather than the default bounded 3-attempt policy.
 *
 * `isTransientReviewError()` returns true for these too — they are
 * transient — but SessionManager uses this narrower check to pick the
 * unbounded policy.
 */
export declare function isProviderBackoffError(output: string): boolean;
/** Check if an agent-qa error output matches a transient failure pattern (stricter than LLM reviews). */
export declare function isTransientQaError(output: string): boolean;
/**
 * A workflow gate is "pre-implementation" iff it is a content gate with no
 * upstream dependencies — meaning nothing it reviews has been produced yet,
 * and the branch cannot contain code satisfying this gate.
 *
 * Derived purely from workflow topology to avoid drift with an explicit
 * `kind` field. See design doc §3.1.
 */
export declare function isPreImplementationGate(gate: {
    content?: boolean;
    depends_on?: string[];
    dependsOn?: string[];
}): boolean;
/**
 * Substitute namespaced variables in a template string.
 *
 * Namespaces:
 * - {{branch}}, {{master}}, etc. — built-in goal variables
 * - {{agent.key}} — from the signal's metadata (provided by the agent)
 * - {{gate_id.meta.key}} — from an upstream gate's metadata
 * - {{goal_spec}} — the goal specification text
 *
 * Phase 2 of the multi-repo design dropped support for `{{project.X}}`
 * tokens — their replacement is the structural `{ component, command }`
 * step shape resolved at runtime by `verification-harness.resolveStep()`.
 * The `projectVars` parameter is retained for back-compat at the call site
 * but is no longer consulted; passing it has no effect.
 *
 * Legacy bare references like {{typecheck_command}} are NOT resolved to
 * prevent accidental cross-namespace collisions. Use the explicit namespace.
 */
export declare function substituteVars(template: string, builtinVars: Record<string, string>, _projectVars: Record<string, string>, agentVars: Record<string, string>, allGateStates?: Map<string, {
    metadata?: Record<string, string>;
    content?: string;
    status?: string;
    injectDownstream?: boolean;
}>): string;
/**
 * Decide whether a command step should be auto-skipped based on its resolved
 * `run` string (after template substitution).
 *
 * Returns a human-readable skip reason if the step should be skipped, or null
 * if it should execute normally.
 *
 * A step is skippable when:
 * - The resolved run string is empty or whitespace-only
 * - The resolved run string still contains an unresolved `{{...}}` template
 *   variable — typically because the referenced project/agent config key is
 *   not set (e.g. `{{project.build_command}}` for a project that doesn't
 *   define a build command).
 *
 * This lets workflows declare optional infrastructure steps (build, lint,
 * custom commands) that gracefully skip-as-passed for projects that don't
 * configure them, rather than failing the gate.
 */
export declare function isCommandStepSkippable(resolvedCmd: string): string | null;
/**
 * Evaluate whether a command step with `expect: failure` passed or failed.
 *
 * Rules:
 * - If exitCode === 0: the command was expected to fail but succeeded → fail
 * - If no errorPattern provided: fail (pattern is required for expect:failure gates)
 * - If errorPattern is an invalid regex: fail with regex error
 * - If output matches errorPattern (case-insensitive): pass
 * - If output does not match: fail
 */
export declare function matchExpectFailure(exitCode: number | null, output: string, errorPattern?: string): {
    passed: boolean;
    output: string;
};
export interface PhaseGroup {
    step: VerifyStep;
    index: number;
}
/**
 * Group active steps by their phase number (defaulting to 0).
 * The `index` in each PhaseGroup refers to the step's position in `allSteps`
 * (the full list including optional steps), so that broadcast events reference
 * the correct original indices.
 */
export declare function groupStepsByPhase(activeSteps: VerifyStep[], allSteps: VerifyStep[]): Map<number, PhaseGroup[]>;
/** Return phase numbers sorted ascending. */
export declare function getSortedPhases(groups: Map<number, unknown[]>): number[];
/**
 * Partition verify steps into active (will run) and skipped (optional but not
 * enabled for this goal).
 *
 * Returns:
 * - `active`: steps that should be executed
 * - `skippedIndices`: original indices of steps that were skipped
 */
export declare function partitionOptionalSteps(steps: VerifyStep[], enabledOptionalSteps: string[]): {
    active: VerifyStep[];
    skippedIndices: number[];
};
/**
 * Build a cache of previously-passed verification steps from earlier signals
 * that share the same commit SHA.
 *
 * Only steps with `passed: true` from completed (non-running) verifications
 * are cached. The current signal is excluded from the search. When a reset
 * invalidation timestamp is provided, signals at or before that boundary are
 * excluded so audit history remains intact without making stale results
 * cache-eligible.
 *
 * `human-signoff` steps are **always excluded** — a prior approval is not
 * consent for a re-signal. Humans must re-confirm any time the gate is
 * re-signalled, even when the commit SHA hasn't changed. This was the
 * Bug-1 defense-in-depth fix in the "Re-attempt: Sign-Off Gates" goal:
 * without this filter, a single approval at SHA X would silently satisfy
 * every subsequent re-signal at the same SHA.
 */
export declare function buildStepCache(signals: GateSignal[], currentSignalId: string, commitSha?: string, verificationCacheInvalidatedAt?: number): Map<string, GateSignalStep>;
/**
 * Check whether every active step already has a cached result, meaning we can
 * skip spawning any agents and resolve the verification entirely from cache.
 */
export declare function canSkipAllSteps(cache: Map<string, GateSignalStep>, activeSteps: VerifyStep[]): boolean;
/**
 * Determine whether all verification steps passed.
 *
 * Steps that were skipped (e.g. because an earlier phase failed, or because
 * they are disabled optional steps) are excluded from the pass/fail decision.
 * The actually-failed step in the earlier phase is what causes the gate to
 * fail — the downstream skipped steps should not pile on as additional
 * failures.
 */
export declare function computeAllPassed(results: GateSignalStep[]): boolean;
//# sourceMappingURL=verification-logic.d.ts.map