Skip to content

fix(gallery): stop echoed batch inputs from jumping ahead in the gallery - #9987

Merged
joshistoast merged 8 commits into
mainfrom
fix/workflow-batch-input-routing
Oct 24, 2026
Merged

joshistoast merged 8 commits into
mainfrom
fix/workflow-batch-input-routing

Conversation

@joshistoast

@joshistoast joshistoast commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

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.

  • Queue: the input-passthrough filter now reads the whole submission: compiled graph nodes plus workflow batch data. This applies to both images and videos. Only well-formed batch entries are read, and malformed or legacy snapshots yield nothing. Input names are collected once per submission, so partial and final routes of a large batch don't rescan it.
  • Gallery: a sparse viewport overlays only recents created after the listing's newest item. That cutoff is read from the page holding the newest end of the listing (page 0 descending, the last page ascending) and kept after that page scrolls out of view; until it has loaded, no recents are overlaid. An older recent belongs inside the backend listing; the listing places it, or the post-run gallery refresh does. Sparse items now 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 (in invokeai/frontend/webv2): passed. Covers lint, typecheck, architecture, 358 unit test files / 3,252 tests, browser tests, journeys, and the performance and accessibility gates.
  • New regression coverage:
    • runtime.test.ts: the issue's reproducer. It failed before the fix: batch-input.png was 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.
  • Browser check against the mock backend: I seeded a project's gallery recents with an old Uncategorized image (on a later backend page) and a newer one. The sparse grid's recent row showed only the newer image, followed by backend items in order. Before this change, the old image also sat in that leading row.
  • Not checked end to end: an actual Image Batch → Image Primitive run on a real backend. The mock backend doesn't execute workflows; the runtime test covers that path.

Review

No blocking findings. Known limitations:

  • The sparse cut follows the pages currently loaded. When the user scrolls far enough that page 0 is unloaded, some hidden older recents can reappear in the offscreen leading rows. This only happens for recents never matched to a backend item by key, and it doesn't affect what's visible at the top of the gallery.
  • Outputs are attached to their destination board after they're created. If two runs finish out of order, the older run's image can stay hidden until the post-run gallery refresh. Before this change it appeared right away, but in the wrong position.

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Meaningful regression coverage added / updated where needed; obsolete tests/code removed
  • Persisted-state and API changes include required migrations / compatibility validation
  • Relevant performance/efficiency opportunities considered; material claims have evidence
  • Material review findings resolved and relevant checks rerun
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

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.
@github-actions github-actions Bot added the frontend PRs that change frontend files label Oct 22, 2026
@joshistoast
joshistoast requested a review from JPPhoto October 22, 2026 05:09

@JPPhoto JPPhoto left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.
@joshistoast
joshistoast requested a review from JPPhoto October 22, 2026 20:38

@JPPhoto JPPhoto left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Edit: didn't mean to approve!

@JPPhoto
JPPhoto self-requested a review October 22, 2026 21:08

@JPPhoto JPPhoto left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Findings/issues:

  1. invokeai/frontend/webv2/src/features/gallery/ui/useGalleryData.ts:237-264: In sparse ASC mode, backendItems covers 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, then GalleryImageGrid.tsx:483-489 places 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:

  1. invokeai/frontend/webv2/src/features/queue/core/graphInputMedia.ts:56-57: Any array-shaped batchData is recursively scanned without validating its datum shape. invokeai/frontend/webv2/src/workbench/queue-integration/queueRunRestoration.ts:32-35,140 accepts a kind-tagged snapshot without validating batch data, so a malformed restored snapshot containing an image_name matching a result can make runtime.ts:1102-1104 filter 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.
@joshistoast
joshistoast requested a review from JPPhoto October 22, 2026 21:26

@JPPhoto JPPhoto left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Findings/issues:

  1. 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-817 invalidates 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.
@joshistoast
joshistoast requested a review from JPPhoto October 23, 2026 23:34

@JPPhoto JPPhoto left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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 restored kind: 'generate' submission with extra batchData can filter a real result if a stray image_name matches it. queueRunRestoration.ts:31-35,139-140 preserves 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. A kind === '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.

@joshistoast
joshistoast enabled auto-merge October 24, 2026 06:03
@joshistoast
joshistoast merged commit 0ddc9df into main Oct 24, 2026
21 checks passed
@joshistoast
joshistoast deleted the fix/workflow-batch-input-routing branch October 24, 2026 06:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frontend PRs that change frontend files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug]: Sparse gallery can show old requeued images ahead of newer items

2 participants