bartulem/usv-playpen: v0.11.2
Authors/Creators
- 1. Princeton Neuroscience Institute
- 2. Princeton University
Description
v0.11.2
Metadata-integrity fix. In the recording GUI, pressing "Add Subject" silently erased an animal's saved interventions from subject_presets.json. The loss surfaced only in the next session, when the animal was recalled and its intervention "failed to load".
⚠️ Who is affected
Anyone using the Record → subject metadata page who stores interventions (optogenetics, chemogenetics, electrophysiology, lesion) against a remembered animal.
Two distinct losses, depending on how the animal was entered:
| flow | session _metadata.yaml | remembered animal (subject_presets.json) |
|---|---|---|
| picked from the autocomplete dropdown | intact | intact |
| picked from the dropdown, then any field edited, then "Add Subject" | intact | interventions erased |
| subject id typed by hand, then "Add Subject" | interventions missing | interventions erased |
So a recording made by typing the animal's id has a _metadata.yaml without its interventions. That file cannot be repaired automatically — if you have affected sessions, the intervention fields must be re-entered by hand. subject_presets.json itself heals as soon as you re-add the intervention through its dialog.
Root cause
_add_subject assembles its dict from the subject form widgets. There is no widget for interventions, so the key is simply absent from that dict. It was then handed to _update_subject_in_repository, which stored it as the complete animal:
self.subject_repository[existing_subject_index] = repository_entry # wholesale replace
Every key the form does not represent — interventions — was destroyed. The session record survived only because _add_subject merges into it with .update(). The repository got replace, the session got merge; that asymmetry was the entire bug.
The autocomplete made it worse: QCompleter was constructed from a plain list, which Qt copies into a private model. A newly remembered animal therefore never appeared in the dropdown during that visit, pushing users to type the id by hand — straight onto the path that also loses interventions from the session record.
Behaviour verified by driving the real GUI offscreen, not by reading the code.
Fixed
_update_subject_in_repositorynow merges into the stored preset instead of replacing it, so a caller passing a partial dict cannot destroy keys it never mentioned. A key the caller does pass still wins — deleting an intervention through its dialog still persists correctly._add_subjectseeds from the remembered preset (falling back to the record already in the session) and overlays the form data, so interventions reach the session record and therefore the recording's metadata.- The completer is backed by a retained
QStringListModel, refreshed on every repository change via a new_refresh_subject_completer(). Animals remembered during a visit now appear in the dropdown immediately.
Four regression tests were written before the fix: three failed against the old code and pass now; the fourth pins that merging never resurrects a deleted intervention.
Full suite green (2184 passed, 92% coverage).
Provenance
Not introduced by an automated code sweep. The partial-dict/replace mismatch dates to ba1dd49 (2025-10-16). A later fix (4189e5a, 2026-05-14) hardened dict aliasing one line away without noticing it.
Full changelog: v0.11.1...v0.11.2
Files
bartulem/usv-playpen-v0.11.2.zip
Additional details
Related works
- Is supplement to
- Software: https://github.com/bartulem/usv-playpen/tree/v0.11.2 (URL)
Software
- Repository URL
- https://github.com/bartulem/usv-playpen