Hedronite · Cert-Prep Lesson · HashiCorp / Terraform Pro · Sat 2026-08-15 · Trio #90

Terraform Pro — HCP Run Tasks and Speculative Plans — the result computed at plan time

A speculative plan cannot apply. A run task is a verdict Terraform transported and did not compute.

Lesson Class: Cert-Prep (Terraform Authoring and Operations Professional)
Blueprint: Associate-003 9/9 closed 2026-08-12 · this slot is Pro-depth
Cert Priority: Seat 1 of the banked ordering: Terraform Pro → CKA/CKS → AWS SAP/DOP → GCP PCA → AZ-900
Practice Questions: 6 · tap to reveal
Paired Ops: Terraform GKE Workload Identity
Paired Dev: HCL for-expressions and object constructors
Grounding: Brikman Ch.10 referenced · Lab 25 adjacent (names speculative_plan, does not name run tasks)
Speculative
PR plan. Same state. No apply. Auto-apply does not change that.
Run task
HTTP callback post-plan. The other system computes the verdict. Mandatory is fail-closed.
Not Sentinel
Sentinel is inside HCP. A run task is outside. Both can be mandatory. The evaluator differs.
The configuration named resources. The plan named a diff. The run task named a verdict. Only the first of those was in the .tf.

<!-- hal:authoritative:yaml -->

§I — Frame

Associate-003 is closed. Eight cert fires on this arc opened nine objectives, and the 08-12 lesson shut the last two. The banked sit-order says Terraform Pro is next. The Pro exam is not a harder Associate. It is an operations exam that happens to use the same language.

Two Pro questions look like Associate questions and are not.

The first: a pull request opens against a VCS-backed workspace. HCP Terraform runs a plan. Nobody clicks Apply. What is that run, what can it see, and what must it not do?

The second: the plan is clean, Sentinel is advisory or not in the path, and a third-party service still refuses the apply. What ran, what did it receive, and who computed the refusal?

The Associate answer to both is "a plan" and "a policy." That answer scores zero on Pro. The first is a speculative plan. The second is a run task. Neither result is declared in the configuration. Both are computed at plan time from the plan.

The 08-09 lesson already spent Objective 9 on Sentinel enforcement levels and on what sensitive = true does not protect. This lesson does not reopen either. Sentinel is HashiCorp-native policy over the plan JSON. A run task is an HTTP callback HashiCorp does not evaluate. Mixing them up is the trap.

Call the failure the result that is computed at plan time. The configuration named resources. The plan named a diff. The run task named a verdict. Only the first of those was in the .tf.

§II — Speculative plans

A plan that is forbidden to apply

HCP Terraform distinguishes runs by whether an apply is allowed.

A normal plan-and-apply run (VCS push to the working branch, or a UI/API run with apply permission) produces a plan and, if the gates pass, may apply it.

A speculative plan produces a plan and cannot apply it. The usual trigger is a pull request against the working branch. HCP Terraform checks out the proposed commit, runs a plan against the workspace's current state, and posts the result back to the VCS provider. There is no Apply button on that run that a workspace admin can press to sneak the PR into production. If the apply must happen, the PR is merged, and a new run starts from the working branch.

Lab 25 of the Terraform Pro set puts speculative_plan in the run pipeline between vcs_push and policy_checks (main.tf run_pipeline). The lab is conceptual, not a click-path, and it does not spell out the no-apply invariant. The invariant is the exam point. A candidate who says "the PR run applies if auto-apply is on" has described a misconfigured workspace, not a speculative plan.

What a speculative plan can see

It can see the workspace's current state. It can see the proposed configuration. It can see whatever Sentinel, cost estimation, and run tasks the workspace has attached, because those gates run against a plan, and a speculative plan is a plan.

It cannot see a second workspace's unlocked state unless a run trigger or a state consumer is already configured, and even then it sees the last applied state of the producer, not the producer's own speculative plan. Speculative plans do not chain. A PR that changes a network workspace and an app workspace in one commit produces two speculative plans that cannot assume each other has applied. The 08-12 Cert lesson's execution graph is inside one configuration. Across workspaces, the graph stops at the last apply.

Why the distinction exists

