Attach tray: re-attaching the same file stops stacking duplicate chips - #40
Conversation
Dropping or pasting a file that lives OUTSIDE the workspace stages a copy, and the tray's dedupe only matched references (WasCopied=false). So attaching the same file twice produced foo.png and foo-2.png: two chips, identical content, two mentions, both counting against the 20-item cap. Match on the ORIGINAL path plus its last-write time, checked before any copying (FindBySource), so a repeat re-mentions the chip that is already there - the same thing clicking the chip does. The timestamp is part of the key on purpose: a staged copy froze the old bytes, so a file edited since must still come in as a new attachment. It sits ahead of the BMP branch too, so re-dropping a .bmp finds the PNG we transcoded the first time. Pasted screenshots and composer text still never dedupe - they have no source file, so each one is genuinely new content. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewing the capture path for this PR (does a screenshot's empty SourcePath let FindBySource match a real file? no - it cannot) turned up something I left behind in firish#36: StageCapturePng still had the old inline trim, `while (Items.Count > MaxItems) Items.RemoveAt(0)`, so a capture arriving at a full tray could evict a still-pending mention - exactly the invariant AddItem exists to protect. It now uses AddItem like every other add, and the empty SourcePath is documented as deliberate rather than incidental. Behaviour verified against the built assemblies in a temp workspace: an out-of-workspace file dropped twice = one chip; edited and dropped again = a second chip (the escape hatch); an in-workspace file twice = one chip, still WasCopied=false; the same image pasted twice = two chips, since contentless pastes have no source to match on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Merging - this is a genuine data bug and the diagnosis is exactly right, including the part where my comment on that path was the misleading bit. "Copies are always distinct files" is true of a pasted screenshot and false of a file handed to us twice, and I wrote it without noticing the difference. Two things I want to credit specifically. The timestamp in the key is what makes this correct rather than merely convenient: a staged copy froze the old bytes, so a file edited since staging has to come in fresh, and that edit is usually the whole reason someone attaches the same path again. And placing the check ahead of the BMP branch means a re-dropped Verified against the built assemblies in a throwaway workspace rather than by reading: outside file dropped twice = one chip; edited then dropped again = a second chip; in-workspace file twice = one chip, still One maintainer tweak on the branch, and it came out of reviewing your change: checking whether a capture's empty Thanks Dave - and thanks for correcting the CLAUDE.md sentence rather than leaving it wrong. |
The bug
Drop or paste a file that lives outside the workspace, then do it again. You get two chips:
Same file, same bytes, two copies in
.claude\attachments\, twoat_mentionedsends, two of the 20 tray slots gone. Do it a few times while iterating on a screenshot outside the repo and the tray fills with clones of one file.The tray already dedupes — but only references (
WasCopied=false). Out-of-workspace files come in as staged copies, and the comment on that path said copies are always distinct files so they never match. True for a pasted screenshot; not true for a file the user handed us twice.The fix
Match on the original path + its last-write time (
FindBySource), checked before any copying happens. A repeat re-mentions the chip that already exists — exactly what clicking the chip does.The timestamp is deliberately part of the key: a staged copy froze the old bytes, so a file edited since it was staged must still come in as a new attachment. That is usually the reason someone attaches the same path a second time.
Placed ahead of the BMP branch as well, so re-dropping a
.bmpfinds the PNG transcoded the first time instead of transcoding it again.Unchanged on purpose:
Program.cs#L10-20and#L30-40are different things.Verification
Release build clean. Manually: drop a desktop file on the panel twice → one chip, two
@-mentionedlines in the feed. Save the file, drop again → a second chip appears, which is the intended escape hatch.CLAUDE.md's attachment paragraph is updated — the old sentence ("copies never dedupe") is no longer accurate.🤖 Generated with Claude Code