There is a newer version of the record available.

Published July 10, 2026 | Version v0.11.2

bartulem/usv-playpen: v0.11.2

  • 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_repository now 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_subject seeds 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

Files (55.0 MB)

Name Size
md5:454bbb26fcc9e7bcbe130bf584b15a19
55.0 MB Preview Download

Additional details

Related works