Skip to main content

The destruction gate

Every application deploy computes a resource-level change plan before it mutates anything. If that plan would destroy, rename or replace a stateful resource, the deploy stops at an unconditional gate and nothing is applied. There is no blanket override:
No blanket flag exists. --auto-approve, --skip-confirmation, --force and approval tokens never satisfy this gate.
Consent is per resource and by exact name. You tell Fjall what to do with each affected resource, and the deploy proceeds only when every one is covered. Stateless changes never stop here. A plain replacement of a stateless resource, or a delete that loses no data, flows through the normal plan and confirmation surfaces.

Findings

A finding classifies why a resource stopped the deploy. Each finding has its own verb vocabulary. Two further findings exist in the shared vocabulary but are never minted by a deploy: The verbs offered column is what menus, tickets and re-run hints actually advertise: the finding’s legal vocabulary filtered to what this release can execute, plus abort. A consent you are offered is a consent that runs.
Resources deleted outside CloudFormation are a different problem with a different tool. The deploy pre-flight blocks with a confirmed finding and points you at fjall drift.

The ticket

When the gate stops a deploy, it prints a ticket naming every affected resource: the finding, the resource type, its stack and logical id, the exact physical name you must consent with, the property change that caused it, and the verbs you may choose.
Every text surface renders these same lines: a withheld fjall deploy, a --plan run, fjall drift repair, the fjall domain commands and fjall org deploy. The text block always closes with ticket digest:, the value --destruction-consent-digest takes. In --agent output the same value arrives as the block’s ticketDigest field. The Ink deploy screen and the web app hold the digest for you and never ask you to pass it, because both consent flows bind the consents themselves. An empty ticket renders nothing at all, digest included.

The verbs

The --remediate help text lists the whole verb vocabulary. Only the verbs printed on your ticket row are accepted for that row. Anything else fails the gate closed with a verdict table.

pin

Offered when the change is safe to accept in place instead of replacing the resource. pin has two arms. Property pin. Probes the live value of the offending property from AWS and writes it back into your application’s infrastructure.ts, so the diff disappears. In this release the live-value probe covers RDS instance and cluster port changes. pin is offered only where the live value can be captured. Identity pin. On a rename-detected row, freezes the deployed capacity identity into capacityIdentity in fjall-config.json so re-synths reproduce the deployed logical ids byte for byte. Either way the deploy then stops (exit code 4) for you to review and commit the config change:
Re-run the deploy without re-supplying the consent. The config edit already satisfied it. Where the automatic edit cannot land, the CLI prints the exact config line to apply by hand instead. Consents you gave for other resources on the same ticket do not run on a pin stop. They re-consent against the recomputed plan on the next deploy, and the CLI says how many were deferred.

recreate

Consents to a new physical resource under the same name.
  • On a plain replacement or a consented delete, CloudFormation performs its native action. Nothing extra is orchestrated.
  • On a custom-named resource, CloudFormation refuses to replace in place, so Fjall runs a surgical removal and the same deploy re-creates the resource under its pinned name. For types that support DeletionPolicy: Snapshot, the removal takes a final snapshot first: DocumentDB clusters, EBS volumes, ElastiCache cache clusters and replication groups, Neptune clusters, RDS clusters and instances, and Redshift clusters. For every other type the data loss is exactly what you consented to.

forget

Stops CloudFormation tracking a resource that no longer exists, without touching anything physical. On a deploy ticket this verb applies to out-of-band deletions, which are remediated through fjall drift repair rather than the deploy itself.

abort and repair

abort declines. The deploy is withheld and nothing is applied. repair is the report-only arm for findings that cannot be safely remediated automatically, so it never appears on a deploy ticket.

Renames

Fjall pairs a delete and a create that are really one resource whose logical identity changed. Deploying such a plan unremediated orphans or deletes the live resource and boots the application against a fresh empty twin. Rename verdicts outrank every other classification, including a resource carrying a Retain policy, because CloudFormation would orphan a retained volume invisibly. rename-detected means the pairing was proved, by the synthesised manifest’s own identity aliases, by the live physical id appearing in the new resource’s properties, by a property digest match, or by being the only candidate pairing in the stack. Consent with pin to weld the deployed identity onto the new slot. pin is offered only when the ticket row carries a slot hint. Without one, only abort is offered, and the cure is to hand-author the capacityIdentity entry in fjall-config.json and validate it with fjall migrate identity. You can also pin a rename before the deploy, outside the consent ceremony:
A deliberate delete-slot-A / create-slot-B swap looks structurally identical to a rename. pin freezes the deployed capacity identity (and its data volume) onto the new slot. If you meant to replace the capacity with a fresh slot, choose abort.
rename-ambiguous means candidate pairings contested each other and no evidence disambiguated them. Classification fails closed. There is nothing safe to pin, so the only executable verb is recreate, which accepts exactly the delete and create the plan already shows.

Consenting interactively

Run interactively, the deploy walks you through the ticket one resource at a time. For each resource you pick a verb from a menu, with each verb’s meaning shown inline, and then, for any verb with consequences, you must type the resource’s exact physical name:
The comparison is exact and case-sensitive. Three mismatches decline the ceremony, as does pressing Esc. The deploy is withheld and nothing is applied. The typed name is re-checked by the deploy engine itself, so the screen can never widen what you consented to.
The ceremony runs only when no consent flags were passed. Once any --remediate, --allow-replace or --destruction-consent-digest is supplied, an unsatisfied ticket exits 4 with the verdict table instead of falling back to a prompt. A flag consent that fails keeps failing loudly.

Consenting with flags

Non-interactive runs (and CI) cannot hold a ceremony. The deploy exits with code 4 and prints the ticket plus the consent shape:
All three flags work on fjall ci run deploy and on fjall org deploy. fjall drift repair takes --remediate and --destruction-consent-digest but not --allow-replace, whose verb belongs to the deploy.

Consents fail closed

Every supplied consent gets a verdict. A misspelt or surplus name, or a verb that is not legal for the finding, fails the gate closed with a per-name verdict table rather than being ignored:
A consent to a verb the release cannot yet execute withholds truthfully. The output says the consent was given, names what is executable today, and does not ask you to consent again. fjall deploy <app> --plan prints the pending destructive changes alongside the change plan. The ticket rows and the closing ticket digest: line go to stdout, because the plan is the run’s result:
stdout
The instruction naming the consent flags is conversation, so it goes to stderr:
stderr
Applying later with --destruction-consent-digest guarantees the consent covers exactly the changes that were reviewed. If the plan changed in between, the deploy withholds and asks for a fresh review.

Other ticket surfaces

Four more commands mint tickets through the same engine. The same rules apply on all four: named per-row consent, digest binding, fail-closed verdicts, and exit 4 on withheld. Three differences from an application deploy:
  • The verbs are recreate, forget (delegated-child NS only, when the parent cannot delete it), and abort. There is no pin.
  • --allow-replace is not available on the three fjall domain surfaces and is rejected rather than silently dropped. fjall org deploy carries the full consent family, including --allow-replace.
  • Records classified unknown by the zone classifier are never offered on a ticket. Classification fails closed, and only provable residue is remediable.
fjall org deploy has no --plan surface, so its digest comes from a prior withheld run rather than from a plan. The withheld run prints it: the human ticket closes with a ticket digest: line, and --agent carries the same value as the block’s ticketDigest field. The human hint asks for --remediate on every row and treats the digest as optional:

Exit codes

The deploy exit-code contract:

Exit code 4 in CI

Exit 4 is not a failure. It means a human decision is required and nothing was applied. A pipeline that hits it should:
  1. Surface the printed ticket to a human, in the job log, a PR comment, or a chat notification.
  2. Stop. Let the failed-by-default step be the stop, and do not retry.
  3. After a human has reviewed, re-run the deploy with the named consents, ideally minted from a --plan run and bound with --destruction-consent-digest.
Never auto-inject --remediate or --allow-replace in a pipeline. Baking a consent flag into CI defeats the gate: the next unrelated change that replaces a resource of the same name is silently consented. Consents belong to a human review of a specific ticket.
Deploys started from the Fjall web app pass through the same gate and present a consent dialog there. A withheld run that was approval-gated re-mints its approval token, still bound to the same plan digest but with a 25-hour window, so a consent decision can take as long as the review needs. The web app abandons an unanswered destructive-pending deploy after 24 hours.

Next Steps

fjall drift

Detect and repair resources deleted outside CloudFormation.

fjall deploy

Every deploy flag, target, and option.

CI/CD Integration

Wire deploys, plans, and consent handling into your pipeline.

fjall destroy

Explicit teardown of a whole application or organisation.