import { type S3Client } from "@aws-sdk/client-s3"; import { type Result } from "@fjall/generator"; import { ORG_TRAIL_BUCKET_OUTPUT_KEY, TRAIL_BUCKET_OUTPUT_KEY, TRAIL_KEY_ARN_OUTPUT_KEY, type ProviderAccount, type TrailLifecycleState } from "@fjall/util/config"; import { type DecommissionClients, type DecommissionOutcome } from "./memberTrailCleanup.js"; import type { DeployCallbacks } from "../../types/callbacks.js"; export { ORG_TRAIL_BUCKET_OUTPUT_KEY, TRAIL_BUCKET_OUTPUT_KEY, TRAIL_KEY_ARN_OUTPUT_KEY }; export interface MemberTrailFacts { /** * Org-trail delivery verified for this account. `undefined` = could not be * determined (probe failed or recency scan truncated) — never advance on it. */ orgDeliveryVerified?: boolean; /** Outcome of this run's decommission attempt (draining accounts only). */ decommissionOutcome?: DecommissionOutcome["outcome"] | "failed"; } export type TrailMigrationTransition = { action: "advance"; to: TrailLifecycleState; } | { action: "hold"; reason: string; }; /** * Pure transition truth table for the org-trail migration. Uncertainty never * advances state: a probe that failed or could not complete holds the account * where it is and reports why. */ export declare function decideNextTransition(state: TrailLifecycleState | undefined, facts: MemberTrailFacts): TrailMigrationTransition; export interface TrailMigrationDeps { /** Management-account S3 client — the org trail bucket lives there. */ managementS3Client: S3Client; /** Assume the member role and build the decommission clients. */ getMemberClients: (account: ProviderAccount, region: string) => Promise>; } export interface TrailMigrationInput { orgId: string; orgTrailBucketName: string; /** Cascade-deployed accounts (platform + members). */ accounts: ProviderAccount[]; /** accountId → home-region stack outputs captured by this run's cascade. */ cascadeOutputs: Map>; defaultRegion: string; recencyWindowMs?: number; abortSignal?: AbortSignal; } export interface TrailMigrationOutcome { accountId: string; accountName: string; from: TrailLifecycleState | undefined; /** Set only when the account advanced this run. */ to?: TrailLifecycleState; heldReason?: string; } /** * Reconcile every cascade account's trail lifecycle against AWS ground truth. * Two-invocation convergence by design: deploy N creates the org trail * (overlap with member trails is sanctioned for up to a day), deploy N+1's * cheap probes advance states. Facts are re-derived from AWS on every run — * the persisted lifecycle is an intent cache, so lost persistence self-heals. * * Never throws and never fails the deploy: every problem is reported through * callbacks and the account simply holds its current state. */ export declare function reconcileTrailMigration(deps: TrailMigrationDeps, input: TrailMigrationInput, callbacks: DeployCallbacks): Promise;