What does a plan-time policy rule lose when you re-express it against recorded state or an inventory?
answer
- compare the two documents field by field
- one has a verb, the other only nouns
- no action, no before, no requester
- the touched-only scope disappears too
- one thing is gained: unknowns become concrete
basics
~10 sIt loses the change action, the prior value, the surrounding request context that identified the author, and the implicit scope of only judging touched resources. A state record is attributes with no verb attached.
solid answer
~50 sA plan entry has a verb and a history: an action such as create or update, a `before` object holding the previous values and an `after` object holding the new ones. A state or inventory record has neither — it is a bag of current attribute values. So three kinds of rule stop translating. Transition rules (`do not widen this`, `do not destroy that`) have no prior value to compare against. Rules that grandfather (`only enforce this on newly created resources`) have no action to test. Attribution disappears too: a plan-time run happens inside somebody's change, so the pipeline knows who asked, while a scheduled scan has no requester at all and must route findings by ownership tags. Finally the implicit scoping goes: the rule now judges the whole population, not the delta, so its first run usually returns a large pre-existing backlog.
code
json · 15 lines// plan JSON: resource_changes[0]
{
"address": "aws_db_instance.orders",
"change": {
"actions": ["update"],
"before": { "engine_version": "12.4", "...": "..." },
"after": { "engine_version": "12.9", "...": "..." }
}
}
// state JSON: values.root_module.resources[0]
{
"address": "aws_db_instance.orders",
"values": { "engine_version": "12.9", "...": "..." }
}go deeper
Know that a plan entry says what is happening to a resource while a state record only says what the resource currently is. That single difference is what the whole answer hangs on.
Be ready to enumerate the losses precisely — action, prior value, requester context, touched-only scope — and to name a rule of each shape that does and does not translate. Mention that unknown-until-apply values become concrete as the one gain.
Demonstrate that you would keep transition rules at the plan gate rather than force them over state, and that you would plan for the first run's backlog and the ownership-tag routing before enabling the scan.
Own the position that a rule set is not portable between the two inputs, and that promising 'the same policies, everywhere' commits the team to rules that quietly weaken when re-expressed.
## The shape of each input A plan entry for a resource carries an **action** (create, update, replace, destroy, no-op), a **before** object with the values the resource has now, and an **after** object with the values it will have. It is a statement about a transition. A state or inventory record carries an **address**, a type, and the **current attribute values**. There is no action, no before, and no notion that anything is happening. It is a statement about a fact. Everything a rule loses in the move follows from that one difference. ## 1. The change action A rule phrased around the verb has no equivalent. `Deny creating a public bucket` becomes, over state, `flag any public bucket that exists` — a different rule with a different blast radius. `Do not destroy this resource` cannot be expressed at all: state never describes a deletion, it simply stops mentioning the resource, and a resource that has vanished looks identical to one that was never in scope. The practical consequence is that you cannot grandfather. At plan time you can say `only newly created resources must satisfy this`, which lets a rule land without a backlog. Over state, every resource is judged the same way, whenever it was created. ## 2. The prior value No `before` means no comparison. Any rule about a direction of travel — widening a rule set, lowering a retention period, downgrading an instance class, dropping encryption — is unwritable over state. The best you can do is compare two scans taken at different times and diff them yourself, which is a different mechanism with its own bookkeeping, not the same rule. ## 3. The request context The plan document itself does not carry an identity, but the plan-time **run** does: it happens inside somebody's change, in a pipeline that knows the requester, the branch and the review. A finding at that moment lands in front of the person who caused it, and telling them is free. A scheduled scan over state has none of that. The finding arrives with an address and nothing else. Routing it to a human depends entirely on metadata attached to the resource — ownership tags, or a mapping from the address back to the module and repository that declares it. If that metadata is missing or stale, findings pile up in a shared queue with no owner, which is the most common way a state scan becomes noise. ## 4. The implicit scope At plan time the rule is automatically limited to what the change touched. That limit was doing quiet work: it kept results small and every result relevant to somebody right now. Removing it means the very first run of a re-expressed rule evaluates every resource that has ever existed, and typically returns a large pre-existing population. That backlog is not a bug — it is the risk that was always there and was never visible — but it has to be triaged as a one-off before the rule can function as an ongoing signal, otherwise every subsequent run is drowned by it. ## What you gain Two things, and both matter. **Coverage.** The untouched resources — the long-lived, stable, unpatched ones — are finally in scope. **Concrete values.** A plan can contain values that are **unknown until apply**: an identifier the provider assigns, an attribute computed from another resource that does not exist yet. A plan-time rule has to cope with those explicitly, and deciding whether an unknown should pass or fail is a real design problem. In state, the apply has happened, so those attributes hold actual values. Rules that had to hedge around unknowns become straightforward reads. ## Which rules survive the translation A useful sorting rule for an interview: | Rule shape | Translates? | | --- | --- | | Attribute must equal / must not equal a value | Cleanly — the value is right there in the record | | Attribute must be present, or must match a pattern | Cleanly | | Only enforce on newly created resources | No — no action to test | | Do not move this attribute in this direction | No — no prior value | | Require an approval or an owner on the change | No — no requester in the record | So the honest answer is that re-expressing a rule set over state is not a port. It is a re-authoring in which the attribute-shape rules come across almost unchanged, the transition-shape rules have no equivalent and must be left at the plan gate, and the resulting findings need a routing and closure workflow that the plan gate never needed.
- What happens the first time you run a re-expressed rule over the whole estate?It returns the entire pre-existing population that violates it, often a large number, because the touched-only scoping is gone. Treat that first run as a one-off triage: decide per resource between an owned fix with a date and an explicitly accepted exception with an expiry, then let subsequent runs report only what is new or newly overdue.
- Which rules survive the translation cleanly and which do not?Attribute-shape rules survive: a version must be supported, encryption must be on, a tag must be present. Transition-shape rules do not: anything phrased as do not widen, do not destroy, or only enforce on creation depends on the action and the prior value, neither of which exists in a state record. Those stay at the plan gate.
- Does anything actually get easier when the input is state rather than a plan?Yes. A plan can carry values that are unknown until apply, and a plan-time rule has to decide whether an unknown passes or fails. After the apply, state holds the real value, so the rule just reads it. You lose the ability to refuse the change and gain unambiguous data.
saying these in an interview costs you the question
- Assumes the state record identifies who made the change
- Writes a state rule that references a before value
- Expects the re-expressed rule to fire on the same resources
- Forgets state has no create-versus-update distinction
- Thinks unknown-until-apply values persist into state