A log-retention rule's subject lives in another root module's plan — how do you gate it?
answer
- the rule's subject is one hop away
- the reference dead-ends outside this run
- an unmatched rule looks like a pass
- constrain the input or re-home the control
- delete it here, record where it went
basics
~20 sUsually you do not gate it here. When the control's subject is missing from this plan, either constrain the module input so it becomes visible, or re-home the control where the subject exists. Approximating it is worse than not enforcing it.
solid answer
~50 sThe control is really about the log group's retention; the trail only points at it. If the group is created by the platform team's configuration, this plan holds a reference that dead-ends — it resolves to a variable or module output with no planned resource behind it. Four options: approximate against what is present, which buys a green run and no assurance; fail closed on any trail whose destination is not declared here, which blocks the normal cross-module architecture; require the destination as a constrained module input so the plan carries it, which works when you own the interface; or declare the control out of scope for this gate and enforce it where the log group is created or observed. I take the last and record it — the thing I refuse to ship is a rule that can never match and reports green forever.
go deeper
Understand that a plan describes one configuration's run, so a resource created elsewhere simply is not in the file. Be able to say why a rule about it would find nothing rather than fail.
Explain how the reference chain dead-ends at a variable or module input, and why an empty join must be reported as unevaluable rather than passing. Know that a rule which never matches produces the same output as a rule that always passes.
Weigh the four responses out loud — approximate, fail closed, constrain the module input, re-home — and commit to one with its cost. Interviewers are listening for whether you would ship a rule that cannot fail, and for the bookkeeping that keeps coverage honest.
Own the scope decision for the whole control set: which controls this gate claims, which are enforced elsewhere, and how that split is published so a green pipeline is never read as blanket assurance. Be ready to defend deliberately not enforcing something here.
## The rule's subject is not the resource you were looking at "Audit logs must be retained for at least a year" sounds like a rule about the trail. It is not. Retention is an attribute of the **log group the trail writes into**, and the trail merely names that destination. So the moment you sit down to write the rule you discover the subject is one hop away, and whether the gate can see it depends entirely on who declared it. Three situations, in increasing order of difficulty: 1. **Both resources are in this configuration.** Then it is an ordinary join: read the trail's destination argument out of `configuration`, take the referenced address, look up the log group in `planned_values`, assert on its retention. This is the good case and it is why the join is worth building. 2. **The log group is created by another root module.** The destination arrives as a variable, a module input, or a value read from somewhere outside this run. The reference chain ends at something that is not a resource in this document. The join returns nothing. 3. **The log group was created by hand, or before the estate was codified.** The destination is a literal name or id. There is no reference at all, and nothing in any plan governs that resource. Cases 2 and 3 are the same problem from the gate's point of view: **the artifact does not contain the thing the control is about.** ## The four responses, and what each actually costs **Approximate it.** Write a rule against what *is* present — the trail exists, the destination is set, so call it satisfied. This is the tempting one because it produces a rule that runs, passes, and appears in the control list. It is also the worst outcome available, because it converts "we have not checked" into "we checked and it was fine." Anyone reading the gate's output later — a reviewer, a lead planning the next control, an audit-evidence pull — now believes retention is enforced. It is not. **Fail closed.** Block any trail whose destination is not declared in this configuration. This is defensible when cross-module wiring is rare and inside your team's boundary: it forces the resource into the plan where you can judge it. It is the wrong call when cross-module wiring is the intended architecture, because then the gate blocks correct code and the organisation's response is a blanket exemption — after which the rule is decoration with extra process attached. **Constrain the interface.** If you own the module the trail lives in, change the input contract: accept the retention value, or the destination's full definition, as a module input the plan can see, and validate it there. This genuinely re-establishes the join, and it is often the best answer when the two configurations belong to the same team. It costs a coordinated change to every caller, so it scales badly across an estate you do not control. **Re-home the control.** Declare the rule out of scope for *this* gate, and enforce it where the subject exists: in the plan gate over the configuration that actually creates the log group, or as a check over the live resource after the fact. This is a deliberate decision that the control is not enforceable at this point in the pipeline, made explicitly rather than by accident. Both outcomes it produces are honest: the control is enforced somewhere real, and this gate's coverage list does not claim it. ## Why the last option beats a rule that quietly passes The thing to internalise is that a policy gate has two kinds of failure and only one of them is visible. A rule that wrongly blocks gets reported within the hour by the developer it blocked. A rule that can never match produces nothing, and nothing looks exactly like success. Over a year, the gate accumulates these — every one of them a control someone believes is covered — and the total is a coverage claim nobody can substantiate. So when you re-home a control, do the bookkeeping that makes it stick: - **Delete the rule from this gate** rather than leaving a body that never matches. Dead rules are how the claim survives the decision. - **Record where the control moved and who owns it**, so the next person who notices the gap does not re-derive this analysis from scratch. - **Keep the gate's coverage list explicit**, so a green run is read as "these named controls passed," not "everything is fine." - **Instrument the unevaluable case** if you keep a rule at all: a subject that could not be located is a separate result from a subject that passed, and it should be countable. ## The general shape The boundary of what a plan gate can enforce is not drawn by your rule language or your engine. It is drawn by the document: one root configuration's run, containing the resources that run declares and the references between them. Controls whose subject spans that boundary are not harder to write — they are outside the artifact, and the right engineering move is to say so and place the control where its subject lives.
- The destination resolves to a data source rather than a managed resource. Does that change your answer?Not much. A `data` entry names something this configuration reads but does not manage, so even if you can inspect it, blocking this plan cannot change it — the author has no lever. Treat it as the same category: the control belongs wherever that resource is created or observed. What it does give you is a clearer finding, because you can say which existing resource is non-compliant instead of reporting an unresolved reference.
- How do you stop the control silently reappearing as covered once you move it?Remove the rule from this gate instead of leaving one whose body never matches, and record the control's new owner and enforcement point alongside the decision. Then make the gate publish what it actually evaluates, so a green run reads as a named list of controls rather than a blanket pass. If you keep any rule that can be unevaluable, count that outcome separately from a pass so the gap stays visible.
- When is failing closed on an undeclared destination the right call instead?When the wiring is inside one team's boundary and cross-module destinations are the exception rather than the design. Then blocking is a real forcing function: the fix is to declare the resource where you can judge it. It is the wrong call when the estate is deliberately split, because you will block correct changes, collect exemptions, and end up with a rule that is enforced only against people who have not yet learned how to get waived.
saying these in an interview costs you the question
- Approximates the rule and reports the control as covered
- Leaves a rule that can never match, and calls green a pass
- Assumes every resource that matters is in this plan
- Blocks the change to force another team's resource into scope
- Treats an unresolvable reference the same as a compliant one