Skip to content

test(search): re-judge the query whose judged file was deleted - #104

Merged
tae2089 merged 2 commits into
mainfrom
ticket-100
Aug 11, 2026
Merged

test(search): re-judge the query whose judged file was deleted#104
tae2089 merged 2 commits into
mainfrom
ticket-100

Conversation

@tae2089

@tae2089 tae2089 commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Closes #100. Rebased onto main after #101 and #107 landed; every number below is measured on that base.

What this is

A re-judgment of one golden query, with no code beside it. The query why does an answer with nothing in it still suggest another call named two files that no longer answer it:

  • handler_intent.go was deleted with find_by_intent in a3a29d2.
  • handler_query.go stopped building next actions when that hand-off went; the only next it still carries is the paging offset.

Re-judged onto the two files that do answer it now: internal/app/search/wire/wire.go, which is where nextActions and the NextAction contract live, and internal/adapters/inbound/mcp/handler_describe.go, which is the purest form of the same question — describeNextActions returns actions only when the target was not found.

Movement

ccg ALL         0.738 (124/168) 47 62 0.642  ->  0.744 (125/168) 47 62 0.644
ccg ANSWERABLE  0.831 (123/148) 46 61 0.695  ->  0.838 (124/148) 46 61 0.697

top1 and top3 flat. cobra, context-diary and gorm untouched — no fixture was recaptured.

The +1 is wire.go, and it is worth being exact about why: it scores through wire.Limits, not through nextActions or NextAction. The judgment is still right — that file is where the behaviour the query asks about lives — but nobody should read the gain as the ranker having found the next-action code.

Guard

The query's zeroScoreNotes entry is gone, because it now scores. The guard is symmetric and fails on a listed entry that starts scoring, so the entry had to go rather than being left as a stale excuse. The header count follows: nineteen entries, five of them the ranker's own.

testdata/README.md records that an entry has now left that list by being re-judged rather than by being fixed, and states the rule that allows it — a re-judgment may move a number only when it lands as its own change with no code beside it, and the commit says which file scored and why.

Verification

  • CGO_ENABLED=1 go test -tags "fts5" ./... -count=1 — all packages pass
  • go vet ./... — clean
  • gofmt -l . — only the two pre-existing parse fixtures under testdata/binding_gap/go/
  • CI green on 7fe94f3: verify, verify-postgres

🤖 Generated with Claude Code

tae2089 and others added 2 commits August 11, 2026 16:05
`why does an answer with nothing in it still suggest another call` named
two files. One of them, internal/adapters/inbound/mcp/handler_intent.go,
was deleted in a3a29d2 along with the find_by_intent tool, so the answer
key counted two files where at most one could still be found. #99 listed
it as a known gap and said it needed re-judging rather than a ranker fix.
This is that re-judging.

The other named file no longer answers it either. handler_query.go
stopped building next actions when the hand-off to find_by_intent went;
the only `next` it still carries is the paging offset.

The behaviour moved rather than disappeared, and the deletion commit is
narrower than it first reads. It says "search's empty answer no longer
suggests a hand-off", but that is about the hand-off to a second index,
which no longer exists. Two branches of wire.nextActions still fire on a
page with nothing on it: the one offering include_weak when every
candidate was filtered out as weak, and the annotate step when nothing
shown justified itself. So the query is answerable, and now names:

  internal/app/search/wire/wire.go
  internal/adapters/inbound/mcp/handler_describe.go

wire.go holds nextActions and, beside it, NextAction's own comment, which
is the "why" the question asks for in as many words — naming the tool and
its arguments turns a dead-end count into a step. handler_describe.go is
judged with it as the purest form of the question: describe returns
actions only when the target was not found, and a found outline gets
none, so there the empty answer is the only one that suggests a call.

What it costs, stated plainly, because a re-judgment that raises a number
is the move the golden set otherwise forbids:

  ccg ALL         0.720 (121/168) → 0.726 (122/168), MRR 0.636 → 0.638
  ccg ANSWERABLE  0.811 (120/148) → 0.818 (121/148), MRR 0.688 → 0.690
  top1 and top3 flat. cobra, context-diary and gorm untouched.

The +1 is wire.go, which the intent pool already carried at hit 7, file 6
— inside the page of ten. It is worth being exact about why it scores:
the hit is wire.Limits, not nextActions or NextAction. `relevant_files`
judges at file granularity, so any hit in a judged file counts it found,
and by that rule this is a legitimate hit. But the declaration that
matched is not the declaration that answers the question, and a reader
landing there still has to read on. The entry keeps file granularity
because that is the shape it and its bucket already had; changing the
granularity of one query is a different decision from correcting its
answer key, and does not belong in the same change.

handler_describe.go is at hit 30, file 22, and handler_query.go — no
longer judged — is at hit 24, file 21. Both are far past the page.

The zeroScoreNotes entry is gone, because the guard added in #97 refused
to let a scoring query stay filed as a zero:

  "why does an answer with nothing in it still suggest another call" no
  longer scores zero in the baseline; drop its zeroScoreNotes entry so
  the list cannot rot into a silent excuse

That is the guard working as intended, and it is the reason this ticket
could not have been quietly absorbed into another change.

No production code moves here. queries.json, baseline.json, the guard's
own notes and testdata/README.md are the whole diff.

Closes #100

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The commit before this moved the ccg totals and left the block in
testdata/README.md at the numbers from before it. That block is
`make search-eval`'s own output copied whole, and the paragraph under it says
hand-drift is how it went stale once already.

Copied from the harness on this base, not typed: ALL 0.744 (125/168) 47 62
0.644, ANSWERABLE 0.838 (124/148) 46 61 0.697.
@tae2089
tae2089 merged commit 6ef75cb into main Aug 11, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Re-judge "why does an answer with nothing in it still suggest another call": one of its judged files no longer exists

1 participant