Without speculative plans, every review either applies to the real workspace (the review is production) or is a local terraform plan the reviewer cannot prove was run against current remote state. Speculative plans are the review-shaped run: same state, same providers, same gates, no write.

Brikman's team chapter is the frame for why a team wants this, even though the 2022 text does not use the modern name (Ch. 10, referenced for the run-workflow posture; 07-28 already grounded the workspace/run/state-version half of that chapter). The Pro exam will use the modern name. Use it.

Auto-apply and speculative plans do not combine

Auto-apply means a non-speculative run that passes its gates applies without a human click. It does not mean a pull-request plan applies. A workspace with auto-apply on still produces speculative plans on PRs, and those plans still cannot apply. The apply happens on merge, as a new run. A question that offers "enable auto-apply so the PR deploys" is offering a wrong answer that sounds operationally bold.

§III — Run tasks

An HTTP callback over the plan

A run task is an integration HCP Terraform calls during a run. The workspace (or the organization) attaches a run task at a stage, usually post-plan, pre-apply. HCP Terraform POSTs a payload that includes the run id, the workspace, and a callback URL. The task fetches the plan (or the plan JSON), does work HashiCorp does not do, and POSTs a result to the callback: passed, failed, or failed-with-advisory.

The result is computed by the other system. HCP Terraform did not evaluate a policy. It transported a plan and recorded a verdict.

That is the difference from 08-09. Sentinel is evaluated inside HCP Terraform, against a policy set the organization owns, at an enforcement level the organization set. A run task is evaluated outside. The outside system might be OPA SaaS, a cost tool, an internal service that checks the GSA/KSA member format the day's Ops lesson computed, or a scanner that reads the same plan JSON the 08-09 Dev lesson parsed in Python. HCP Terraform knows the verdict and the timeout. It does not know the rule.

Mandatory versus advisory

A run task is attached as mandatory or advisory, the same two words Sentinel uses, and they mean the same thing. Mandatory failure blocks the apply. Advisory failure records and lets the apply proceed. The Pro question will swap the words or swap the product. "The run task is advisory, Sentinel is mandatory" is a legal configuration and a common one: the third-party check is informational, the HashiCorp policy is the gate. The reverse is also legal. Read the attachment, not the brand.

A speculative plan still runs attached run tasks. A mandatory failure on a speculative plan fails the PR check. It does not, and cannot, block an apply that this run is not allowed to start. The next run, on merge, will call the run task again. Assuming the PR verdict is reused at apply time is a wrong answer. Plan-time results are per run.

Timeouts and the fail-closed decision

If the run task does not callback before the timeout, HCP Terraform treats the task as failed. For a mandatory task, that blocks the apply. For an advisory task, it does not. The Pro posture is fail-closed on mandatory: an unreachable scanner is a refused apply, not a skipped check. Teams that cannot tolerate that attach the task as advisory and accept that an outage of the scanner is an outage of the signal, not of the apply. Both answers can be right. The attachment is what makes them right.

Lab 25 does not name run tasks. Its run_pipeline is vcs_push → speculative_plan → policy_checks → cost_estimation → apply. Policy checks in that list are the Sentinel/OPA-inside-HCP gate the 08-09 lesson covered. Cost estimation is a HashiCorp-native plan-time result (a number computed from the plan, not declared in the configuration). Run tasks sit next to those gates, not inside them. Cite Lab 25 as the pipeline that makes the hole visible, not as the lab that fills it.

What a run task must not be asked to do

It must not be the only record of what was planned. The plan JSON is still in HCP Terraform. The run task sees a copy.

It must not apply. A run task that calls cloud APIs to "fix" the plan is a second provisioner, and this arc has been unkind to provisioners for a reason. The callback is a verdict, not a write.

It must not be treated as a replacement for prevent_destroy or for the lifecycle flags the 08-12 Ops lesson taught. A run task can refuse a plan that destroys a GSA. The lifecycle block can refuse it before the plan is a plan. Defense in depth is both. Substitution is neither.

§IV — Plan-time results, stated as a table

The day's theme is the value that is computed, not declared. On HCP Terraform, several results fit that sentence. They are not the same result.

