Name the misconception the evidence supports, and let stage 2 say there isn't one - #22
Merged
Conversation
…uiet Stage 1 gains a fifth signal, `explained_it_back`: the developer put the mechanism into their own words and got it wrong. It ranks above `asked_why` because everything below rank 0 is a reason to suspect a gap and rank 0 *is* one. It was also unreachable before — `asked_why` is gated on the quote being a question, and a confident wrong statement corrects nobody. The highest-ranked signal gets a structural gate rather than a paragraph, on the module's own premise that prompting a model to require a quote is not a control: reject it when the quote is a question, and when `shows` names nothing wrong. Demonstrated understanding disqualifies it too — a wrong restatement the developer later says back correctly is a gap that closed inside the session, and spending the session's one question there is exactly what the rule exists to prevent. Stage 2 may now decline: it names the misconception the evidence supports, or says there isn't one. A decline is `declined`, not `error` and not `silent` — triage did keep the session — and it carries its spend, because silence that costs money and reports $0.00 is the outcome nobody audits. `sessions.discard_reason` records why a session that had something to ask about produced no question, from both paths: stage 4 discarding a written question, and stage 2 declining to seed one. Both previously reached only `grask.log`, which rotates at 1 MB under a detached worker. Feeding the reason back into stage 3 was built and reverted — both arms recovered on the two transcripts that survived, so the premise was not observed to hold. Stage 3 stops asserting a mental state it cannot see: `explained_it_back` gets its own frame, mechanism-shaped but without `MECHANISM_FRAME`'s claim that something went past the developer, and the prompt describes a hypothesis drawn from evidence rather than from what the developer "accepted without fully understanding". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
imkp1
force-pushed
the
evidence-not-mental-state
branch
from
August 8, 2026 14:59
3245235 to
cbf3975
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An external review's central objection, which is correct: stage 2 was asked to state "what this developer may have accepted without fully understanding," and nothing in the pipeline observes understanding. Six changes from that review, plus one of my own that did not survive its own measurement and was reverted in the same branch.
Everything here was run against the real model before being claimed to work. Two changes came back with null results and are documented as unproven rather than quietly kept as wins.
The framing
grask sees turns, agent replies, and diffs. It never sees a mind, and asking for a hidden mental state gets one — fluently, on any session at all. Stage 2 now names the most plausible mechanism misconception the evidence supports, and the prompt says what is not evidence for one: the agent introduced the mechanism, the developer asked a question, the developer accepted a suggestion, the pattern looks unfamiliar. Each is evidence only that something happened.
Stage 2 may decline
Triage decides a session is worth looking at. It never decides a misconception is there, and stage 2 — the first stage to see the agent's side and the diff — is the first thing that can tell. It can now answer
{"decline": "..."}, recorded as the new terminal verdictdeclined.Before this, a stage 2 that found nothing had two exits: invent a hypothesis, which teaches the developer the tool is guessing, or trip a structural gate and be filed as a broken pipeline.
declinedis deliberately neithererror(nothing malfunctioned, and that rate is what says whether the prompt works) norsilent(triage kept this session, and the decline rate is the only way to see it collapsing yield rather than trimming it). Invisible to/grask: no question was written, so there is nothing to explain.Two triage changes, both from the review's own counterexample
A developer asks why jitter is needed, gets an answer, and says "right, so the clients don't all retry at the same instant."
asked_whyfires, and it is wrong to.explained_it_back, ranked above everything includingasked_why. It had nowhere to land before:asked_whyis gated on the quote being a question, and a confident wrong statement corrects nobody, so it was notpushed_backeither. Everything below rank 0 is a reason to suspect a gap; rank 0 is a gap.Answerability is stage 4's first question
A stem may name a local file as its setting, but if choosing between the options needs the contents of a local file the question does not quote, no option is a true answer and the judge marks them all false. The no-option-true rejection now carries every option's reason — without it, "the mechanisms are all broken" and "only its author could answer this" are the same string in the log.
What was measured
silent, zero candidatesexplained_it_back;showsnamed the errorscripts/release.shquestioncapture.py, portable mechanismsilent, 3ask, 0error, 0declinedThe 3 discards are correct catches, not over-rejection: the twelve kept include probes anchored on
cmd/bd/create.go,ticks/reaper.py, and.github/dependabot.yml. It is a ~20% yield cut on the current corpus and a bug report against stage 3 — those questions should never have been written. The decline never fired in 3 opportunities, which shows it does not collapse yield and nothing more.Two null results, kept as such
The stage-3 distractor taxonomy. A blind A/B — three seeds, both arms, six questions interleaved and classified by a judge not told which arm wrote which — came back 9 distractors per arm with exactly one banned shape in each. At n=3 that detects nothing. Kept because it costs ten lines and sits where the design says the lever is; the design doc says it is unproven rather than claiming a win.
Feeding the discard reason back into stage 3 (added in 3097bc1, reverted in 3245235). Both arms on the two discarded probes whose transcripts survived: all four re-asked questions passed stage 4, the two blind re-runs included. The premise — that a re-run needs to be told what went wrong — was not observed to hold, and an unproven keyword argument threaded through three modules costs more than unproven prompt text.
sessions.discard_reasonsurvives the revert on its own merits: stage 4's judgment previously reachedgrask.logand stopped, a file rotated at 1 MB and written by a detached worker. It is what makes the locality rate queryable, which is the number the answerability check exists to move.Notes for review
declinedand new nullable columndiscard_reason, both migrated for existing databases.SIGNAL_RANKrenumbers: addingexplained_it_backat 0 shifts the other four down. Selection on an existing corpus will change where a session carries both signals.tests/— the suite must never reach the real CLI.🤖 Generated with Claude Code