---
name: discriminator-question
description: "An assertion both right and wrong code satisfy proves nothing — ask \"what arrangement makes right and wrong answer DIFFERENTLY\" instead of re-reading the test; six instances on 2026-08-01, incl. a vacuous row written into a REQ gate at mint and an argument that only gates WHETHER there is an output"
metadata: 
  node_type: memory
  type: feedback
  originSessionId: b34cabf6-2098-41af-b492-dc8e22aa8675
  modified: 2026-08-03T06:09:52.555Z
---

An assertion that the intended behavior satisfies — but the bug satisfies too — was never evidence. Four instances in one session (HANDRAIL, 2026-08-01):

1. BTreeMap exact-match-wins fixture queried the UPPERCASE key with both spellings present — ASCII uppercase sorts first, so exact-match and scan-first answered identically; only the lowercase query discriminates.
2. Claim-inertness row compared claim-absent vs claim-forged over an AMBIENT store — empty store admits everyone, both sides agreed for an unrelated reason; needed a CONTROLLED store (claimed admitted, proven refused).
3. Delete-source refusal asserted exit-1 — but the invocation failed anyway further along for an unrelated reason (no dialable address); exit codes are SHARED outcomes; assert the refusal outcome itself plus that the same call WITHOUT the flag is not that refusal.
4. (Cousin) uniform-table blindness — [[uniform-table-blindness-sweep]].

5. **The gate clause of a REQUIREMENT, at mint** (DOORBELL W2, 2026-08-01) — doyle ruled a unit row into a REQ text: "a walk over every named site's rendered help asserts no internal code appears." Green-by-default twice: every shipped site is already clean, so it passes even if the walk enumerated ZERO sites, and passes whether or not the predicate can detect a code at all. He named it himself on acceptance — the setup-suppresses-failing-arm class **wearing a gate row**. Repair: pin the enumeration (assert it visited exactly the named set) AND prove the predicate can fail against a fixture carrying the thing. Without the first it proves nothing about coverage; without the second, nothing about detection.

6. **An argument that only changes WHETHER THERE IS AN OUTPUT** (DOORBELL W4, 2643317) — the inert-rule repair set `authority` and `admit_node`, but both are inputs to `apply_mutation`'s PERMISSION check, not to the rule bytes it writes; the widening gate fires only under `OwnerAgent`, so on a fixture where the write succeeds either way, defect and repair emit BYTE-IDENTICAL rules. A discriminator comparing OUTPUTS can never see an argument that only changes whether an output exists. Repair: arrange the answer to DEPEND on the argument — ROW A a policy-FORBIDDEN widening with the ack given (refused under the mint-recorded owner seat, waved through by the node-sovereign seat), ROW B a record saying no ack given; both directions, plus a non-vacuity row (ack given AND policy allowing → redeems/writes/spends) so the refusals are not a verb that refuses everything.

7. **A COVERAGE-STAGE ACTIVATION** (v0.51.0 doc respin, 235fe5a) — activating `doc` on a REQ to guard a page that had drifted unwatched. `traceable-reqs` reports the stage satisfied from ANY tag anywhere in the tree, so if that REQ already carried a `doc->` tag in some other file, the activation goes green while the page it was meant to guard stays exactly as unguarded as before — paperwork wearing a guard's clothes. Discriminator: grep that the new tag is the SOLE evidence for that REQ, then delete that one line and require exit 1. Both halves — sole-source and can-fail — or the activation proves nothing.

8. **EVIDENCE I AUTHORED, while auditing everyone else's instruments** (IR-18, 2026-08-03) — "the daemon wrote NOTHING to stderr, so it was killed; silent death with an empty log is TerminateProcess, not a slow box." hertz's negative arm killed it: on a PASSING run that rig's daemon stderr is empty too, so the observation is present in both arms and carries zero information either way. I had spent the same night refusing other people's absence-proxies (a blind KILL_REFUSED zero, a blanket zero-REFUSED gate) and did not turn the rule on a sentence I was writing into the register — where it reached SIX sites, including a triage instrument telling a future reader to discriminate two entries by it. Tell: an ABSENCE offered as positive evidence, with no negative arm run. Related cousin: a category error rode along — "bare exit 1 and no panic" (a victim TEST PROCESS dying) was mapped onto "empty daemon.stderr.log" (a log), two different processes and two different artifacts read as one observation.

**Why:** passing is only evidence when failure was reachable; the discriminator question is not answerable by reading the test — it needs the arrangement analyzed against BOTH readings. A "compare the outputs" test is blind to any input that gates whether the output is PRODUCED — check the argument's real consumer (a permission check, an early return) before trusting an equality assertion.

**How to apply:** for every mutation-survival, and for every fixture pinning a precedence/priority/ordering property, ask what arrangement makes the two readings disagree and build THAT. A mutant surviving usually means the test is wrong, not the mutant weak. **Apply the same audit to REQ gate clauses when they are MINTED, not only to the tests that later satisfy them** — a vacuous row written into a requirement is worse than a vacuous test, because it reads as the standard and every later test is measured against it. A row over an "everything is clean" property is the tell. **Turn it on your OWN evidence before writing it into a durable record** — an absence ("nothing in the log", "no lines matched") is never positive evidence until a passing run is checked for the same absence, and a claim in a register propagates into triage instruments where it silently stops discriminating.

Related: [[instrument-soundness-guards]], [[stacked-defects-mask-each-other]].
