fix(localization): authenticate terminal evidence and always hand back an answer - #331
Merged
zzet merged 33 commits intoJul 26, 2026
Merged
Conversation
A ranked head that already answers the request was downgraded to a bounded recovery call whenever it lacked one of the narrow provenance shapes, and a prescribed exact read was issued even when the envelope could carry that body itself. Both spent a caller turn to return evidence the first page had. The provenance proof now gates hard enforcement only. Terminality follows the ranking, and the authorized symbol's body packs first so a prescribed read that this page can satisfy collapses into it — under the same lead-alignment bar the reserved read applies on completion. The ready-to-emit answer is built after byte packing, so oversized pages shed source bodies rather than overrun the envelope budget.
… for it verbatim The ready-to-emit answer was rendered without the request in hand on the page that produces it, so its presented rows fell back to insertion order and only a later merge ever scored them against the task. Measurement also kept finding answers that swapped the located identifier for a neighbouring one inferred from the request text, losing the symbol the page had already found. Thread the request into digest construction, and make the terminal directive and the host-side terminal context ask for the located lines verbatim before any explanation.
Two head-slot leaks fed the same failure: an answer that never showed the code that changes. The production/test partition trusted only the indexer's is_test stamp, so test assemblies whose sole marker is a path token kept production slots; and the quoted-recall coverage check treated a request-level anchor on one candidate as proof that every quoted term was already covered, which silenced the bounded literal lane for compact values. Share the draft test detector at the partition — exempting requests that are about test code or that name the candidate outright — and settle compact values from declaration text alone.
…ven evidence Ranked confidence is not always right: a page can be judged answer-ready while none of its rows mention what the request is about, and that is exactly where the bounded second call used to earn its keep. Completing those pages traded a correct answer for a saved turn. Terminality without a provenance proof now also requires packed evidence that carries the request's lead — the same alignment bar the reserved read clears before it may end a session. A request the server cannot evaluate (no task text) keeps the ranked verdict, since there is nothing to disagree with.
The answer asked the caller to reproduce its localization lines verbatim while showing only three primary and four supporting rows, so a retained row outside that window was evidence the page had found and then hidden — and the caller was being told to answer from the window. Present the whole retained set, and make the byte budget honest about it: an enriched envelope over budget now gives back its weakest presented row before it sheds any packed source body.
The terminal completion carried no instruction at all, so a host that reads completion.instruction — the field every non-terminal state populates — learned nothing about what to do with the answer it had just been handed, and the ambient workflow told agents only to stop calling tools. Populate the terminal instruction and prime the workflow to open the reply with the returned lines quoted verbatim, inside the profile's existing byte ceiling.
A terminal page replaced its structured payload with the answer lines alone, so a host that renders structured content showed the caller seven file:symbol lines and no code. The caller did the reasonable thing and went looking for the source — spending a turn to be told it already had the answer. Mirror the packed envelope into the terminal projection so files, symbols, ranked rows and the head's body stay beside final_response.
The terminal projection replaced structured content outright, and a host that renders structured content in preference to text then saw only the answer lines. On the localize page that meant an answer with no evidence; on the one authorized read it meant the caller was handed a completion instead of the source it had just been permitted to fetch. Decode the tool's own payload and keep it beneath the terminal keys, so every page that ends navigation still carries the evidence it ended it with.
A blocked post-terminal call returned a bare refusal, so the caller had nothing to act on and reached for the next tool instead — measured at up to seven consecutive denials in one session, draining the turn budget until the reply was truncated. Carry the retained answer on the terminal marker and append it to the refusal, so the first blocked call already contains everything the caller needs to finish the turn.
This variant keeps every change that gives the caller more to work with — the preserved terminal payload, the answer carried on a refusal, compact-value recall, the emit contract — and restores the bounded second call that ranked readiness alone used to skip. Measured at N=1 over the localization suite it is the strongest accuracy configuration of the three (symbol 22/28 against 21 for the base and 20 with terminality) while still cutting median cost, which is why the terminality half is held here rather than shipped on its evidence so far.
The terminality tests travelled with the revert and kept asserting that unproven ranked evidence ends navigation, which is exactly what this branch does not do. Re-point them at the contract that is actually in force — one bounded call for unproven evidence — and give the terminal-payload test a provenance-proved fixture, so it tests what a terminal page CARRIES rather than when a page becomes terminal.
Asking for the located lines verbatim raised median output tokens ~40% against the unmodified engine, and output is the most expensive token class in a session. The contract compounded it by inviting an unbounded explanation on top of evidence the caller had just been told to quote. Keep the verbatim block — measurement shows the located symbol reaches the answer through a supporting line in roughly a quarter of hits, so the block cannot be narrowed — and bound only the free-form half.
…ings The bounded relation slot already existed to carry a wrapper-to-implementation hop, but it chose by task-term overlap — and a helper shares every term its wrapper matched, so the pair can never separate and the wrapper's unrelated siblings win on list order. Measured consequence: the code that actually changes reaches the session inside a source body and never as a row, so it cannot reach the answer at all. Recognise the delegation by the one convention that holds across languages — the implementation's identifier extends the wrapper's with a short suffix — and rank it ahead of overlap. The base floor keeps the variant family (Load/LoadAll) out, since those are sibling operations rather than helpers.
The terminal projection emitted the answer block at the top level and again on the completion that sits beside it, with the closing directive inside both. On a terminal page that is the most expensive place to repeat oneself — measured at 1,185 duplicated characters, about 30% of the page, billed at the cache-write rate. Keep the authoritative copy on the completion and leave the directive at the top level as the pointer to it.
Measured across 336 sessions: a terminal page that ordered the caller to reproduce its lines verbatim drew an explicit manipulation accusation in 30% of the caller's own statements, against 2% on pages without that wording. The rate was zero before the wording landed. Ordering a caller to recite a page it judges wrong reads as coercion — and its judgement is right more often than not, since the pages it rejects carry a ground-truth row only a quarter of the time. Ask for the answer, name what the answer should carry, and say plainly that disagreement belongs in the reply rather than in another navigation call.
…answer The retained digest filled from the terminalizing call's rows first, under a hard ten-row cap. A targeted read returns one row and that ordering is right; a broad search returns twenty, and every ranked localization row was evicted — so the answer was assembled entirely from the caller's last query. Measured: a session ranked the ground truth FIRST, the caller read exactly that symbol, then searched for build configuration, and the answer shipped three build-config rows with the located file absent even from the supporting rows. Fresh rows still lead, bounded by a reserve, and give back whatever the localization does not need.
…its words Prose separates what an identifier joins. A request naming its subject in separated words tokenizes to terms that never intersect the symbol spelling that subject as one word, so the acceptance test refused the very symbol the contract had just prescribed. Match a candidate term against a requested term plus its remainder, on both the task-overlap and lead-overlap counters and on a recovery row's own name. The bar itself is unchanged: evidence that merely echoes the reported symptom, or that carries the request's words only in its signature, is still refused.
…s proven Every state but answer_ready cleared final_response, so a session that ran out of steps or stopped early returned nothing at all — one measured session in five. The rows were already ranked and packed at that point; only the confidence to call them an answer was missing. Non-terminal states now carry the same rows as an explicitly unconfirmed page, with its own heading and closing line so it can never be mistaken for the proven one, and never carrying the directive that ends a session. The page is deliberately terse and is the first thing shed when an envelope overflows: it restates identities the envelope already holds, so buying it with evidence rows would cost the caller information to keep a copy. States outside a localization flow, and states that ranked nothing, still carry no page — boilerplate with no identities in it is bytes, not an answer.
While a localization marker is live, a host read fell through to the access policy, which answers with "call a Gortex graph tool instead" — and the marker then refused exactly that call. Measured across recorded sessions: 26 such pairs in 20 sessions, the advised tool being a host read, grep or glob in 22 of them. Each pair spends a turn and teaches the caller nothing. The marker now answers those host tools itself, handing back the retained evidence instead of prescribing a step it will not honour. Tools the access policy would not redirect into a graph call keep passing through, so a non-enforceable answer gains no wider reach.
…acked The check for a prescription the page already answers existed and was unit tested, but nothing ever called it, so callers kept paying a round trip for bytes the engine could have shipped. Wire it in, and apply it to refinement pages as well as exact reads. Body and instruction move together or not at all: a page that inlines the source and still commands the read leaves the caller doing both, which costs payload and saves no call. And when the evidence policy will not stand behind the retirement it demotes an unproven answer to a recovery page — a worse offer than the bounded read — so that case restores the prescription and its bytes.
An envelope over budget shed its candidate page before anything else, so the answer a caller would use if it stopped there was the first thing sacrificed to keep a source body it could still fetch. Measured on recorded first calls, only 11 of 28 responses reached the caller with a page. Shed packed bodies and surplus digest rows first. The page goes only when nothing else can be given back, and even then only if going makes the response fit — dropping it from an envelope that is over budget either way costs the caller its answer and saves nothing.
A page fills its byte budget with ranked rows, so an ordinary body overflowed it by a few hundred bytes and was refused — and the caller then spent a whole round trip fetching those same bytes. That trade is backwards: inline they are paid once, as a round trip they are paid again as a fresh request, its cache write and its output. Allow a bounded overshoot for the one body that removes a call: never below the minimum real budget, never more than half again, and only when the bytes actually retire or release the read. The shed loop honours the same limit, so it cannot claw back the bytes and reinstate the call they just avoided. Body and instruction move together. Evidence that clears the alignment bar becomes an answer; evidence that does not still stops commanding a read of what it just shipped, while claiming nothing about ranking and forbidding no tool. A prescription that still authorizes several candidates keeps its read — shipping one of them answers nothing and leaves the rest to fetch.
A symbol's exposed ring was filled in retrieval order, so a file with many neighbours could take every slot. The symbol a request is actually about is often in the second file — inside the full ring, past the prefix the crowded file left behind. Give each file a share of the slots before any file takes a second helping. Neighbours held back are not dropped: they fill whatever slots remain once the spread is covered, so the ring is the same size as before and only its composition changes. A ring that genuinely overflows still reports itself incomplete, so no caller can claim uniqueness from a saturated projection.
…ighbourhood" This reverts commit 89528ca.
The predicate was written to keep a page that never names the request's subject from ending a session, but it was never wired to a call site, so it enforced nothing and the linter flagged it. Remove it rather than leave a protection that exists only on paper. The idea is still worth having — a page whose evidence does not carry the request's lead is exactly where continued navigation pays — but reviving it is a behavioural change that needs its own measurement, not a silent re-wiring.
The shutdown-ordering assertion polled a channel non-blockingly the statement after Close returned. That channel is closed from a deferred call in another goroutine, so passing required that goroutine to be scheduled first — a timing property nothing guarantees, and one a loaded runner loses. Wait bounded instead. The defect this guards against is Close returning while the pass keeps running, and no amount of waiting hides that.
…er-fidelity-only * origin/main: (26 commits) claudecode: call the shared instructions-dir resolver directly codex: install a standing rule block and flag untrusted hooks fix(indexer): evict present-but-excluded files on reindex Bump version to v0.61.4 fix(mcp): keep source-literal recall assertions off the wall clock fix(indexer): bound the per-repo trigram searcher cache fix(daemon): report indexed documents, not a since-construction delta fix(indexer): evict from search on the same predicate that admits Restore MCP Toplist badge in README fix(mcp): run graph analysis on demand instead of eagerly test(cli): pin the built-in commands against tool-hint shadowing fix(cli): let the completion command reach cobra's generator fix(index_health): a degraded pass that landed nothing is not ok fix(mcp): let the analysis generation pass the store's validation fix(goanalysis): run go/packages in the module's own directory fix(init): refuse to index the filesystem root or $HOME Bump version to v0.61.3 test(indexer): pin parse-tree release on every incremental path fix(indexer): release parse trees across the prepared-extraction lifecycle fix(indexer): release parse trees on the incremental index paths ...
…ndex The first track call detaches its index on purpose, so whether a following call reports the repo as tracked or as still indexing depends on whether that background work happened to finish — exactly what detaching leaves unspecified. Pinning one of the two wordings made the assertion a race against machine speed. Assert the property the test documents instead: the second call recognises the repo rather than starting over. Both answers satisfy it, and neither hides a handler that forgot the repo.
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.
Summary
Localization always hands back an answer, and stops asking for evidence it already holds.
Terminal evidence (earlier work, unchanged):
answer_readyLOCALIZATIONtuple list soFILES,SYMBOLS, andEVIDENCEretain the same positional identitylocalizedcompletion for a strictly qualified single implementation resultAnswering (new in this update):
answer_readyclearedfinal_response, so a session that ran out of steps returned nothing at all. Non-terminal states now carry the same rows as an explicitly unconfirmed page, with its own heading and closing line, and never the directive that ends a session.Validation
go test ./internal/mcp ./internal/hooks ./internal/profiles— 4030 passedgo build ./internal/...