/** * The `pin` arm — the non-destructive escape hatch (plan § 3): probe the LIVE * value of each offending property from its owning service and emit an * edit-ready codemod into the user's fjall config so the diff disappears. * Degrades to report-only carrying the exact config line whenever any step * cannot complete confidently — never a partial edit (the * `restoreAndReconcileQuarantinedBucket` reconcile doctrine). The codemod is * OFFERED to the caller (Q6): this module only computes `modifiedContent`; * the surface that owns the config file decides to write it. * * v1 probe table: RDS DBInstance/DBCluster `Port`. Every other * (resourceType, property) pair degrades honestly to `no-probe-support` * naming the pair. * * Failure messages are pre-masked at construction. */ import type { AwsProvider } from "../../aws/AwsProvider.js"; export interface PinTarget { stack: string; logicalId: string; resourceType: string; /** Ticket `physicalName` — a pinned literal, or the shared placeholder * shape (`remediationPlaceholderPhysicalId`) for unpinned rows. */ physicalName: string; /** Offending property paths from the ticket row (bare names or * `/properties/`-prefixed pointers). */ offendingProperties: readonly string[]; } /** One probed live value plus the exact config line that pins it. */ export interface PinnedProperty { /** CloudFormation property name (e.g. "Port"). */ property: string; /** fjall config property the codemod writes (e.g. "port"). */ configProperty: string; liveValue: string | number; /** The exact config line for manual application (e.g. `port: 5433`). */ configLine: string; } export type PinReportOnlyReason = "no-probe-support" | "physical-id-unresolved" | "probe-failed" | "no-infrastructure-content" | "unresolved-construct" | "edit-failed" /** The codemod was a byte-identical no-op — the config already carries the * probed value(s), so claiming an edit would loop the deploy forever. */ | "already-pinned"; interface PinTargetIdentity { stack: string; logicalId: string; resourceType: string; physicalName: string; } export type PinResourceOutcome = (PinTargetIdentity & { outcome: "edit-ready"; /** The construct symbol the codemod edited. */ constructName: string; pinned: PinnedProperty[]; }) | (PinTargetIdentity & { outcome: "report-only"; reason: PinReportOnlyReason; /** Pre-masked human detail (unsupported pairs, probe error, edit error). */ detail?: string; /** Probed values that WERE resolved — the exact config lines the * operator can apply by hand even though no edit was emitted. */ pinned?: PinnedProperty[]; /** Candidate construct names on ambiguous resolution. */ candidates?: string[]; }); export interface PinRemediationReport { outcomes: PinResourceOutcome[]; /** The config content with EVERY edit-ready outcome applied, present iff * at least one target reached edit-ready. Later targets compose on top of * earlier edits. */ modifiedContent?: string; /** The exact source snapshot the edits were composed against — present iff * `modifiedContent` is. The write-back owner MUST verify the file on disk * still matches this snapshot before replacing it wholesale: the consent * ceremony can sit for minutes, and a whole-file write composed from a * stale read silently reverts a concurrent user edit (lost update). */ sourceContent?: string; } export interface PinProbeCoverage { /** True iff EVERY offending property has a live-value probe. */ covered: boolean; /** The `#` pairs without a probe (all pairs when * no offending properties were recorded — nothing is probeable). */ unsupportedPairs: string[]; } /** * Whether the v1 probe table can execute a pin for this resource. The * destruction gate consults this BEFORE accepting a `pin` consent — declaring * the verb executable and then degrading every target to report-only * (no-probe-support) would stop the deploy for a write-back that can never * happen. */ export declare function pinProbeCoverage(resourceType: string, offendingProperties: readonly string[]): PinProbeCoverage; /** * One-line detail for a pin outcome (everything after the physical name). * Shared by `renderPinReportLines` and the CLI's labelled row rendering so * both surfaces stay byte-identical. Identifier-only plus pre-masked details * — safe for any sink. */ export declare function formatPinOutcomeDetail(outcome: PinResourceOutcome): string; /** * Render the per-resource pin outcome lines every surface shares (engine * callbacks, CLI human output, agent output). */ export declare function renderPinReportLines(report: PinRemediationReport): string[]; export interface RunPinRemediationParams { targets: readonly PinTarget[]; /** The user's infrastructure config source. Absent (worker surfaces with * no config checkout) degrades every target to report-only with the exact * config lines. */ infrastructureContent?: string; /** Display path for codemod diagnostics. */ infrastructureFilePath?: string; abortSignal?: AbortSignal; } /** * Run the pin arm over consented targets. Never throws; every failure mode * is an in-band report-only outcome (pre-masked at construction). Outcomes * may be fewer than targets when the abort signal fires mid-loop. */ export declare function runPinRemediation(aws: AwsProvider, params: RunPinRemediationParams): Promise; export {};