Synced customizations with the same destination are resolved nondeterministically
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
While working on #327754, I noticed an existing issue in `SyncedCustomizationBundler` when multiple customization files flatten to the same destination in the synthetic plugin.
For example, these two user instruction files:
```text
~/.copilot/instructions/shared.instructions.md
~/.claude/rules/shared.instructions.md
|
v
rules/shared.instructions.md
```
Both source files map to the same `rules/shared.instructions.md` destination.
## Current behavior
The bundler reads all source files concurrently and appends each completed read to `entries`. When two files map to the same destination:
- Both files are read and both are added to `entries`.
- The destination is written more than once.
- The final content depends on which asynchronous read completes last, so there is no deterministic winner.
- Provenance is recorded separately before the reads complete and can point to a different source than the content that ultimately wins.
- Both files contribute to the content nonce even though only one file remains at the destination.
- A failure reading the file that would otherwise lose the collision still fails the entire bundle.
The same problem can occur for skills when two sources contain the same skill directory name:
```text
~/.copilot/skills/shared/SKILL.md
~/.claude/skills/shared/SKILL.md
|
v
skills/shared/SKILL.md
```
## Expected behavior
Destination collisions should have an explicit and deterministic precedence rule. Content, provenance, and nonce calculation should all use the same winning source, and losing duplicates should not need to be read.
This is separate from #327754. Restoring user customization syncing fixes that issue for uniquely named files; collision handling can be addressed independently in a follow-up change.
Contributor guide
Assessment
This issue has not been assessed yet.