refactor(frontend): drop per-project fan-out from all batch fetchers#4637
refactor(frontend): drop per-project fan-out from all batch fetchers#4637mmabrouk wants to merge 1 commit into
Conversation
One project is in scope at a time in the web app, so grouping batched requests by project and issuing one query per project handles a state that cannot exist. Every batchFn now takes the single project in scope, throws if coalesced requests disagree, and resolves all ids with one call. Documents the invariant in web/AGENTS.md.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Context
While reviewing #4634, @junaway flagged the artifact fetcher's shape: it grouped requests into a
Mapkeyed byproject_idand ran one query per project inside aPromise.all. That structure handles a state that cannot exist. The web app holds exactly oneproject_idin scope at any time, and the/queryendpoints accept multiple ids, so a batch of coalesced requests always resolves with a single call.The interesting part is where that shape came from. It was not invented for #4634; it was copied from the fetchers sitting right next to it. A grep for the pattern found it in 13 batch fetchers across 9 files: workflow revisions, latest revisions, traces, spans, testsets, testset revisions (twice), testcases (twice), evaluation runs, annotations, and environments. Every one of them defends against a multi-project batch that no caller can produce. Each copy also drags in real complexity: nested grouping maps, per-group error handling, and in one case a per-project
queryClientset that exists only to serve the impossible case.This is how a wrong pattern propagates. "Match the surrounding code" is the default instinct for any contributor (or agent) writing a new fetcher, and the surrounding code taught the wrong thing. #4634 fixed its own fetcher after review; this PR removes the remaining 12 copies and writes the invariant down so the next fetcher starts from the right shape.
Changes
Every
batchFnnow follows one shape:project_idfrom the first request. If any other request disagrees, throw. A multi-project batch means a bug upstream, and per @junaway's review it must fail rather than be silently accommodated.Before (the shape every fetcher had):
After:
Behavior that was per-fetcher stays: cache short-circuits, fallback-to-individual-fetch paths, and cache priming are preserved, just no longer duplicated per project group. Grouping by other dimensions survives where it is real: the testcase entity fetcher still groups its cache lookup by
revisionId, because the paginated cache is genuinely revision-scoped. The rule is only that the project dimension is singular.web/AGENTS.mdnow states the invariant under Data fetching ("Single project scope"), so the convention no longer lives only in the code it was just removed from.Tests
tsc --noEmitclean onagenta-entities; zero errors in the two touchedweb/ossfiles (the workspace has unrelated pre-existing errors elsewhere).agenta-entitiesunit tests pass.What to QA
This is a refactor with no intended behavior change, so the check is regression-only: the touched fetchers feed most entity displays. Browse the evaluators table, a testset and its revisions, an evaluation run detail, the annotation queue, a trace drawer, and the deployments page. Everything should load exactly as before, with no new errors in the console.