Repository navigation
fix(gallery): stop echoed batch inputs from jumping ahead in the gallery - #9987
Conversation
Image Batch values live in the submission's batch data, not the compiled graph, so the passthrough filter now scans both before routing images and videos.
Sparse viewports overlay only recents newer than the newest loaded backend item, and sparse items merge the same overlay the rows render.
JPPhoto
left a comment
There was a problem hiding this comment.
Finding/issue:
Batch result routing repeats a large input scan (invokeai/frontend/webv2/src/features/queue/core/graphInputMedia.ts:16). Each completed item scans the same batch data twice through invokeai/frontend/webv2/src/features/queue/runtime.ts:1197 and :1200. The supported limit is 10,000 items; a batch with 10,000 image inputs can cause roughly 200 million input-value visits across its result routes. This runs on the browser's UI thread. What this is: input names are collected again for every partial result. Problem: large supported batches can delay results and board updates. Fix: collect names once per submission and reuse them. If skipped: large batches may make the UI feel stalled. Effect: delayed output visibility. Likelihood: only large batches, up to the supported limit. Recovery: routing eventually finishes; repeating the batch repeats the cost. Test: benchmark a 10,000-image batch and verify collection happens once per submission.
A solution:
Cache SubmissionInputMediaNames once per immutable backendSubmission in createQueueRuntime, then reuse it for partial and final image/video routing. A runtime-local WeakMap (which releases entries when submissions are no longer referenced) avoids changing persisted data or keeping a global cache. Keep the collector itself pure.
Add a focused test that routes multiple results for one submission, confirms inputs stay filtered, and confirms collection happens once.
I didn't implement or test this change. The main risk is that caching assumes backendSubmission is not mutated, matching its existing immutable contract.
Result routing caches each submission's input media names in a runtime-local WeakMap, so partial and final image/video routes no longer rescan every batch item.
JPPhoto
left a comment
There was a problem hiding this comment.
Findings/issues:
invokeai/frontend/webv2/src/features/gallery/ui/useGalleryData.ts:237-264: In sparse ASC mode,backendItemscovers only subscribed pages; page 0 contains the oldest items. A recent newer than that page but older than an unloaded tail item passes the cutoff, thenGalleryImageGrid.tsx:483-489places it after all backend rows. What this is: the cutoff does not know the listing's newest item. Problem: older recents can still appear after newer items, sometimes duplicating a persisted item until its page loads. Fix: establish the tail timestamp before showing ASC recents. If skipped: the ordering issue remains for ASC users. Effect: misordered or duplicate gallery items. Likelihood: normal while later pages are unloaded. Recovery: loading the item's page removes a persisted duplicate. Test: add a sparse ASC case with only the first page loaded and a recent older than an unseen tail item; the current ASC unit test includes the newest backend item and misses this case.
Corner/impossible cases worth noting, possibly fixing later:
invokeai/frontend/webv2/src/features/queue/core/graphInputMedia.ts:56-57: Any array-shapedbatchDatais recursively scanned without validating its datum shape.invokeai/frontend/webv2/src/workbench/queue-integration/queueRunRestoration.ts:32-35,140accepts a kind-tagged snapshot without validating batch data, so a malformed restored snapshot containing animage_namematching a result can makeruntime.ts:1102-1104filter that result and skip board attachment. Effect: the result may be missing from its destination board. Likelihood: rare; requires malformed persisted data and a matching name. Recovery: manual search and board assignment. Test: cover malformed media-bearing batch data in a restored active run.
The recent overlay cut now comes from the page holding the listing's newest end (page zero in DESC, the last page in ASC) and is kept after that page scrolls out of view. Recents wait until that page loads, so ASC and deep DESC scrolls no longer show older recents.
The input filter now reads image items only from batch datums that match the persisted workflow datum shape, so a malformed restored snapshot cannot hide a real result.
There was a problem hiding this comment.
Findings/issues:
invokeai/frontend/webv2/src/features/gallery/ui/useGalleryData.ts:748-763: The retained cutoff survives Gallery invalidation.invokeai/frontend/webv2/src/features/gallery/data/queryCache.ts:798-817invalidates inactive pages without refetching them. If the DESC head or ASC tail page was evicted, an upload while scrolled away can add a newer listing item while an older local recent still passes the stale cutoff and appears ahead of it. Effect: gallery items can be temporarily misordered. Likelihood: a supported mutation after scrolling away. Recovery: revisit the newest-end page to refresh its cutoff. Fix: clear or suspend the cutoff on invalidation. Test: cover eviction, mutation, and refresh in both sort directions.
Suggestions:
- Consider a 10,000-image timing check for the scan optimization. The runtime test proves one scan with one input, but does not measure UI-thread cost at the supported limit.
Preserve backend-read freshness across invalidation and local cache patches. Cover retry recovery and 10,000-input batch routing.
JPPhoto
left a comment
There was a problem hiding this comment.
This is good to merge. There is one corner/impossible case worth mentioning plus a suggestion (below):
invokeai/frontend/webv2/src/features/queue/core/graphInputMedia.ts:52-70: A malformed restoredkind: 'generate'submission with extrabatchDatacan filter a real result if a strayimage_namematches it.queueRunRestoration.ts:31-35,139-140preserves unknown fields. Valid generation does not create this shape; it requires malformed journal data and a name match. Effect: the result may miss its destination board. Test: restore such an entry and verify the result still routes. Akind === 'workflow'guard would close this edge.
Suggestions:
- Update the PR description's known limitation: it still says older recents can reappear after the newest page leaves view, which this head now prevents by suspending the overlay after eviction.
Summary
Workflows that feed an Image Batch into an Image Primitive echo the source image back in their results. The result filter that drops echoed input media only scanned the compiled graph's nodes. Batch values are stored separately, in the submission's batch data, so the echoed source was routed as a new result and added to gallery recents. In the sparse gallery, recents render as their own leading rows (descending) or trailing rows (ascending), so the old image jumped ahead of newer backend items.
itemsnow merge the same overlay the rows render, so selection and navigation agree with the grid. Dense mode still interleaves recents by timestamp, as before.Related Issues / Discussions
Closes #9953
QA Instructions
pnpm check:release(ininvokeai/frontend/webv2): passed. Covers lint, typecheck, architecture, 358 unit test files / 3,252 tests, browser tests, journeys, and the performance and accessibility gates.runtime.test.ts: the issue's reproducer. It failed before the fix:batch-input.pngwas routed and attached to the board.graphInputMedia.test.ts: batch-data and malformed batch-data cases.useGalleryData.test.ts: covers the sparse cut in both directions, the same-instant tie, no loaded items, and dense mode unchanged.useGalleryData.browser.test.tsx: sparse rows and items agree.Review
No blocking findings. Known limitations:
Checklist
What's Newcopy (if doing a release after this PR)Need help on this PR? Tag
@codesmith-botwith what you need.