[#8] Duplicate-name conflict on paste/import — verify first #8

Closed
opened 2026-07-02 00:50:45 -04:00 by the_og · 1 comment
Owner

Status: verify before coding

Do not implement until the current behavior is confirmed. Read paste_json / dropEvent in bcc.py and apply_servers in bcc_core.py, then post a comment on this issue describing what actually happens today when a pasted/dropped server name collides with an existing one. If it silently overwrites, then code the fix. If it already prompts, close this issue.

Problem (if behavior is silent overwrite)

parse_pasted_json_verbose / apply_servers may silently overwrite an existing server when a pasted or drag-and-dropped server name matches one already present. Silent overwrite matches the "config got clobbered" complaint pattern.

Proposed fix (if needed)

Add an explicit prompt (overwrite / rename / skip) when a pasted or dropped server name collides with an existing entry.

Acceptance criteria (if needed)

  • Pasting a server with a name that already exists prompts the user instead of silently overwriting.
  • Renaming and skipping both work correctly.

Relevant code

  • bcc_core.py::apply_servers (line 186)
  • bcc_core.py::parse_pasted_json_verbose (line 531)
  • bcc.py paste/drop handlers
## Status: verify before coding **Do not implement until the current behavior is confirmed.** Read `paste_json` / `dropEvent` in `bcc.py` and `apply_servers` in `bcc_core.py`, then post a comment on this issue describing what actually happens today when a pasted/dropped server name collides with an existing one. If it silently overwrites, then code the fix. If it already prompts, close this issue. ## Problem (if behavior is silent overwrite) `parse_pasted_json_verbose` / `apply_servers` may silently overwrite an existing server when a pasted or drag-and-dropped server name matches one already present. Silent overwrite matches the "config got clobbered" complaint pattern. ## Proposed fix (if needed) Add an explicit prompt (overwrite / rename / skip) when a pasted or dropped server name collides with an existing entry. ## Acceptance criteria (if needed) - Pasting a server with a name that already exists prompts the user instead of silently overwriting. - Renaming and skipping both work correctly. ## Relevant code - `bcc_core.py::apply_servers` (line 186) - `bcc_core.py::parse_pasted_json_verbose` (line 531) - `bcc.py` paste/drop handlers
the_og added the P1 label 2026-07-02 00:50:45 -04:00
Author
Owner

Investigated current behavior before touching anything, per the issue instructions.

Paste path (PasteDialogMainWindow.paste_json, bcc.py ~1623-1653, using core.parse_pasted_json_verbose in bcc_core.py ~700): on a name collision it already shows a QMessageBox.question — "'{name}' already exists. Replace it? Yes = replace · No = keep both (renamed)". Choosing "keep both" appends -2, -3, ... until a free name is found. This path was already safe.

Drag-and-drop path (MainWindow.dropEvent, bcc.py ~1826-1848): this did not go through the same prompt. It silently renamed any colliding server to a fixed "{name}-imported" suffix, with no check that the suffixed name was itself free:

for name, data in servers.items():
    names = {s.name for s in self.servers}
    if name in names:
        name = f"{name}-imported"
    self.servers.append(core.ServerEntry(name, data, True))

Two concrete problems:

  1. No prompt at all on drop — inconsistent with paste, and the user gets no say in replace-vs-rename.
  2. If "{name}-imported" was also already taken (e.g. dropping the same file twice, or a server that already ends in -imported), the code did nothing further — two ServerEntry objects with the identical .name end up in self.servers. That isn't visible immediately, but apply_servers() (bcc_core.py ~192-198) builds the on-disk mcpServers dict via {s.name: s.data for s in servers if s.enabled} — a plain dict comprehension, last-one-wins, no warning. So on Save, one of the two same-named entries is silently dropped, and its config is lost.

So: paste already handled collisions safely; drag-and-drop did not, and had a latent silent-data-loss bug on repeated/edge-case collisions. This is a real gap, not just theoretical, so I'm implementing a fix rather than closing the issue.

Fix: extracted the collision-resolution used by paste (-2, -3, ... loop) into a pure, tested function core.resolve_name_collision(name, existing) -> str in bcc_core.py, and factored both paste_json and dropEvent to go through one shared MainWindow._import_server(name, data) helper that always prompts (replace / keep-both-renamed) on collision and always renames via the guaranteed-unique resolver. Drag-and-drop now behaves identically to paste — no more silent overwrite/collapse. Added unit tests for resolve_name_collision in tests/test_core.py (no-conflict passthrough, single collision, multiple taken suffixes, empty existing set, and a repeated-call scenario simulating a double-drop that previously could collide).

PR incoming.

Investigated current behavior before touching anything, per the issue instructions. **Paste path** (`PasteDialog` → `MainWindow.paste_json`, bcc.py ~1623-1653, using `core.parse_pasted_json_verbose` in bcc_core.py ~700): on a name collision it already shows a `QMessageBox.question` — "'{name}' already exists. Replace it? Yes = replace · No = keep both (renamed)". Choosing "keep both" appends `-2`, `-3`, ... until a free name is found. This path was already safe. **Drag-and-drop path** (`MainWindow.dropEvent`, bcc.py ~1826-1848): this did **not** go through the same prompt. It silently renamed any colliding server to a fixed `"{name}-imported"` suffix, with **no check that the suffixed name was itself free**: ```python for name, data in servers.items(): names = {s.name for s in self.servers} if name in names: name = f"{name}-imported" self.servers.append(core.ServerEntry(name, data, True)) ``` Two concrete problems: 1. No prompt at all on drop — inconsistent with paste, and the user gets no say in replace-vs-rename. 2. If `"{name}-imported"` was *also* already taken (e.g. dropping the same file twice, or a server that already ends in `-imported`), the code did nothing further — two `ServerEntry` objects with the identical `.name` end up in `self.servers`. That isn't visible immediately, but `apply_servers()` (bcc_core.py ~192-198) builds the on-disk `mcpServers` dict via `{s.name: s.data for s in servers if s.enabled}` — a plain dict comprehension, last-one-wins, no warning. So on Save, one of the two same-named entries is **silently dropped**, and its config is lost. So: paste already handled collisions safely; drag-and-drop did not, and had a latent silent-data-loss bug on repeated/edge-case collisions. This is a real gap, not just theoretical, so I'm implementing a fix rather than closing the issue. **Fix**: extracted the collision-resolution used by paste (`-2`, `-3`, ... loop) into a pure, tested function `core.resolve_name_collision(name, existing) -> str` in bcc_core.py, and factored both `paste_json` and `dropEvent` to go through one shared `MainWindow._import_server(name, data)` helper that always prompts (replace / keep-both-renamed) on collision and always renames via the guaranteed-unique resolver. Drag-and-drop now behaves identically to paste — no more silent overwrite/collapse. Added unit tests for `resolve_name_collision` in tests/test_core.py (no-conflict passthrough, single collision, multiple taken suffixes, empty existing set, and a repeated-call scenario simulating a double-drop that previously could collide). PR incoming.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: the_og/better-claude-config#8