fix(sdk): store and report one spelling of an upload's filename - #30
Merged
Conversation
Unicode lets the same name be two different byte strings. macOS hands over the
decomposed form — `á` as `a` + U+0301 — and that is what the plugin wrote to
disk and put in the `<attachment filename="…">` tag. A model asked to use that
name writes the composed form back, because that is what it produces. The two
do not compare equal, so every path the agent builds from the name it was given
misses the file that is actually there:
cp: cannot stat '…/Veronika Paulova'$'\303\241''_ucitelka.jpg': No such file
Observed on a production session with Czech filenames: 21 of its 95 tool
failures, second only to a path-resolution bug. Nothing the agent can do about
it — it never sees the bytes, and retrying produces the same string. It burned
turns on `ls`, `find` and a second `cp` before giving up on the attachment.
So the plugin now composes on the way in, once, in `prepareUpload`. The stored
name is carried on `PreparedUpload` and both upload handlers build their
`UploadDescriptor` from it rather than from their own input, which is what makes
the metadata, the event and the directory entry agree by construction instead of
by coincidence.
Only the spelling changes: NFC cannot introduce a path separator, and validation
runs on the normalized name.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MjPDwksb3bAUC4fCVi3QXS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Unicode lets the same filename be two different byte strings. macOS hands over the decomposed form —
áasa+ U+0301 — and that is what the uploads plugin wrote to disk and put in the<attachment filename="…">tag it shows the agent. A model asked to use that name writes the composed form back, because that is what models produce. The two do not compare equal, so every path the agent builds from the name it was given misses the file that is actually there:Observed on a production session with Czech filenames: 21 of its 95 tool failures, second only to a path-resolution bug. There is nothing the agent can do about it — it never sees the bytes, and retrying produces the same string. It spent turns on
ls,findand a secondcpbefore giving up on the attachment entirely.The fix
Compose on the way in, once, in
prepareUpload. The stored name is carried onPreparedUpload, and both upload handlers now build theirUploadDescriptorfrom that rather than from their own copy of the input — so the metadata, theattachment_uploadedevent and the directory entry agree by construction instead of by coincidence.Only the spelling changes. NFC cannot introduce a path separator, and
validateUploadInputruns on the normalized name, so the basename check still guards what is written.Verification
bun run ts:buildclean.bun test packages/sdk/src/plugins/uploads/61 pass / 0 fail.The new test fails without the fix (verified by neutering
toStoredFilename), and the widerpackages/sdksuite has an identical failure set on this branch and onmain— 26 either way, all in services/skills/mailbox/agent-shutdown, none touched here.🤖 Generated with Claude Code
https://claude.ai/code/session_01MjPDwksb3bAUC4fCVi3QXS