/** * [G2] Stateless drift pre-flight (drift-remediation plan § Phase 5). * Before the cdk spawn, each stack about to deploy is checked for the Class 1 * wedge: a stack in a failed/rolled-back status, or one carrying journalled * suspects, is probed (bounded); a CONFIRMED out-of-band deletion blocks the * deploy with a named finding — the deploy would only re-wedge. * * Statelessness: the trigger reads live stack status, so a fresh machine with * an empty journal still catches the wedge. Deviation from the plan text * recorded in the Phase 5 report: the plan assumed the active-deployment * guard's DescribeStacks already ran on the deploy path — it is destroy-only, * so this pre-flight issues ONE `getStackStatus` (DescribeStacks) per stack * to deploy. Healthy stacks with an empty journal pay nothing further. * * Fail-open on probe infrastructure errors: only `confirmed-deleted` blocks; * unconfirmed findings surface as warnings and the deploy proceeds. */ import { type Result } from "@fjall/generator"; import type { CloudFormationService } from "../../services/infrastructure/CloudFormationService.js"; import type { DriftFinding } from "../../types/drift.js"; import { type DetectStackDriftDeps } from "./detectStackDrift.js"; /** * Stack statuses that evidence a possibly-wedged last operation. Narrow by * design: rollback-complete and update-failed are where the BC wedge lands; * rollback-failed is the same class one step worse. IN_PROGRESS states are * the active-deployment guard's concern, not drift's. */ export declare const DRIFT_PREFLIGHT_TRIGGER_STATUSES: ReadonlySet; /** Bounds the whole pre-flight so a slow probe cannot stall the deploy. */ export declare const DRIFT_PREFLIGHT_BUDGET_MS = 90000; export interface RunDriftPreFlightParams { stackNames: readonly string[]; cfnService: Pick; abortSignal?: AbortSignal; budgetMs?: number; } export interface DriftPreFlightOutcome { confirmed: DriftFinding[]; unconfirmed: DriftFinding[]; /** Stacks whose status or journal triggered a probe. */ probedStacks: string[]; } export declare function runDriftPreFlight(deps: DetectStackDriftDeps, params: RunDriftPreFlightParams): Promise>; export interface DriftPreFlightBlockExtras { /** Journal says flip-applied but the live template VERIFIABLY no longer * carries the flip — surgery must re-run before deploying. */ flipNotLive?: ReadonlyArray<{ finding: DriftFinding; opId: string; }>; /** The live template could not be read, so the flip's liveness is * unverifiable — the cure is retrying the deploy, not re-running repair. * `message` is pre-masked at construction. */ flipUnverified?: ReadonlyArray<{ finding: DriftFinding; opId: string; message: string; }>; /** Flip is live but the deploy's synth still declares the target — this * deploy is not the converge. */ stillDeclared?: ReadonlyArray<{ finding: DriftFinding; opId: string; }>; } /** * Compose the blocking failure message for confirmed pre-flight findings. * `inProgressOpIds` names forget operations that cover blocked findings but * have not yet applied the Retain flip — the cure is resuming them, not * deploying ([G2] × remediation-journal interaction). `extras` carries the * partition's suppression-refused buckets, each with its own cure. */ export declare function formatDriftPreFlightBlock(confirmed: readonly DriftFinding[], inProgressOpIds?: readonly string[], extras?: DriftPreFlightBlockExtras): string;