v1.15.0: Downstream impacts
A plan tells you what one Module is about to do. It tells you nothing about what that does to the Modules reading its outputs. Approving an apply has always meant approving everything it sets off further down, without seeing any of it.
Now, when a plan changes an output something else reads, Snap CD asks those Modules what it means for them and shows you their answers before you decide.
Full notes: 1.15.0 on GitHub.
Why a downstream plan lies
Two Modules, one feeding the other. Plan the upstream: it reports a replacement, and the output the downstream Module reads becomes "known after apply". Plan the downstream Module in the same breath and it reports no changes.
Both plans are right about the world they were given. The downstream one just happens to describe a world that stops existing the moment the upstream applies.
Inside a single root this can't happen. A resource gets replaced, its computed attributes become unknown, every expression reading them becomes unknown, and each provider is asked whether that forces a replacement of its own. Split the same resources across two Modules and there is no shared plan graph, so none of that carries over.
What happens now
A plan that changes an output starts a wave. Each Module reading one of those outputs is asked to plan again, this time with the predicted value in place of the one in state.
The value it gets is the real one the upstream's plan produced, including an unknown where the plan couldn't work the value out yet. That last part is why a made-up placeholder won't do. A fake string gets past validation blocks and length limits a real unknown would skip, and makes count and for_each succeed with the wrong instance set. An unknown refuses to plan, which is the right answer.
So each Module's own providers decide whether the change forces a replacement, the same way they would inside one root. A chain is answered one hop at a time, and a Module that two changes reach at once answers each of them separately.
On the approval screen
Each downstream Module shows what it predicted, with its own logs, and the wave is summarised above them: nothing changes, something changes, something gets destroyed or replaced, or a check did not finish.
A prediction only holds for the moment it was made, though. If the Module's code, declaration or input values have moved since, it is marked stale and you can ask for another. The first prediction stays on the record: what was predicted at the time is worth keeping.
If the asking never started at all, the screen says so and offers to try again, so you don't read an unchecked change as a checked one.
Terraform and OpenTofu
Probes run through snapcd-inspect, built on the OpenTofu libraries. The engine CLI can't do this: there is no way to tell plan that a variable is unknown, because a -var or a var file carries a literal.
It works against a directory either engine initialised. The two resolve an unqualified provider source to different registry hosts, so the lock file and the provider cache disagree about a provider's identity even when the binary is the same release. Snap CD sorts that out without touching your working directory or your lock file.
Fixes
- Runner logs are stored in chunks, so adding to a log costs the same however large it has already grown.
- A log batch now says which table it belongs to instead of the Server going looking for a matching job, and a runner writing logs is checked against the job the same way every other step reply is.
- A manual job whose request couldn't be handled is now failed with the reason, instead of sitting at Running with nothing behind it. The sweep that closes abandoned manual jobs now covers move, import, remove and address lookups, not just splits.
Intelligent GitOps for Infrastructure as Code. Automate, orchestrate, and scale your infrastructure deployments with confidence.
© 2026 Snap CD. All rights reserved.