Skip to content

fix(search): newest-first context, session lookup, jsts split, ID disambiguation#2065

Closed
thedotmack wants to merge 1 commit intomainfrom
bugfix/search-bugs-2
Closed

fix(search): newest-first context, session lookup, jsts split, ID disambiguation#2065
thedotmack wants to merge 1 commit intomainfrom
bugfix/search-bugs-2

Conversation

@thedotmack
Copy link
Copy Markdown
Owner

Summary

Test plan

  • Verify context preview shows newest observations first
  • Verify SessionStart finds previous sessions in populated DB
  • Verify JS files don't include TS-only node types in outline
  • Verify get_prompts and get_sessions MCP tools work

Closes #1917, closes #1918, closes #1919, closes #1920

🤖 Generated with Claude Code

…ambiguation

- Fix #1917: Sort timeline and day groups newest-first so truncated 2KB
  SessionStart preview shows recent data instead of oldest observations
- Fix #1918: Use consistent cwd fallback (process.cwd()) in session-init
  matching context handler; replace unsafe process.cwd() fallback in
  storeObservation with 'unknown-project' to prevent worker-cwd mismatch
- Fix #1919: Split shared jsts tree-sitter query into separate javascript
  and typescript variants; JS query excludes interface_declaration,
  type_alias_declaration, and enum_declaration which don't exist in
  tree-sitter-javascript grammar
- Fix #1920: Add get_sessions and get_prompts MCP tools with batch
  endpoints (/api/sessions/batch, /api/prompts/batch); update context
  footer, legend, and MCP instructions to disambiguate observation IDs,
  session IDs (S-prefixed), and prompt IDs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 18, 2026

Warning

Rate limit exceeded

@thedotmack has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 33 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 33 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 127bdf26-101a-4cbd-a46f-8c6f9d718d60

📥 Commits

Reviewing files that changed from the base of the PR and between beea789 and 449f6bd.

📒 Files selected for processing (9)
  • src/cli/handlers/session-init.ts
  • src/servers/mcp-server.ts
  • src/services/context/ObservationCompiler.ts
  • src/services/context/formatters/AgentFormatter.ts
  • src/services/context/formatters/HumanFormatter.ts
  • src/services/context/sections/TimelineRenderer.ts
  • src/services/smart-file-read/parser.ts
  • src/services/sqlite/observations/store.ts
  • src/services/worker/http/routes/DataRoutes.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/search-bugs-2

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 18, 2026

Code Review

Overview

This PR bundles four targeted bug fixes: newest-first context sorting (#1917), consistent project-key resolution (#1918), JS/TS tree-sitter query split (#1919), and two new MCP batch-fetch tools for sessions and prompts (#1920). The changes are focused, well-scoped, and the motivation for each is clearly documented.


Issues

1. Wrong store used for prompt lookup (DataRoutes.ts)

handleGetPromptsByIds fetches prompts via this.dbManager.getSessionStore(), which returns a session store. If getUserPromptsByIds is only defined on a prompt/observation store, this will throw at runtime.

// Both handlers share the same store — is this intentional?
const store = this.dbManager.getSessionStore();
const sessions = store.getSessionSummariesByIds(...);  // OK
...
const store = this.dbManager.getSessionStore();
const prompts = store.getUserPromptsByIds(...);         // Bug if prompts live elsewhere

Please verify that getUserPromptsByIds is actually a method on the session store and not on a separate prompt store.

2. 'unknown-project' fallback may cause cross-project pollution

// store.ts
const resolvedProject = project || 'unknown-project';

If the worker receives observations without a project key (e.g. during race-condition startup), they're bucketed under the shared sentinel 'unknown-project' across all sessions and real projects. A query scoped to project='unknown-project' would then return observations from multiple unrelated projects. Consider either:

  • logging a warning when the fallback fires so it's visible, or
  • using a more unique sentinel (e.g. unknown-project-${memorySessionId.slice(0, 8)}) so stray records don't co-mingle.

Minor Notes

3. Duplicated batch-handler validation logic

The ids coercion + array/integer validation block is identical in handleGetSessionSummariesByIds, handleGetPromptsByIds, and (presumably) handleGetObservationsByIds. A small private helper on BaseRouteHandler would eliminate the copy-paste and make future changes consistent.

private parseIds(raw: any, res: Response): number[] | null {
  // coerce, validate, return null and set 400 on failure
}

4. tsx maps to typescript query — confirm TSX grammar compatibility

tsxtypescript is correct for .tsx files since tree-sitter-typescript covers both. Just worth confirming the (interface_declaration) and (type_alias_declaration) captures resolve correctly against the TSX grammar variant (some versions use a separate tsx parser that is a superset of the typescript one).

5. No automated tests added

The test plan is entirely manual. Given that fixes #1917 and #1919 are pure logic changes (sort order reversal, query routing), they're straightforward to unit test. Would be good to add at least:

  • A test asserting buildTimeline returns items newest-first
  • A test asserting getQueryKey('javascript') returns 'javascript' (not 'typescript') and that the JS query does not include interface_declaration

Positives

  • The cwd ?? process.cwd() fix in session-init.ts is clean and the comment ties it back to the context handler pattern.
  • The JSTS_BASE_QUERY extraction and TS-only extension is a good structural improvement — much clearer than a monolithic jsts query.
  • The newest-first sort comment explaining the 2KB truncation constraint is exactly the kind of non-obvious WHY that should be in code.
  • MCP tool descriptions clearly differentiate ID types (emoji-prefix vs S-prefix vs prompt IDs) — good UX for the AI consumer.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 18, 2026

Greptile Summary

This PR closes four bugs: timeline/context output is now sorted newest-first so truncated 2KB previews surface recent data; session-init.ts uses the same cwd ?? process.cwd() fallback as the context handler, fixing project-key consistency for session lookup; the shared jsts tree-sitter query is split into separate javascript and typescript variants to prevent TS-only node type errors on JS files; and two new MCP tools (get_sessions, get_prompts) with matching batch HTTP routes enable direct ID disambiguation from timeline results.

Confidence Score: 5/5

Safe to merge; all remaining findings are P2 style suggestions that do not block correct behavior.

All four bug fixes are well-scoped and follow existing patterns. The only flagged issues are a missing integer guard on the limit parameter (consistent with the pre-existing handleGetObservationsByIds pattern) and a note about orphaned historical observations — neither affects runtime correctness of the new code.

No files require special attention; DataRoutes.ts has a minor P2 on limit validation shared with the existing batch handler.

Important Files Changed

Filename Overview
src/services/worker/http/routes/DataRoutes.ts Added /api/sessions/batch and /api/prompts/batch POST endpoints; both new handlers omit integer validation on the limit parameter before SQL interpolation.
src/services/sqlite/observations/store.ts Fallback project replaced from cwd-derived key to 'unknown-project' to avoid worker-cwd mismatch; pre-existing observations under wrong key are orphaned.
src/servers/mcp-server.ts Added get_sessions and get_prompts MCP tools mirroring get_observations, with updated documentation and error messages for all three tools.
src/services/smart-file-read/parser.ts Split shared jsts tree-sitter query into separate javascript (base nodes only) and typescript (base + interface/type/enum) variants, preventing TS-only node errors in JS files.
src/services/context/ObservationCompiler.ts Sort direction flipped from ascending to descending so newest context appears first when output is truncated.
src/services/context/sections/TimelineRenderer.ts Day-group sort order flipped to newest-first, consistent with ObservationCompiler change.
src/cli/handlers/session-init.ts Added ?? process.cwd() fallback for cwd so project-key resolution matches the context handler, fixing session lookup consistency.
src/services/context/formatters/AgentFormatter.ts Legend and footer strings updated to mention all three fetch tools (observations, sessions, prompts).
src/services/context/formatters/HumanFormatter.ts Help text updated to list all three fetch tools.

Sequence Diagram

sequenceDiagram
    participant Agent as MCP Client (Agent)
    participant MCP as mcp-server.ts
    participant Worker as Worker HTTP
    participant DB as SessionStore (SQLite)

    Agent->>MCP: search(query)
    MCP->>Worker: POST /api/search
    Worker-->>MCP: results with IDs (obs emoji, S-prefixed, prompt)
    MCP-->>Agent: index results

    Agent->>MCP: timeline(anchor=ID)
    MCP->>Worker: GET /api/timeline
    Worker-->>MCP: newest-first chronological context
    MCP-->>Agent: day-grouped context (newest day first)

    alt Observation IDs
        Agent->>MCP: get_observations([IDs])
        MCP->>Worker: POST /api/observations/batch
        Worker->>DB: getObservationsByIds()
        DB-->>Worker: observations
        Worker-->>MCP: full details
    else Session IDs (S-prefixed) [NEW]
        Agent->>MCP: get_sessions([IDs])
        MCP->>Worker: POST /api/sessions/batch
        Worker->>DB: getSessionSummariesByIds()
        DB-->>Worker: session summaries
        Worker-->>MCP: full details
    else Prompt IDs [NEW]
        Agent->>MCP: get_prompts([IDs])
        MCP->>Worker: POST /api/prompts/batch
        Worker->>DB: getUserPromptsByIds()
        DB-->>Worker: user prompts
        Worker-->>MCP: full details
    end
    MCP-->>Agent: ~500-1000 tokens/result
Loading

Fix All in Claude Code

Reviews (1): Last reviewed commit: "fix(search): newest-first context, sessi..." | Re-trigger Greptile


/**
* Get SDK sessions by SDK session IDs
* POST /api/sdk-sessions/batch
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 limit not validated before SQL interpolation

Both new batch handlers (handleGetSessionSummariesByIds and handleGetPromptsByIds) extract limit from req.body and pass it straight through to the SQL query as LIMIT ${limit}. A non-integer value (e.g. "10; SELECT 1") would be interpolated into the prepared-statement template before this.db.prepare() is called. While bun:sqlite rejects multi-statement strings at prepare-time, it will also throw an unhandled error for any non-numeric value, since the handler has no integer guard on limit.

The existing handleGetObservationsByIds follows the same pattern — consider adding a consistent integer check when limit is truthy:

Suggested change
* POST /api/sdk-sessions/batch
if (limit !== undefined && (!Number.isInteger(Number(limit)) || Number(limit) < 1)) {
this.badRequest(res, 'limit must be a positive integer');
return;
}

Fix in Claude Code


// Guard against empty project string (race condition where project isn't set yet)
const resolvedProject = project || getProjectContext(process.cwd()).primary;
// Guard against empty project string (race condition where project isn't set yet).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Historical observations under old wrong key are orphaned

The new fallback ('unknown-project') correctly prevents future writes from using the worker's process.cwd(), but any observations already stored under the incorrect cwd-derived project key (from before this fix) are still stranded — they won't surface in queries scoped to the user's real project key. Worth documenting a one-time migration path (or at least a note in the changelog) so users who hit #1918 before this fix know how to recover those records.

Fix in Claude Code

@thedotmack
Copy link
Copy Markdown
Owner Author

Closing to start fresh from main — will redo fixes isolated in Docker container.

@thedotmack thedotmack closed this Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant