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.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.--auto-approve,--skip-confirmation,--forceand approval tokens never satisfy this gate.
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.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:
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 throughfjall 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 aRetain 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:
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 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 code4 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:Plan first, consent bound to the plan
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
stderr
--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), andabort. There is nopin. --allow-replaceis not available on the threefjall domainsurfaces and is rejected rather than silently dropped.fjall org deploycarries the full consent family, including--allow-replace.- Records classified
unknownby 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
Exit4 is not a failure. It means a human decision is required and nothing was applied. A pipeline that hits it should:
- Surface the printed ticket to a human, in the job log, a PR comment, or a chat notification.
- Stop. Let the failed-by-default step be the stop, and do not retry.
- After a human has reviewed, re-run the deploy with the named consents, ideally minted from a
--planrun and bound with--destruction-consent-digest.
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.