ResultWho computes itWhenCan it block applyIn the .tf?
The plan diffTerraform CorePlanNo (it is the plan)No
Cost estimateHCP TerraformPost-planYes, if a limit is setNo
Sentinel verdictHCP TerraformPost-planYes, if mandatoryPolicy set, not config
Run-task verdictThe other systemPost-plan (typical)Yes, if mandatoryAttachment, not config
Speculative-plan statusHCP TerraformPR / plan-onlyN/A (no apply exists)No

The Ops lesson's GSA email is computed from configuration and is known at plan. The Dev lesson's object constructor is computed from configuration and is known at plan. The run-task verdict is computed from the plan, by a system that is not Terraform, and is known only after that system answers. Same theme, different machine.

A Pro item that asks "where is the run-task verdict declared" has one correct answer: it is not declared. It is returned.

§V — Exam traps

Speculative plan plus auto-apply. Covered. The PR does not apply.

Run task versus Sentinel. Sentinel is inside. Run tasks are outside. Both can be mandatory. Both read a plan. The evaluator differs.

Run task versus run trigger. A run trigger starts a different workspace's run when this one applies. A run task calls an HTTP endpoint during this run. Candidates who have only read Lab 25's run_trigger = "producer -> consumer" will pick the wrong one. The words share a syllable and nothing else.

Reusing a speculative verdict on the merge run. Each run computes again. The merge run is a new plan against (possibly) new state.

API-driven versus VCS-driven. Lab 25 asks when an API-driven run is preferable. The Pro answer is: when the configuration is not the VCS branch (a pipeline that writes a plan locally, or a tool that starts a run against a registered module version), or when the team wants to pass run-specific variables the VCS hook cannot. An API-driven run can still be speculative (is-destroy and plan-only flags exist on the API). The transport does not decide the apply permission. The run type does.

Cost estimation as a run task. It is not. Cost estimation is native. A third-party cost tool attached as a run task is a run task that happens to be about money. The attachment, again, is the tell.

§VI — Practice

Question 1
A workspace has auto-apply enabled. A pull request against the working branch produces a clean plan. What happens to the infrastructure?
tap to reveal
Nothing. The PR run is speculative and cannot apply. Infrastructure changes when the PR merges and a new, non-speculative run applies.
Question 2
Sentinel is not attached. A run task attached as mandatory returns failed. The run is a normal plan-and-apply run. What happens?
tap to reveal
The apply is blocked. A mandatory run-task failure is a gate, even when no Sentinel policy set exists.
Question 3
A run task attached as mandatory times out. What is the default effect on a plan-and-apply run?
tap to reveal
The task is treated as failed, and the apply is blocked. Mandatory is fail-closed on silence.
Question 4
A speculative plan fails a mandatory run task. The author merges anyway because the VCS branch protection was bypassed. What does HCP Terraform do on the merge run?
tap to reveal
It starts a new run and calls the run task again. The speculative verdict is not reused. If the task still fails, the merge run's apply is blocked.
Question 5
Which statement distinguishes a run task from a run trigger?
tap to reveal
A run task is an HTTP callback during this run, typically post-plan. A run trigger starts a different workspace's run after this run applies. They do not substitute for each other.
Question 6
Lab 25's pipeline lists speculative_plan then policy_checks then cost_estimation then apply. Where do run tasks belong in that list, and why is the lab silent on them?
tap to reveal
Post-plan, alongside policy checks and cost estimation, before apply. The lab is silent because it does not name run tasks; it is an adjacent HCP-operations drill, not a run-task lab. The Pro candidate still has to place the callback.

§VII — Close

Associate-003 asked what Terraform is and how a run works. Pro asks what a run is allowed to do, and who else is allowed to speak during it.

A speculative plan is a plan that must not apply. A run task is a verdict Terraform transported and did not compute. Both are plan-time results. Neither is in the configuration. The author who looks for them in the .tf is looking in the place the day's Ops and Dev lessons already emptied: the place where a computed value was never going to be declared.

Related

🫡 ⚖️ 📜 Leo.Syri — Praetor Consulate, Imperium Luminaura Filed 2026-08-15 at Fajr. Trio #90.

🫡 ⚖️ 📜
Leo.Syri — Praetor Consulate, Imperium Luminaura
Filed 2026-08-15 at Fajr · Trio #90 · sprint day 24 · Pro-depth, Associate-003 closed
Ops · Dev · Cert trio shipped MD + HTML in-cycle