The agent wired the success path and left the failure branch silent
The agent implemented the happy path, returned 200, and declared done. The failure branch existed in code but emitted nothing: no log line, no trace span, no error returned to the caller. When that branch fired in production, the symptom looked like a request that vanished, and on-call had nothing to grep for.
A feature that fails quietly is harder to fix than one that crashes visibly. A crash at least names the place; a silent branch leaves you reconstructing which condition even ran.
Why the success path gets all the attention
The task prompt usually describes what should happen. The agent builds against that target: validate the input, call the service, return a result. The failure branches read like leftovers to tidy later, and logging feels like ceremony the task did not ask for. So the catch block swallows the exception into a generic response, the guard clause returns an empty value, and the retry fallback continues without recording why it moved.
This slips past review because the code compiles and the unit test covers the success path. Nobody checked what happens when the branch actually runs, because the path only appears under an edge the test does not reach.
Every exit branch should be observable
The cheap rule: every branch that leaves a caller for a non-success reason emits one structured line before returning. A stable short error code, the trace id, and the inputs that decide the branch without leaking secrets. The line does not need a novel, but it has to be greppable after the fact.
That means doing three small things that are easy to skip:
- Emit a structured log on each non-success exit, not just the top-level catch. A guard clause that returns empty is still an exit.
- Propagate the trace id into the log so the failed request links back to the incoming request instead of floating alone.
- Redact secrets and tokens; a breadcrumb that leaks a credential creates a worse incident than the silent branch.
Before calling the task done, inject the fault once and read the log back. Force the branch to run, confirm the line appears with the right code and trace, then remove the temporary trigger. A branch you never exercised is a branch you cannot trust.
Make the failure path as easy to inspect as success
Reviewers can ask one question that catches most of these: trace every place the function can return for a reason other than the happy path and point to the line that records it. If a branch has no log and no surfaced error, it is incomplete regardless of how clean the success path looks.
Observation is part of the implementation
Logging the failure branch is not a follow-up ticket to file later. A silent branch means the next failure starts from zero: no evidence, no trace, just a user report and a guess at the condition. Wire the success path, then give the failure path a voice, and verify that voice actually prints under fault.