Skip to content

Duplicate File.name collapses the stereo-pairing dict, defeating find_pairs' two-lefts guard #11

Description

@bmxcode

Found while fixing the ISO 9660 short-name collision in #10, and deliberately left out of it — the fix touches find_pairs' contract, which is a different deliverable.

The defect

extract_volume collects parsed samples in a dict keyed by the filesystem's name:

https://github.com/bmxcode/samplerdisc/blob/main/src/samplerdisc/extract.py#L194

parsed[entry.name] = sample
...
pairs = find_pairs(list(parsed))

Where a filesystem yields two distinct files under one name, the second silently replaces the first in that dict. No audio is lost — both WAVs are already on disk by then, unique_path having given the second one a suffix — but the pairing runs against a name list that no longer matches the disc.

Why that is worse than a missed pair

find_pairs is deliberately conservative, and says so:

A base with two lefts and no right, or three files, is not a pair. Being conservative costs the user a manual join; being loose silently welds two unrelated sounds together.

The dict collapses the duplicates before find_pairs can apply that rule, so the guard cannot fire:

from samplerdisc.stereo import find_pairs

entries = ["KICK -L", "KICK -L", "KICK -R"]   # two different files, one name

find_pairs(entries)
# []  -- refuses, correctly: two lefts

parsed = {}
for name in entries:
    parsed[name] = object()                   # extract.py:194
find_pairs(list(parsed))
# [Pair(base='KICK', left='KICK -L', right='KICK -R')]  -- pairs anyway

The result is a stereo WAV welding whichever KICK -L happened to be walked last to KICK -R — exactly the silent, wrong join that ADR-0007 keeps the mono originals as insurance against. It reports as a normal Joined, with nothing saying a choice was made.

How likely is it

Not reachable on any disc in the collection today, which is why this is an issue rather than part of #10:

  • ISO 9660 discs now read Joliet, where names are unique (ADR-0019). Vintage Pro's 61-way primary-tree collision is no longer the path taken — and its .EBL names carry no -L/-R marker anyway.
  • A non-Joliet disc with colliding short names and a side marker would hit it. Nothing rules that out; the AKAI, E-mu and Roland backends make no uniqueness guarantee about File.name either.

So: latent, same as the collision in #10 was before .EBL support was on the horizon.

Shape of a fix

The key has to be something unique per entry while find_pairs keeps operating on names — it is a name heuristic and should stay one. Roughly: key parsed by an identity the filesystem guarantees (the entry itself, or its start block), and give find_pairs a way to say "this base had two candidate lefts" so the ambiguity is reported rather than resolved. A Skipped with a reason would fit how the rest of extract_volume handles what it will not guess.

Not obviously a one-liner — Pair carries names, and _join_pairs looks samples back up by name — hence a separate change.

Worth adding either way

There is no test anywhere asserting what extraction does with two entries sharing a name. #10 added one for the output paths (test_colliding_names_extract_to_one_file_each); the pairing side has none, and the snippet above is most of one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions