Skip to content

Conversation

@mkrokosz
Copy link

@mkrokosz mkrokosz commented Feb 3, 2026

Summary

  • Batch version tag resolution in list endpoints to reduce N sequential ctx.runQuery() calls to 1
  • Applies to both skills and souls list/get endpoints

Problem

The resolveTags function was called per-item in list responses, with each call making sequential ctx.runQuery() calls for each tag. For a list of 20 skills with 5 tags each, this resulted in 100 separate action→query round-trips.

Solution

  • Add getVersionsByIds batch query to skills.ts and souls.ts
  • Replace per-item tag resolution with batch resolution that:
    1. Collects all version IDs from all items
    2. Fetches all versions in a single query
    3. Maps results back to each item

Performance Impact

Scenario Before After
List 20 skills, 5 tags each 100 action→query round-trips 1 round-trip
Single skill detail, 5 tags 5 round-trips 1 round-trip

Changes

  • convex/skills.ts: Add getVersionsByIds query
  • convex/souls.ts: Add getVersionsByIds query
  • convex/httpApiV1.ts: Replace resolveTags/resolveSoulTags with batch versions
  • convex/httpApiV1.handlers.test.ts: Update tests to verify batch behavior

API Impact

None - response format is unchanged.

🤖 Generated with Claude Code

Greptile Overview

Greptile Summary

This PR batches version-tag resolution for skills and souls in the v1 HTTP API handlers. Instead of resolving each tag via repeated ctx.runQuery() calls per item, handlers now collect all version IDs from the response, fetch the corresponding versions via a single getVersionsByIds query, and map the resolved version strings back onto each item.

The approach fits the existing Convex pattern of keeping list endpoints cacheable/efficient while doing additional enrichment in the HTTP layer.

One correctness issue to address: the new batch resolvers assume the batch query always returns an array, and can throw when there are no tags / the query returns null.

Confidence Score: 2/5

  • This PR is not safe to merge as-is due to a crash in the new batch tag resolution path when the batch query returns null/undefined.
  • Score is reduced because the new resolveTagsBatch/resolveSoulTagsBatch assume the batch query returns an iterable array and will throw if it returns null (observed in tests when listing skills with no tags / when runQuery mock returns null). The remaining changes are straightforward and localized, and the performance intent is sound.
  • convex/httpApiV1.ts (batch tag resolver helpers); also review the new batch queries in convex/skills.ts and convex/souls.ts for expected input sizes/limits.

(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!

Context used:

  • Context from dashboard - AGENTS.md (source)

- Add getVersionsByIds batch query to skills.ts and souls.ts
- Replace per-item tag resolution with batch resolution in httpApiV1.ts
- Reduces N action→query round-trips to 1 for list endpoints

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel
Copy link
Contributor

vercel bot commented Feb 3, 2026

@mkrokosz is attempting to deploy a commit to the Amantus Machina Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +1128 to +1134
export const getVersionsByIds = query({
args: { versionIds: v.array(v.id('skillVersions')) },
handler: async (ctx, args) => {
const versions = await Promise.all(args.versionIds.map((id) => ctx.db.get(id)))
return versions.filter((v): v is NonNullable<typeof v> => v !== null)
},
})
Copy link

Choose a reason for hiding this comment

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

[P2] getVersionsByIds uses Promise.all(versionIds.map(ctx.db.get)), which will issue one db.get per ID anyway. This reduces action→query round-trips (good), but inside the query it can still be a large fan-out (up to all tags across the page). If versionIds can be large, consider adding a conservative cap/deduplication at the query boundary, or using an index-based fetch strategy if available.

Also appears in convex/souls.ts:148-154.

Prompt To Fix With AI
This is a comment left during a code review.
Path: convex/skills.ts
Line: 1128:1134

Comment:
[P2] `getVersionsByIds` uses `Promise.all(versionIds.map(ctx.db.get))`, which will issue one `db.get` per ID anyway. This reduces action→query round-trips (good), but inside the query it can still be a large fan-out (up to all tags across the page). If `versionIds` can be large, consider adding a conservative cap/deduplication at the query boundary, or using an index-based fetch strategy if available.

Also appears in `convex/souls.ts:148-154`.

How can I resolve this? If you propose a fix, please make it concise.

- Short-circuit when no version IDs to resolve
- Add null coalescing for runQuery response
- Fixes potential crash when tags are empty or query returns null

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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