Skip to content

feat(recall): add corpus browser page - #1243

Open
wesm wants to merge 7 commits into
mainfrom
feat/recall-page
Open

feat(recall): add corpus browser page#1243
wesm wants to merge 7 commits into
mainfrom
feat/recall-page

Conversation

@wesm

@wesm wesm commented Jul 23, 2026

Copy link
Copy Markdown
Member

Adds Recall as a top-level page for browsing accepted distilled entries across sessions. The page provides lexical search and project, type, active extraction-generation, and review-state filters while preserving provenance warnings and transcript evidence links. Unsearched browsing uses bounded keyset pages; ranked searches retain existing relevance semantics, reject continuations after any entry or evidence mutation, and explicitly disclose the existing 500-result cap. Read-only backends omit the navigation destination, and direct Recall URLs show an unavailable state without issuing unsupported requests.

A read-only status card reports the configured extraction generation’s coverage, backlog, failures, units, and entry count. The HTTP response omits generation request configuration, and unconfigured servers present an explicit inactive state. Activation, retirement, and the separate Insights relocation remain follow-up slices.

Distilled entries need a corpus-wide inspection surface so extraction coverage and output quality can be assessed beyond one transcript. Expose read-only manager coverage and exact review-state filtering while keeping the first page bounded and management actions out of this slice.
@roborev-ci

roborev-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown

roborev: Combined Review (5f8ae7a)

The Recall browser is generally sound, but two medium-severity usability gaps should be addressed.

Medium

  • frontend/src/lib/components/recall/RecallPage.svelte:91 — The generation selector includes building and retired generations, while entry requests omit status and therefore return only accepted entries. Because machine-generated entries for building and retired generations are archived, selecting those generations misleadingly shows an empty result set. Limit the selector to active generations, or include archived entries and display their lifecycle status.

  • frontend/src/lib/api/recall.ts:15 — Results are permanently capped at 200 with no pagination, load-more action, or truncation indicator, making entries beyond the first page inaccessible. Add cursor-based pagination to the endpoint and UI, along with a total or truncation indicator.


Reviewers: 2 done | Synthesis: codex, 11s | Total: 7m11s

A fixed first page made older accepted entries unreachable, and exposing non-active extraction generations offered filters whose entries are not served by the browser. Cursor-bound pages keep the browse surface bounded without silently truncating the corpus, while active-only generation choices align the filter with the accepted-entry lifecycle.
@roborev-ci

roborev-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown

roborev: Combined Review (c3f7ef0)

The PR adds useful Recall browsing features, but it introduces a material search-semantics regression that should be fixed before merging.

Medium

  • internal/server/recall.go:105 — Recall search bypasses the ranked query path. Requests containing q now use the raw recency-ordered list query instead of QueryRecallEntries. This breaks direct/HTTP parity and loses full-text, evidence, and metadata matching, relevance ordering, and score metadata. Queries containing only ignored terms may also return the entire unfiltered corpus.

    Suggested fix: Preserve the ranked query path for the existing API, or add a separate, explicit recency-paginated browser mode with equivalent search semantics. Normalized queries containing no searchable terms should return an empty result.


Reviewers: 2 done | Synthesis: codex, 8s | Total: 7m18s

Cursor pagination must not change the established GET search contract. Keep recency keysets for unsearched corpus browsing, but page searched requests over the ranked query path so evidence and metadata matches, relevance ordering, scores, and ignored-query handling stay aligned with direct Recall queries.
@roborev-ci

roborev-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown

roborev: Combined Review (ef454cd)

The PR has one medium-severity pagination consistency issue; no material security regressions were found.

Medium

  • internal/server/recall.go:212 — Ranked pagination reruns searches against the current corpus and slices by offset. If background extraction inserts a higher-ranked entry between page requests, results can shift, causing duplicate or skipped entries; duplicate IDs can also conflict with the keyed Svelte list. Bind ranked cursors to a corpus revision and reject or restart stale pagination, or preserve a stable result snapshot across pages.

Reviewers: 2 done | Synthesis: codex, 9s | Total: 6m45s

Offset pagination is only safe while ranked results refer to the same served corpus. Bind ranked cursors to the monotonic Recall revision and fail closed when it changes before or during a page request; the browser restarts from page one instead of appending a shifted result set.
@roborev-ci

roborev-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown

roborev: Combined Review (60be1b3)

Changes requested: ranked pagination has two medium-severity correctness issues.

Medium

  • internal/server/recall.go:233 — Ranked cursors use RecallCorpusRevision, which does not track all fields affecting ranked membership or ordering, including metadata, evidence, review state, and trusted-only fields such as provenance_ok. Mutations can therefore cause skipped or duplicated entries. Use a dedicated pagination revision covering every relevant field and evidence mutation.

  • internal/server/recall.go:240 — Ranked pagination treats MaxRecallEntryLimit as a cumulative cap, so searches with more than 500 matches silently stop at 500 and reject subsequent cursors. Implement true offset/keyset pagination with a per-page limit, or explicitly expose the truncation.


Reviewers: 2 done | Synthesis: codex, 7s | Total: 6m25s

Ranked cursors need a revision covering every entry and evidence mutation, not the narrower embedding freshness counter. Install a dedicated query revision for stable continuation checks, and make the existing 500-result ranking boundary explicit in both the API and browser instead of silently ending pagination.
@roborev-ci

roborev-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown

roborev: Combined Review (440a110)

Medium-severity cursor invalidation bug found; no high or critical issues identified.

Medium

  • internal/db/recall.go:365 — A full resync copies the old query revision unchanged. If every old Recall entry is omitted because its source session was not preserved, no entry/evidence trigger advances the revision, leaving ranked cursors valid even though the corpus is now empty.
    • Fix: Ensure the replacement revision is strictly newer whenever copying an existing corpus, and add coverage for an all-entries-skipped resync.

Reviewers: 2 done | Synthesis: codex, 7s | Total: 9m58s

A replacement archive can legitimately preserve none of the prior Recall entries. Ranked cursors still need to fail closed in that case, so the copied query revision must advance even when no row-level triggers fire. The HTTP read-only fixture also needs to model the new list endpoint instead of accidentally serving from its embedded SQLite store.
@roborev-ci

roborev-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown

roborev: Combined Review (d117939)

The Recall browser is sound overall, but needs a read-only-mode availability guard before merging.

Medium

  • Recall is unusable in PostgreSQL/read-only modefrontend/src/lib/components/layout/AppHeader.svelte:84

    The Recall tab and route are exposed unconditionally, while PostgreSQL/read-only stores return ErrReadOnly for Recall queries. In supported pg serve mode, the page always reports a loading error.

    Fix: Hide or disable Recall when sync.readOnly/settings.readOnly is true, and handle direct /recall navigation with an unavailable state or redirect.


Reviewers: 2 done | Synthesis: codex, 8s | Total: 12m58s

Recall storage is unavailable through read-only backends, so advertising the browser leads users to a page that can only fail. Wait until backend capability is known, omit the navigation destination when Recall cannot be queried, and keep direct URLs on an explicit unavailable state without issuing unsupported requests.
@roborev-ci

roborev-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown

roborev: Combined Review (0d6be12)

No Medium, High, or Critical findings; the reviewed changes are clean at the requested severity threshold.


Reviewers: 2 done | Synthesis: codex, 6s | Total: 9m13s

@wesm

wesm commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

I need to do some QA on this before merging

@mjacobs

mjacobs commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

I tested #1243 locally end-to-end this evening.

test setup: checked out the PR, pointed [recall.extract] at gemma-4-31B-it-qat behind llama.cpp (OpenAI-compatible endpoint) on a RTX 5090, and ran the full extract → activate → browse flow against:

synthetic archive

a first test (testfixture-generated, ~14 sessions) to shake out the pipeline before committing a several GPU hours processing my real session data.

Looks good, no functional issues. extract doctor → clean probe on the first try, extraction ran with zero schema failures (Note: llama.cpp enforces the json_schema response format with grammar-constrained decoding, so a local gemma that was never tuned for this still produces valid entries every time; IME gemma/gemini wouldn't always do that naturally).

my real session data

Same setup with real data completed in a few hours (I don't have specific timestamps off hand, but it was a few hours) processed 483 sessions with 5 sessions that couldn't complete the extraction. Note that 488 sessions was a small subset of my overall session data, but those were the sessions that were eligible for extraction given the expected constraints of the extraction (tl;dr protecting potentially sensitive data).

Recall UI

Recall page does what the PR description claims: status card with coverage/backlog, project/type/generation/review-state filters, lexical search flipping between keyset and ranked pagination, and the evidence links jump to the source transcript at the right ordinals.

Screenshot:
snippy_1784867769694
(I blurred several text blocks)

Some minor adjustments to the UI may be worthwhile aesthetic enhancements, but definitely not blocking IMO.

@wesm

wesm commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

Thank you. I'll work on making the UI less ugly! I'm not sure the 3-column layout is useful either

@roborev-ci

roborev-ci Bot commented Jul 24, 2026

Copy link
Copy Markdown

roborev: Combined Review (0d6be12)

No Medium, High, or Critical findings; the changes look clean overall.


Reviewers: 2 done | Synthesis: codex, 3s | Total: 23m37s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants