Skip to content

fix(localization): authenticate terminal evidence and always hand back an answer - #331

Merged
zzet merged 33 commits into
mainfrom
fix/localization-terminal-evidence-replay-minimal-indexed
Jul 26, 2026
Merged

fix(localization): authenticate terminal evidence and always hand back an answer#331
zzet merged 33 commits into
mainfrom
fix/localization-terminal-evidence-replay-minimal-indexed

Conversation

@zzet

@zzet zzet commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

Localization always hands back an answer, and stops asking for evidence it already holds.

Terminal evidence (earlier work, unchanged):

  • replay terminal localization evidence deterministically after answer_ready
  • authenticate one-shot terminal receipts against the session, tool-use ID, and tool name; reject forged, stale, and replayed receipts
  • distinguish advisory and hard terminal markers so trusted, sufficient evidence can stop graph navigation without blocking unrelated tools
  • preserve primary implementation candidates before relation interleaving, filter unrelated relation rows, and recover unique complementary evidence
  • render one ordered LOCALIZATION tuple list so FILES, SYMBOLS, and EVIDENCE retain the same positional identity
  • add a non-terminal localized completion for a strictly qualified single implementation result

Answering (new in this update):

  • match a request against the identifier that joins its words. Prose separates what an identifier joins, so a request naming its subject in separated words never intersected the symbol spelling it as one — the acceptance test refused the very symbol the contract had just prescribed. The bar is unchanged: symptom-echoing names and signature-only overlap are still refused.
  • hand back the best candidates before the answer is proven. Every state but answer_ready cleared final_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.
  • give back that page last, not first. An envelope over budget shed its candidate page before anything else, sacrificing the answer to keep a source body the caller could still fetch. It now goes only when nothing else can, and only if going makes the response fit.
  • stop advising a call the same turn will refuse. A host read fell through to the access policy, which answers "call a Gortex graph tool instead" — and the marker then refused that call. Measured across recorded sessions: 26 such pairs in 20 sessions.
  • ship the prescribed body instead of asking for it. A page fills its budget with ranked rows, so an ordinary body overflowed by a few hundred bytes and was refused; the caller then spent a whole round trip on those same bytes. A bounded overshoot is now allowed for the one body that removes a call, and body and instruction move together.

Validation

  • go test ./internal/mcp ./internal/hooks ./internal/profiles — 4030 passed
  • go build ./internal/...

zzet added 29 commits July 24, 2026 00:29
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.
@zzet zzet changed the title fix(localization): authenticate and replay terminal evidence fix(localization): authenticate terminal evidence and always hand back an answer Jul 26, 2026
zzet added 4 commits July 26, 2026 08:58
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.
@zzet
zzet merged commit 2b7cdde into main Jul 26, 2026
10 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.

1 participant