Skip to content

Fix code review findings, node loss on device delete, and Run tab timer - #183

Merged
gbradham merged 7 commits into
mainfrom
claude/glider-code-review-e6b291
Sep 30, 2026
Merged

gbradham merged 7 commits into
mainfrom
claude/glider-code-review-e6b291

Conversation

@gbradham

Copy link
Copy Markdown
Member

Fixes about 80 findings from a repo-wide code review, plus two user-reported bugs. The full suite passes locally (5813 passed, 4 skipped); ruff and black are clean.

User-reported bugs

  • Nodes vanished after their output device was deleted. ExperimentSession.remove_device/remove_board deleted every node bound to the device. The editor kept drawing them, but reassigning showed no PWM row, the assignment was not kept, and the nodes were missing from the saved file. Removing a device now only unbinds it (_unbind_nodes). A regression test deletes the device, reassigns PWM, saves and reloads.
  • Run tab timer disappeared when a run started. The Run page hid its timer while live, and RunnerShell hides the banner on the Run tab, so no timer was visible. The header timer now always shows.

By area

  • Hardware (hal/, harp):
    • Declarative GPIO and PWM outputs go low on shutdown.
    • Serial and Harp ports get write timeouts and cancel in-flight reads.
    • I2C closes under its lock.
    • Mega analog pins map to the right channel.
    • E-stop loops over a copy of the pin table.
    • Stepper and BLE setup release what they claimed.
    • BLE retries only after a real disconnect.
  • Core:
    • E-stop stops hardware first.
    • .glider, config, device library, project and adopt files are written atomically (core/fileio.py).
    • A recorder failure aborts start and rolls back.
    • Device teardown runs in parallel with timeouts.
    • Flow load failures block start, and nodes with a missing device are kept.
    • A node error stops the run safely.
    • Execs that fire while paused replay on resume.
    • Plugin fixes: two-group name collision, reload, --no-plugins, and installer validation.
    • A stalled camera now reaches the operator.
  • Vision:
    • Recorders finalize from PAUSED and ERROR.
    • The tracking logger recovers after a write error.
    • Multi-camera callbacks re-register after a preview restart.
    • Frames sent to the CV worker are capped to the newest one.
    • Stale tracks are no longer logged.
    • The writer size follows real frames.
    • Fps correction uses capture timestamps.
    • Circle zones are tested in pixel space.
    • A cancelled tracking run is reported as cancelled.
  • Behavior analysis (changes reported numbers, see CHANGELOG):
    • Durations for strided ethograms were about 3× too low.
    • Mirror augmentation leaked between train and test.
    • Mirroring now uses a fixed pivot.
    • Dropout frames no longer bias the speed threshold.
    • Background is scored in cross-validation.
    • An fps mismatch between model and poses now warns.
    • Streamed and batch runs now give the same freeze labels.
    • Cross-validation macro-F1 uses the same support floor as evaluation.
    • Annotation saves are atomic.
  • Session Review:
    • Moving a marker's scope saves the new store first.
    • Saves merge with other writers.
    • A changed time zero opens read-only.
    • Fixing one session's pose or arena no longer drops the cohort.
    • These no longer crash: an empty ethogram, a share read error, duplicate session ids.
    • Timeline edge and trim fixes.
  • GUI:
    • A failed or cancelled save no longer loses work.
    • New and Open are refused mid-run.
    • Undo is cleared on New and Open.
    • Undoing a node delete restores its type, state and connections.
    • Zone config propagates on New.
    • Running QThreads are never destroyed (new gui/qthreads.py).
    • The annotator keeps its trim on close.

Behavior changes on the rig

  • Start refuses if any recorder fails to start, including a configured mic that is missing.
  • Start refuses if flow nodes failed to load.

Deliberately left open

  • .glider has no schema version.
  • No detection of exec cycles without a Delay.
  • Two CNN metric choices in E8: gap-filling length and the leaky early-stopping split.
  • No per-frame video timestamp file, and no re-keying of the tracking frame index.
  • The live-behavior frame queue is still unbounded.
  • G7 could not be reproduced.

Some intermediate commits are not green on their own: the vision commit uses gui/qthreads.py, which lands in the GUI commit.

The Run page hid its header timer while live, expecting the run banner to
carry it, but RunnerShell hides the banner on the Run tab, so no timer
showed there at all.
…LE teardown

Declarative GPIO/PWM outputs go low on shutdown; serial and Harp ports get
write timeouts and cancel in-flight reads; I2C closes under its lock; Mega
analog pins map to the right channel; e-stop iterates snapshots; stepper and
BLE setup release what they claimed; BLE retries only after a real drop.
…nfigured

Hardware stops first on e-stop; .glider, config, device library, project and
adopt files are written atomically; recorder start failures abort the start
and roll back; device teardown is parallel and bounded; flow load failures
block start, and nodes with a missing device are kept; a node error stops the
run safely; paused exec propagation replays on resume; plugin load, reload and
install fixes; a stalled camera now reaches the operator.
…rames

Recorders finalize from PAUSED and ERROR; tracking logger recovers after a
write error; multi-camera callbacks re-register after a preview restart;
CV hand-off is bounded to the latest frame; stale tracks are no longer
logged; writer size follows real frames; stalls raise an error; fps
correction uses capture timestamps; circle zones are tested in pixel space;
cancelled tracking is reported as cancelled.
Changes reported numbers; see CHANGELOG. Mirrored copies share zone ids;
background is scored in CV; durations use frame numbers and stride;
dropout re-seeds no longer bias speed thresholds; fps mismatches warn;
mirroring uses a fixed pivot; streamed runs match batch freeze labels;
CV macro-F1 uses the evaluation support floor; annotation saves are atomic.
Scope moves save the new store first; saves merge with other writers;
a changed time zero opens read-only; pose/arena fixes reload one session in
place; failed video opens stay local; empty ethograms, share read errors and
duplicate session ids no longer crash; timeline edge and trim fixes.
…saved work

Deleting a device used to delete every node bound to it from the session
(the fix is in ExperimentSession.remove_device, committed with core), so
reassigning showed no PWM row, the assignment was not kept, and the nodes
were gone on reopen. Also: a failed or cancelled save no longer lets
New/Open/close discard work; New/Open are refused mid-run; undo is cleared
on New/Open and node undo restores type, state and connections; zone config
propagates on New; running QThreads are never destroyed (new qthreads
helper); annotator persists its trim on close and aborts merges on failed
saves.
@gbradham
gbradham merged commit aa91cd8 into main Sep 30, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant