feat(brief): build a retrieval brief a receipt can prove - #166
Merged
Conversation
tangletools
approved these changes
Aug 21, 2026
tangletools
left a comment
Contributor
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 759d2c95
This PR was opened by the trusted drewstone account.
This approval is provisional and was applied by the local stand-in because the pr-reviewer webhook host is unreachable (2026-08-21). CI on this head is fully green. The full PR reviewer audit re-runs via the resweep when the service returns and will publish findings if it detects issues.
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.
Why
discovery-lab measured, on 2026-08-19: re-derivation stayed flat at 5.6–11.2% before and after citations shipped, and citing pages re-derived MORE than non-citing ones — 9.6% vs 5.6% (#157, capability 4).
"Search the store first" was a prompt instruction, and an instruction is not infrastructure. The economics of an amnesiac agent favour re-deriving a fact over fishing for it in a 2,000-page pile, so the store loses to the model every time the choice is left to the model. The fix is to hand the run the knowledge before its first token, with the ids ready to cite, and to record what was handed over.
What
buildKnowledgeBrief(visiblePages, question, { limit, excludeInvalidated, tags, kinds, maxChars })returns{ question, retrieverId, retrieverConfigDigest, hits, citationIds, results, text }.textis deterministic Markdown: one- [id] title — snippetline per page, in rank order. Nothing carries a timestamp, so the same page set produces the same brief on every run.resultsis exactly the shapecreateKnowledgeRetrievalReceipttakes, so the caller mints a receipt with no adapter in between. That is what turns "retrieved" from a claim into a record.retrieverIdandretrieverConfigDigestcomplete the receipt's retriever identity. The package cannot know which published version is running it once bundled, so the caller declares onlyversion.excludeInvalidateddefaults to true here, the opposite ofsearchKnowledge. A brief offers every page it names with an id ready to cite; a refuted page in it invites a run to build on a dead claim.searchKnowledgekeepsfalse, because a caller reading history needs those pages.maxCharsbounds the brief, and a page whose line does not fit is left out oftext,hits,citationIds, andresultsalike. A receipt that recorded 7 results while the agent was shown 6 would be worse than no receipt.Pure, Worker-safe, zero new dependencies. It composes the existing ranking, the existing receipt constructor, and the existing origin labels; it adds no second retriever and no second receipt.
Simplification
Simplification:
searchKnowledge(index, query, options)is nowsearchKnowledgePages(index.pages, ...). One ranking implementation with two entry shapes, the index form delegating, so a chain read no longer has to fabricate aKnowledgeIndexto be searched and the two paths cannot drift. The lexical-index guard moved to the same page-set terms.Net: +328 / -14 lines, 9 files, 1 ranking implementation kept (a second, page-set copy avoided), 0 new retrievers or receipt shapes.
Not done here: the brief does not mint the receipt itself, because minting needs a clock, a run id, and an actor, none of which belong to a pure ranking function. The tool adapter is where those meet.
Tests: +3 (a refuted page stays out of a brief unless the caller asks for it, which is the default that protects a run from citing a dead claim; the rendered text, ids, and results describe one identical set under a
maxCharsbound, which is the honesty property of the receipt; the results round-trip into a retrieval receipt that verifies and joins the visibility snapshot, with the config digest matching — the cross-boundary contract that makes retrieval provable), -0 deleted. No shape assertions.Proof
The failing files and their count are unchanged from clean
origin/mainon this macOS host, and every failure raisesknowledge transaction directory escaped its root— the/var->/private/varsymlink undertmpdir().tests/filesystem-search-provider.test.ts, the one search-path file in that set, fails with that same error and fails identically on main. Linux CI has no such symlink.Refs #157