Skip to content

fix(sqlite): apply limit after reordering in getUserPromptsByIds (follow-up to #2153)#3347

Open
justindeisler wants to merge 1 commit into
thedotmack:mainfrom
justindeisler:fix/user-prompts-limit-before-reorder
Open

fix(sqlite): apply limit after reordering in getUserPromptsByIds (follow-up to #2153)#3347
justindeisler wants to merge 1 commit into
thedotmack:mainfrom
justindeisler:fix/user-prompts-limit-before-reorder

Conversation

@justindeisler

Copy link
Copy Markdown

Follow-up to #2153.

That fix added 'relevance' support to all three SessionStore hydration methods. getObservationsByIds and getSessionSummariesByIds also got the matching limit handling; getUserPromptsByIds did not, and still has the original behaviour.

The divergence

Both siblings guard the LIMIT and slice after the reorder:

const limitClause = limit && !preserveIdOrder ? `LIMIT ${limit}` : '';
...
const ordered = ids.map(id => rowMap.get(id)).filter(...);
return limit ? ordered.slice(0, limit) : ordered;

getUserPromptsByIds has neither — it applies LIMIT unconditionally and returns straight from the reorder.

Why that breaks

Under orderBy: 'relevance' the ORDER BY clause is deliberately empty, so SQLite is free to satisfy the LIMIT directly from the id-index scan — in ascending rowid order. The method therefore truncates to the oldest n candidates and only then permutes the survivors into caller order. A caller passing a ranked id list loses its top hits before the reorder ever runs.

Concretely, with 5 prompts requested highest-id-first and limit: 3, it returns one row rather than the caller's top 3: SQL keeps the three lowest ids, then the reorder discards the two of those that aren't in the caller's first 3.

Scope

This is latent, not user-visible. No caller in the tree passes 'relevance' to this method today, so nothing currently misbehaves — I'd rather say that plainly than oversell it. It bites the moment a caller does, which is the case #2153 set out to make safe, and the asymmetry between the three methods is the kind of thing that's much cheaper to fix now than to debug later.

Changes

No behaviour change for any existing caller: with preserveIdOrder false the generated SQL and the return value are identical to before.

Verification

bun test tests/services/sqlite/ tests/worker/   # 298 pass, 0 fail
npx tsc --noEmit                                # clean

Branched from main at f5633c1 (v13.11.0).

Follow-up to thedotmack#2153. That fix added 'relevance' to all three SessionStore
hydration methods, but getUserPromptsByIds only received half of the
treatment its two siblings got.

getObservationsByIds and getSessionSummariesByIds both guard the LIMIT on
!preserveIdOrder and slice after the reorder:

    const limitClause = limit && !preserveIdOrder ? `LIMIT ${limit}` : '';
    ...
    const ordered = ids.map(id => rowMap.get(id)).filter(...);
    return limit ? ordered.slice(0, limit) : ordered;

getUserPromptsByIds has neither. Under orderBy: 'relevance' the ORDER BY
clause is empty, so SQLite satisfies the LIMIT straight from the id-index
scan in ascending rowid order. The method truncates to the OLDEST n
candidates and only then permutes the survivors into caller order -- so a
caller passing a ranked id list loses its top hits before the reorder ever
runs. With 5 prompts requested highest-id-first and limit 3, it returned a
single row instead of the caller's top 3.

This is latent rather than user-visible: no caller in the tree passes
'relevance' to this method today. It bites the moment one does, which is
exactly what thedotmack#2153 set out to make safe.

The method is now byte-identical in shape to its two siblings. Two tests
added to the existing thedotmack#2153 suite; the first fails without this change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes relevance-ordered prompt hydration in the SQLite session store. The main changes are:

  • Defers limit for getUserPromptsByIds until after caller ID order is restored.
  • Keeps the existing SQL LIMIT behavior for date-ordered prompt lookups.
  • Adds tests for limited and unlimited orderBy: 'relevance' prompt hydration.

Confidence Score: 5/5

Safe to merge with minimal risk.

The code change is small and matches existing sibling method behavior. Tests cover the changed limited and unlimited relevance-order paths.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • Executed the broader SQLite and Bun worker test suite to capture the overall test run metadata, including timestamps, working directory, pass/fail counts, and exit status.
  • Executed the focused relevance regression test to confirm targeted behavior and record its pass/fail results.
  • Performed the TypeScript no-emit type check to verify compile-time checks completed with no emitted outputs.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
src/services/sqlite/SessionStore.ts Aligns getUserPromptsByIds with sibling hydration methods by applying limit after relevance-order reordering.
tests/services/sqlite/get-observations-by-ids-relevance.test.ts Adds tests for getUserPromptsByIds relevance ordering with and without limit.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
  participant Caller
  participant Store as SessionStore.getUserPromptsByIds
  participant DB as SQLite

  Caller->>Store: ids ranked by relevance + limit
  Store->>DB: SELECT prompts by ids without LIMIT when preserving id order
  DB-->>Store: matching prompt rows
  Store->>Store: map rows by id
  Store->>Store: reorder rows to caller id order
  Store->>Store: slice reordered rows to limit
  Store-->>Caller: top ranked prompts
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
  participant Caller
  participant Store as SessionStore.getUserPromptsByIds
  participant DB as SQLite

  Caller->>Store: ids ranked by relevance + limit
  Store->>DB: SELECT prompts by ids without LIMIT when preserving id order
  DB-->>Store: matching prompt rows
  Store->>Store: map rows by id
  Store->>Store: reorder rows to caller id order
  Store->>Store: slice reordered rows to limit
  Store-->>Caller: top ranked prompts
Loading

Reviews (1): Last reviewed commit: "fix(sqlite): apply limit after reorderin..." | Re-trigger Greptile

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