[MODEL] Opus 5 writes verification probes without establishing their discriminating power (11 instances, one session)

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 30, 2026

Preflight

  • [x] Searched existing label:model issues — no similar report found.
  • [x] Contains no sensitive information. All project names, paths, session IDs and

internal identifiers have been removed; every instance below is stated as a
generic mechanism.

Type of Behavior Issue

Other unexpected behavior — a systematic weakness in self-verification.

What I Asked Claude to Do

Ordinary engineering work over a long session: diagnose a runtime hang, root-cause it,
fix it, verify the fix, and deploy. Nothing about the requests was unusual; the
behavior below appeared in the verification steps Claude chose for itself.

What Claude Actually Did

Eleven times, it wrote a command whose OUTPUT it then quoted as evidence, without
establishing that the command could distinguish the answer from its negation. Each
command was syntactically valid, exited 0, and produced plausible output.

The defining property: a broken verification returns a reassuring value. No error,
no exception, no red.

This is not a knowledge gap. The model had the relevant rule in context — it quoted
"a check that cannot fail is not a check" and "absence and failure must never share one
output" correctly throughout the session, and used exactly that principle to find
several real defects in the code under repair. It violated the same rule in its own
steps.

The tractable observation: every instance it caught, it caught by running a
control. Every instance that survived to affect a conclusion was one where it skipped
the control. The gap is consistency in applying a discipline the model demonstrably
knows.

Expected Behavior

For any probe whose output will be quoted as evidence, the model should establish
discriminating power before reasoning from the result — with a control that must return
a different value, not with reasoning about the command.

Permission Mode

bypassPermissions

Can You Reproduce This?

Not as a single deterministic repro — it is a pattern across a long session, and the
individual shapes (awk range operators, greps for absent tokens, process probes
matching themselves) are well-known traps that the model navigated correctly many other
times in the same session. What is reproducible is the class: give the model a
multi-hour investigation where it must verify its own claims from logs and process
state, and instances appear.

---

The failure mode

When the model writes a command whose OUTPUT it will then quote as evidence, it
frequently does not establish that the command can distinguish the answer from its
negation. The command is syntactically valid, exits 0, and returns plausible output.
The model then reasons from it.

The defining property: a broken verification returns a reassuring value. There is
no error, no exception, no red. Eleven instances occurred in one session.

This is not a knowledge gap. The model had the rule in context — it quoted "a check
that cannot fail is not a check" and "absence and failure must never share one output"
correctly throughout, and used exactly that principle to locate several real defects in
the code under repair. It violated the same rule in its own verification steps.

The tractable observation: every instance the model caught, it caught by running a
control. Every instance that survived long enough to affect a conclusion was one where
it skipped the control. The gap is consistency in applying a discipline the model
demonstrably knows, not absence of the knowledge.

Why this class deserves separate attention

Production code that breaks gets reported. Verification code that breaks stays
green.
It therefore outlives other defects, and it leaves a reader believing an area
was checked — a false barrier that suppresses later suspicion. Two of the eleven
instances silently affected a live system before a human noticed.

---

Worked instances

Each is stated as: the question → the probe → what it returned → the truth → why the
two share an output.

1. awk '/start/,/end/' used as a time window

  • Question: did event X occur between 21:44 and 22:13?
  • Probe: awk '/21:44:29/,/22:13:00/' log | grep -c X
  • Returned: 3
  • Truth: 0
  • Mechanism: awk's range operator ends at the first line matching the end pattern.

No line contained the literal 22:13:00, so the range ran to EOF and swept in
everything after the window. "In range" and "no end pattern found" produce identical
output.

  • Occurred twice before being caught.

2. A control group that returned zero for an unrelated reason

  • Question: did the stuck session fail to emit event X, specifically?
  • Probe: count X for the stuck session in a window; control = count X for a

different session in the same window.

  • Returned: target 0, control 0.
  • Truth: the target genuinely did not emit; but the control was 0 because nothing

emitted in that window.

  • Mechanism: a control that is zero for its own reasons cannot certify the target's

zero. The comparison became discriminating only after finding a session that DID emit
inside that exact window.

3. A missing log line read as missing behaviour

  • Question: did the retry path ever fire?
  • Probe: grep -c "Upstream idle, retrying" log0
  • Truth: undecidable from that probe — the substring retrying appears nowhere

in the log, so the code path may simply not log.

  • Mechanism: "behaviour absent" and "behaviour not instrumented" share the output

0. The discriminating signal was a different event the retry path must emit
regardless of logging.

4. Grepped a file that had rotated mid-investigation

  • Question: does the log contain the diagnostic that would confirm the hypothesis?
  • Probe: grep pattern current.log0
  • Truth: the log had rotated between two commands; the evidence was in log.1.
  • Mechanism: "not present" and "you are reading the wrong file now" share 0. This

was one sentence away from being written up as "hypothesis refuted".

5. A mutation test whose anchor did not exist

  • Question: does this test actually bind to the code I changed?
  • Probe: replace the implementation with a broken version, re-run, expect red.
  • Returned: green — reported as "the test is inert".
  • Truth: the str.replace anchor spanned a line break and matched nothing. Nothing

was mutated.

  • Mechanism: "mutation applied, no effect" and "mutation never applied" share a

green run. Fixed by asserting the anchor exists before mutating — a one-line change
that converts a silent no-op into a loud failure.

6. Probed a test file's strings against a compiled binary

  • Question: did this commit's code get compiled into the deployed binary?
  • Probe: picked a string from the commit, strings binary | grep -c0
  • Truth: the string was chosen from a test file, whose contents are never in a

production binary. The zero carried no information either way.

  • Mechanism: "not deployed" and "probed something that could never be there" share

0. Same shape recurred later with a source comment — comments are stripped at
build.

7. A green test that was inert against the fix it claimed to cover

  • Question: does the fix cover failure shape B (as well as shape A)?
  • Probe: added a test case for shape B; it passed.
  • Truth: measured afterwards by disabling the fix — the shape-A case turned red and

the shape-B case stayed green. It never exercised the fix, and structurally could
not reach the production condition (the test harness mocks the module the mechanism
lives in).

  • Mechanism: "covered and passing" and "not covered, therefore passing" share

green. Left as written it would have been a green light over the exact residual risk
the accompanying bug report flagged.

8. A liveness gate scoped one level narrower than the thing it guarded

  • Question: is anything running on this daemon (before restarting it)?
  • Probe: GET /sessions?directory=<one project>0 → "safe to restart"
  • Truth: the daemon is per-USER, not per-project. Four sessions were live in three

other projects. An unscoped endpoint existed the whole time.

  • Mechanism: the command is correct for "is anything running in this project" and

has zero discriminating power for the question actually asked. Nothing in the
command's text reveals the mismatch. Two restarts were performed under this blind
spot before a human caught it.

9. A gate predicate corrupted by the very bug being repaired

  • Question: is anything actively working?
  • Probe: count sessions with state == "running".
  • Truth: the defect under repair leaves sessions stuck in that exact state.

Sessions stranded weeks earlier still reported running, so the gate could never
reach zero and a wait loop built on it would have waited forever.

  • Mechanism: "working" and "died and never cleaned up" share the value running.

Freshness (has it advanced recently?) is what discriminates. Caught by a human
observing that the reported sessions were not actually active.

10. A guard added to a code path the case in question never takes

  • Question: does the new pre-flight disclosure run?
  • Probe: invoked the function directly — correct output; syntax check passed;

the wiring was one line.

  • Truth: it was wired into a function called only on the graceful path, while

the forced path — the one that bypasses the existing safety gate and therefore most
needs the disclosure — never calls it. Discovered only by running the real command
and noticing nothing printed.

  • Mechanism: every check answered "does this function work". None asked "does it

run". This occurred in the commit that added a guard against this exact class.

11. Self-matching process probes

  • pgrep -f 'X serve' matched the model's own shell, returning it as if it were a

stale server process.

  • pkill -f "until [ ..." matched and killed the model's own command (exit 144).
  • Mechanism: the probe's own invocation is part of the process table it searches.

---

Root cause, stated generally

A probe's discriminating power is a property of the pair (command, question) — never
of the command alone.

git status --porcelain -- <paths> is exactly right for "are these paths dirty" and
has zero discriminating power for "did I stage them" (on a tree with any concurrent
writer it is non-empty either way). Same command, two questions, one correct and one
useless.

The consequence is what makes this class hard: reading the command text can never
reveal the mismatch.
Code review cannot catch it. Type checking cannot catch it. A
more careful writer cannot reliably catch it, because the error is not in the writing.

The only mechanism that catches it is a control: run something that must return a
DIFFERENT value, and check that it does.

What consistent correct behaviour looks like

For any probe whose output will be quoted as evidence:

  1. Write the exact predicate beside the command. One sentence: "asks whether X".

A check with no stated purpose cannot even be judged wrong — nobody can say whether
it achieved its aim.

  1. Ask "will this go red when it should?" and answer it with a control, not with

reasoning. A positive control (same probe, target that certainly exists → non-empty)
and, where the claim is an absence, a negative control.

  1. Re-verify the source of truth has not moved between observation and conclusion

(file rotated, tree changed, process restarted).

  1. **Before mutating anything to prove a test binds, assert the mutation anchor

exists.** Otherwise a no-op mutation "proves" the test is inert.

The model performed all four correctly many times in this same session. The request is
consistency, not new capability.

Suggested direction

Because the defect is not visible in the command text, "be more careful" cannot fix it.
What would: treating a control as part of the default shape of an evidential probe,
the way a try implies a catch — so that emitting a bare probe whose result will be
quoted is the unusual act, not the normal one.

Explicitly not claimed

  • No cross-model comparison. One session, one model, no baseline. Nothing here

says other models do better or worse.

  • Not a frequency measurement. A second instance of the same model, running under a

different harness on the same day, self-reported four instances of this class and
named the same root cause in its own words. That corroborates that the class is real;
it does not measure a rate.

  • Not an inability to detect. The model self-caught 8 of 11. The complaint concerns

the 3 that were not caught, and the silence of the failure mode — not a claim that
the model cannot recognise it.

View original on GitHub ↗