Skip to content

id(web): multi-image paste/drop inserts images in upload-completion order, not clipboard order #1323

Closed

Description

@dezren39

Bug

Pasting or dropping multiple images at once into the id web editor inserts them in upload-completion order, not clipboard order. Uploads race: whichever /api/upload request finishes first does not determine position — in the verified probe below, the image whose upload finished first ended up second in the document. The resulting order is effectively nondeterministic and depends on file sizes and network timing.

Evidence

pkgs/id/web/src/image-upload.ts:

  • handlePaste (~L185-202) and handleDrop (~L204-228) start every file's upload from the same insert position (view.state.selection.from / one posAtCoords result) via independent handleImageUpload(view, file, insertPos) calls — no sequencing or ordering token.
  • handleImageUpload (~L232-245) adds a placeholder widget at that shared position; on completion it inserts the image node at its placeholder's mapped position (found[0].from). All placeholders sit at the same document position, so completion order — not paste order — decides the final sequence.

Verified this run on main 1bf2afb2 with a targeted vitest probe (real EditorView + plugin, mocked fetch; probe since removed):

  • Pasted [first.png, second.png]; resolved second.png's upload first, then first.png's.
  • Resulting document image order: [second.png, first.png] — reversed relative to the clipboard.

With equal timing the order varies run to run; larger files (slower uploads) systematically drift later/earlier than the user pasted them.

Why it matters

Multi-image paste is the normal way users add screenshots and photo sets to a document. Silently scrambling their order corrupts the document's meaning (before/after shots, step-by-step screenshots, comic/panel sequences) and the user may not notice until the document is shared — in a collaborative editor, possibly after collaborators have seen the scrambled version.

Acceptance criteria

  • Images pasted or dropped together appear in the document in clipboard/file-list order, regardless of individual upload completion order (e.g. sequence the insertions, or give each placeholder a stable ordered slot that later completions insert after).
  • A failed upload in the middle of a batch does not reorder or drop the remaining images; its placeholder is removed and the survivors keep their relative order.
  • Regression test in pkgs/id/web/src/image-upload.test.ts: real-view probe like the one above — paste two images, resolve the uploads out of order, assert document order matches paste order; same for the failure-in-the-middle case.
  • Single-image paste/drop behavior unchanged; existing web tests pass (cd pkgs/id/web && bun run test / vitest).

Related but distinct: #1321 (an all-oversized paste/drop is swallowed entirely) touches the same handlers.

Activity

  1. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 27, 2026
  3. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · state: filed

    • Agent: new-issue-creator job
    • Session / ID: new-issue-creator run, 2026-10-27T06:56Z
    • Found via: filed this run
    • Task: Filed after verifying on main 1bf2afb with a targeted vitest probe (real EditorView + image-upload plugin, mocked fetch; probe removed after): pasted [first.png, second.png], resolved second.png's upload first — document image order came out [second.png, first.png]. All uploads share one insert position and insert at their placeholder on completion (image-upload.ts handlePaste/handleDrop/handleImageUpload), so order follows completion timing, not the clipboard.
    • Expectation: effort s — triage picks the ordering mechanism (sequenced insertion vs ordered placeholder slots), then a small fix with an out-of-order-completion regression test; a mid-batch failure must not reorder survivors.
    • Links: body: hidden_files/issue-code-image-upload-paste-order-body.md; queue packet packet-1323.json (repo-health-code-pilot); sibling id(web): pasting or dropping only oversized images silently swallows the paste — event claimed, nothing inserted, no feedback #1321 (same handlers, all-oversized swallow)
  4. added
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 27, 2026
  5. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    Intake review

    Fleet monitor intake pass (protocol §5), 2026-10-27. Verified still live: no merged PR implements or resolves this issue as of this run, and no duplicate open issue covers it.

    Related: Related: sibling #1321 (all-oversized paste/drop swallowed) touches the same handlers and already has task 1311 queued; this issue's own triage task 1312 is queued. Acceptance criteria were already in the body under the heading; labels were already normalized by the filer — this pass only adds the intake review + meta/enriched.

    Notes / risks / suggested approach: Risk: ordering fix must not break the single-image path or placeholder cleanup on failure. Suggested approach per the filer: sequenced insertion or stable ordered placeholder slots, with the out-of-order-completion regression test.

    Labels normalized by this pass: meta/enriched.

  6. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  7. 5 remaining items

  8. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Oct 31, 2026
  9. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · resumed, re-parked on CI

  10. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 31, 2026
  11. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — Agent: repo-worker-code (lane B); state: claimed. Task 1312 resumed for PR #3194 merge: Codex review on head 6699f09 completed with no findings; targeted suite verified on the laptop at the exact PR head (bunx vitest run src/image-upload.test.ts — 45/45 pass in a clean worktree). Note: .github/workflows/id-check.yml has no pull_request trigger (push-to-main + dispatch only), so no PR CI run exists for this head; the push-to-main run after merge is the CI gate. Merging under the standing directive.

  12. added a commit that references this issue on Oct 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions