Unknown is not the same answer as no
A status field that can only say pass or fail will lie by omission the moment the real answer is 'not computed yet.' Treating pending as blocked trains people to ignore both.
Get the field notesContents
A merge check has three honest answers: yes, no, and not yet. Most dashboards only have room to show two.
When a platform hasn't finished computing whether a change is safe to merge, it reports the same shape of message a real blocker would: nothing green, a status that reads unresolved, sometimes the literal word "unknown." An operator glancing at that field cannot tell "wait a few seconds" from "this is actually stuck" without opening the object and reading a different attribute entirely.
#Why this fails in a specific direction
If the third state ("not yet computed") is common and transient, the practical effect isn't random noise. It trains a pattern:
First pass: someone sees the ambiguous status, checks by hand, finds it really was just pending, and moves on. Correct call, but it cost a manual check.
Repeat passes: the same ambiguous status shows up on unrelated items, usually still just pending. The manual check starts feeling like wasted motion.
The pass that matters: the status shows up one more time. It is not pending. It is a real block. The read is identical to the fifty times before it, so the response is identical too: skip the check, assume it'll clear.
Nobody decided to stop checking real blockers. The interface never gave them a way to tell the difference, so the cheap heuristic ("it's probably just pending") generalized to cover a case it was never actually true for.
#This is not the same problem as a dead gate
A gate that never fires is silent because the bad case hasn't happened, or because the gate itself has gone stale. Either way, the gate has one real state at any moment, and the ambiguity is about history, not about the current read.
This is different. The field itself is compressing two distinct, simultaneously-possible current states into one displayed value. There's nothing wrong with the underlying check; the interface reporting it just doesn't have enough bits.
| Symptom | Cause | Fix |
|---|---|---|
| A gate that's been quiet a long time | Rare bad case, or a stale/dead check | Manufacture the bad case, confirm the gate can still fire |
| A field that reads the same for "still computing" and "blocked" | Not enough displayed states for the number of real states | Separate the states before displaying, not after |
Confusing these two diagnoses wastes the fix. Building a positive control catches a dead gate. It does nothing for a field that's honestly reporting a live check and a stuck check as the same string.
#Widen the field before you widen the timeout
A common patch is to wait a fixed interval and then treat "still ambiguous" as "must be blocked." That only relocates the collapse to a later moment; it doesn't remove it. A slow-but-fine computation and a genuinely stuck one still look identical right up until the timeout fires, so now the system is wrong on a schedule instead of wrong immediately, which is worse to debug because the wrongness has a delay built into it.
Widening the field is cheaper than it sounds: read whichever attribute of the underlying object already distinguishes "in progress" from "resolved," and surface that attribute directly instead of leaving it as a fact someone has to already know to go dig for.
- In progress: the check is running. Say so, in words that are never reused for a failure state.
- Resolved, blocked: name what's blocking it specifically, not a generic catch-all string.
- Resolved, clear: this is the only state that should ever render as quiet.
If the underlying platform genuinely can't expose a third value, that's a real gap worth escalating on its own, not a reason to route around it with a guess. A field you can't disambiguate isn't a field anything downstream should be allowed to decide on autopilot.
#Auditing your own status fields
Start by listing every status field an operator or an automated decision currently trusts, and for each one, count how many real states the underlying system can actually be in versus how many distinct values the field can display. Anywhere those two numbers don't match, you've found a collapse waiting to happen, whether or not it's caused trouble yet.
Then go looking for the tell that it already has: ask around for a field anyone describes as "usually fine, ignore it" or "just check by hand." That phrase is what a collapsed field sounds like from the outside, once the workaround has become routine enough that nobody remembers it started as a one-time exception.
Where you find one, the repair is the same either way: give the missing state its own value, sourced from whatever the system already tracks internally, rather than picking a longer wait and hoping the ambiguity lands somewhere less expensive.
A field that can't say "not yet" is going to get read as "no" by someone, eventually, and the someone reading it that way won't know they got the wrong answer until it's already cost something.
See how EP treats operational instrumentation as part of the build, not an afterthought.
Get the field notes.
One useful note on AI operations, no hype. A weekly roundup, and we skip any week without something worth sending.
Double opt-in. Unsubscribe any time. Read our privacy notice.
Keep reading
- · 3 min
More writers does not mean more throughput
Say you give twenty autonomous agents write access to the same shared state. The bottleneck does not move to the model. It moves to whoever has to reconcile the collisions.
- · 3 min
The check that cannot fail is not a check
A safety gate that has never been triggered looks identical to one that is broken. The difference only shows up when you go looking for the trigger it should have caught.
- · 4 min
Installing an agent skill is running untrusted code
A skill looks like documentation, so teams install one like they trust a README. The audits say treat it like code you are about to execute.