Why does a rule rejecting a Namespace without a companion NetworkPolicy block every namespace?
answer
- the companion lives inside the namespace
- it cannot exist before its parent
- not staleness - unsatisfiable
- always fails, retry never helps
- gate the later object instead
basics
~10 sAt admission time the NetworkPolicy cannot exist yet: it lives inside the namespace being created. The rule asks about a future state at the one instant it cannot be true, so it rejects everything.
solid answer
~50 sThe rule is evaluated on the create of the Namespace itself, and the companion object is namespaced - it can only be created after its namespace exists. So the condition the rule tests is unsatisfiable at exactly the moment the rule runs, and every namespace is refused. This is not staleness and no fresher read fixes it; it is an ordering error. The general form to recognise is: object A is valid only if companion B exists, where B cannot exist until A does. Admission decides one write at a time and has no notion of a bundle, so a manifest containing both objects is still two separate decisions in an order you do not control. The invariant is real, but it belongs after the fact - a sweep that flags namespaces still lacking a policy - or in the provisioning path that produces both objects together.
go deeper
Know that a NetworkPolicy lives inside a namespace, so it cannot be created before that namespace exists, and a rule demanding it at namespace creation can never pass.
Explain that admission decides one write at a time with no bundling, and distinguish an unsatisfiable rule that always fails from a stale read that fails intermittently.
Show that you check satisfiability at the interception point before writing a rule, and can relocate the invariant to a later object or a scheduled sweep.
Decide where invariants of this shape should live across the estate - a gate, a provisioning template, or a detective control with an owner - rather than forcing them into admission.
## The ordering trap Someone writes a sensible-sounding guardrail: no namespace may exist without a network policy governing it. They express it at the obvious interception point - the creation of the Namespace - and every namespace creation starts failing, including their own test. The reason is ordering, not tooling. A NetworkPolicy is a namespaced object: it lives inside a namespace and cannot be created before that namespace exists. At the instant the Namespace is being admitted, the companion object is not merely missing from the engine's view - it is impossible. The rule tests a condition that can only become true strictly after the decision it gates. Recognise the shape, because it recurs: **A is valid only if companion B exists, and B cannot exist until A does.** Any rule with that structure rejects unconditionally. ## Why a manifest containing both objects does not save it The instinctive rebuttal is that the team applies both objects together, so surely the policy sees both. It does not. Admission is invoked once per write. A file with two documents becomes two requests, in an order the client chooses, and each is decided alone with no knowledge that the other is coming or has just landed. There is no bundle, no transaction, no two-phase decision. If the Namespace request is decided first - and it must be, or the NetworkPolicy write has nowhere to go - the rule sees no companion. ## Distinguish it from staleness, because the fixes are different Two failure modes look similar from the outside and are diagnosed differently: - **Staleness.** The companion object exists, but the engine has not seen it yet. Symptom: intermittent, load-dependent, disappears on retry. Fix: freshness, ordering, or accepting a soft rule. - **Unsatisfiability.** The companion object cannot exist yet. Symptom: fails one hundred percent of the time, and retrying never helps. Fix: move the check. *Always fails, retry never helps* is the tell. If the rule has never once passed, stop tuning the data source and look at what the rule is asking for. ## Which direction of the pair admission can check The pairing is checkable when the object under decision is the *later* one, because by then both objects can exist. So instead of gating the Namespace on its policy, gate the workload on it: refuse to admit a Deployment or Pod into a namespace that has no policy governing it. Now the condition is satisfiable at decision time - the namespace and its policy could both have been created already - and the check is a cross-object read of state that is genuinely there. That version has its own well-known weaknesses, the ones cross-object rules always have: the engine reads a view of the recent past, and a namespace created and never used simply never triggers the check. But it can at least pass, which the original could not. ## What to do with an invariant that admission cannot hold The requirement is legitimate - the mistake is only the interception point. - **Detect after the fact.** Enumerate namespaces on a schedule, flag any that still lack a policy after a grace period, and route it to an owner. This is a detective control, it produces evidence, and it copes with the ordering perfectly well because it runs when both objects have had time to exist. - **Make the provisioning path produce both.** If namespaces are created through a request workflow or a templated repository rather than by hand, the companion object is part of the template and the invariant holds by construction, no gate involved. - **Check at the later object.** As above, gate what runs inside the namespace rather than the namespace itself. ## The interview point underneath Interviewers use this to see whether a candidate reasons about *when* a rule runs, not just *what* it says. A policy author who only asks what the rule should assert will write unsatisfiable rules; one who asks what could possibly be true at the moment of interception will not. The general check is a single question about every cross-object rule: **at the instant this decision is made, is the thing I am requiring even able to exist yet?**
- Would checking on Namespace update instead of create work?Only partly. You could admit the create and refuse later updates that still lack a companion, but nothing forces anyone to update a namespace, so one created and never touched again is never re-examined. The check would have no reliable trigger, which is a detective control implemented badly.
- Which direction of that pair can admission genuinely check?The later object. Refusing a workload in a namespace that has no policy is satisfiable, because both the namespace and the policy can already exist when the workload arrives. It is still a cross-object read of possibly stale state, but at least the condition it tests is reachable.
- How do you tell this apart from a caching problem in a real incident?Look at the failure rate. Staleness is intermittent and load-dependent, and a retry usually succeeds. An unsatisfiable rule fails every single time and no retry ever helps. A rule that has never passed once since it was deployed is an ordering bug, not a data-freshness bug.
saying these in an interview costs you the question
- Assumes objects applied in one file are admitted as a bundle
- Thinks admission can wait for the companion to appear
- Blames cache staleness for a rule that always fails
- Adds retries to a rule that can never pass
- Never asks what can exist at the moment of interception