Skip to content

Release 2026-10-28: Arena Studio v0.100 - #283

Merged
mbreiser merged 30 commits into
mainfrom
release/2026-10-28
Oct 29, 2026
Merged

mbreiser merged 30 commits into
mainfrom
release/2026-10-28

Conversation

@mbreiser

@mbreiser mbreiser commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Release candidate 2026-10-28 rc2 · candidate commit 06bad57a02 · built on main 8d5b952a9c

Live on Next: https://reiserlab.github.io/webDisplayTools/next/

Tool Version
Arena Studio v0.99 → v0.100
PR Title Head CI Release notes
#281 rig: pin rig-nodes 0.3.0 + re-lock with pixi 0.83 (#280, LAB-338) 2218d39e63 green Arena Studio
#269 ros2-poc: okey-cokey rig — CW/CCW pair protocols, camera + G6 Foxglove dashboard, uFMF tools, ww14 run records (LAB-303) e9dd994f74 green ⚠ missing
#282 rig: record the rig-nodes host monitor (/rig/host) in every run's bag db51439a58 green Arena Studio
#284 Imaging boundary: the 2P imaging work moves to the private rig repo; gateway keeps the 2P topics (LAB-303, LAB-319) e25914ebbc green Arena Studio

Promotion checklist

  • CI green on this PR and on every constituent PR (pixi run release checks)
  • Validated on a rig between sessions — comment Validated 06bad57 … (pixi run tiers -- validate --rig … --by …). Any change to a constituent PR = rebuild (rc+1) = validate again.
  • Release window: Slack heads-up posted; nobody is mid-experiment (release lists recent rig runs — advisory)
  • After merge: rigs hard-refresh between sessions; if fictrac-bridge/ changed, rig PCs git pull + restart the bridge

Promote with pixi run release (merges with a merge commit — never squash — and tags release-2026-10-28). Manifest: releases/2026-10-28.json.

🤖 Generated with Claude Code release tooling (scripts/tiers/candidate.py)

mbreiser and others added 30 commits October 26, 2026 16:57
…rk between pairs) per Grace; smoke variant same shape

The full run is now 24 pairs (3 duties x 4 colors x 2 reps), ~16 min; the 10 s pause is
kept across block boundaries. The reversal is phase-continuous (15 s x 80 fps = 1200
frames, a multiple of the 20-frame period) and the camera timestamp moves to the start of
each pair so its round trip never stretches the CW half.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ove camera + G6 dashboard plan

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… dashboard phases 1/1b/2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…303)

Live: bridge_node also publishes /arena/browser (the bag record is unchanged); the new
stimulus_node turns it into the EXPECTED display (the trial's .pat frame x duty in the
panels' LED colors, PNG) and the OBSERVED display (controller telemetry cf rows), plus the
arena's lag, display rate and health, all on the controller's own clock. viz_node gains BIAS
fps-from-count, drops, rtt and writer queue, and --sources. rig.py: --stimulus (included by
--foxglove) and --no-fictrac. Layout: foxglove/arena-okey-cokey.json.

Replay: foxglove_json.py --stimulus rebuilds the same topics from a finished bag
(nodes/dashboard_replay.py, the same pure code) and /camera/image from the run's uFMF
(tools/ufmf.py, BIAS's v4 layout), placed on the bridge clock by the getTimestamp replies.

Panel colors are a Python port of js/panel-color.js, pinned cell by cell under Node.
Tests: test-stimulus 54/54 (incl. a real 80 fps trial from the 2026-10-14 smoke run, every
lag 0), test-stimulus-live 10/10, harness 54/54, root suite 71/71. No live camera (BIAS
unchanged by decision).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e dashboard steps, handover for the lab-PC test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…art from it (no Python/git assumed)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- pixi.toml: viz env on win-64 prepends Library\lib to PATH; foxglove_bridge
  exited 0xC0000135 (foxglove.dll / foxglove_cpp_shared.dll not on the DLL path)
- tools/bias-ufmf.ps1 + config/bias/okey-cokey-bfs-u3-51s5m.json: BIAS v0.73.1
  restarts in jpg and rejects load-configuration until the camera has captured
  once; the script does connect -> 2 s capture -> load, run after every BIAS start
- setup checklist + run sheet: arena on this rig is mounted upside down
  (protocol CW turns CCW seen from above; protocols unchanged, no direction test
  needed), Foxglove install URL/silent flags, 8766 not 8765, path placeholders
  (no D: on ww14), runlog-check pre-run "unknown" trials, known issues
- .gitignore: stop ignoring tests/fixtures/*.jsonl.gz (the okey smoke fixture
  was never committed; still needs adding from ww18)
- okey-cokey-pc-ww14-setup-2026-10-22.md: PC facts, tool versions, BIAS/camera,
  two passing smoke runs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run sheet step 5/6 on REISERLAB-WW14, 2026-10-22:
- Full g6_color_optomotor_test with flies: runlog-check 48/48 pass, BIAS
  58/58 ok, 70 953 frames at 73.3 fps. Results in
  okey-cokey-pc-results-2026-10-21.md.
- The first full attempt died at minute 9 when the Claude desktop app
  restarted and took BIAS, the rig and the Studio server with it. New
  tools/okey-cokey-start.ps1 starts all three through WMI so they outlive
  the launcher; the run sheet points real runs at it.
- The controller moved from COM3 to COM5 (a second Teensy is on COM3):
  setup notes and run sheet now say to pick it by the name G6_Arena.
- A deliberate occlusion made the ufmf 11.8 GB instead of ~0.5 GB; a
  by-eye panel glitch report is recorded as open (telemetry is clean).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ws Terminal tabs

Ran tools/okey-cokey-start.ps1 on ww14 with BIAS, the rig and the server
all stopped: exit 0, ports 5010/7447/8765/8766/8092 up, every listener's
parent chain runs through WmiPrvSE (none under the Claude app), BIAS on
ufmf. The rig and server consoles open as tabs of one Windows Terminal
window, which hid the rig tab from the operator at first; the script,
run sheet and results now say so and how to stop them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or glyph on several panels

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto claude/okey-cokey-rig

# Conflicts:
#	rig/.gitignore
#	rig/HANDOVER-okey-cokey-2026-10-21.md
#	rig/config/bias/okey-cokey-bfs-u3-51s5m.json
#	rig/docs/okey-cokey-foxglove-dashboard-plan.md
#	rig/foxglove/arena-okey-cokey.json
#	rig/nodes/arena_display.py
#	rig/nodes/bias_health.py
#	rig/nodes/dashboard_replay.py
#	rig/nodes/stimulus_core.py
#	rig/nodes/stimulus_node.py
#	rig/okey-cokey-pc-2026-10-21.md
#	rig/okey-cokey-pc-results-2026-10-21.md
#	rig/okey-cokey-pc-setup.md
#	rig/okey-cokey-pc-ww14-setup-2026-10-22.md
#	rig/tests/fixtures/protocols-2026-10-14/g6_color_optomotor_smoke.yaml
#	rig/tests/test_stimulus.py
#	rig/tests/test_stimulus_live.py
#	rig/tools/bias-ufmf.ps1
#	rig/tools/okey-cokey-start.ps1
#	rig/tools/ufmf.py
…y reads (it had only ever existed in one worktree; the .gitignore exception was added 2026-10-22 but the file never was)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d on the installed rig_nodes package (LAB-303, LAB-338)

The shared half of rig/ moved to reiserlab/rig-nodes (PR #274); this merge re-expresses the
okey-cokey additions through the installed package instead of the deleted local modules:

* rig.py — the --no-fictrac / --stimulus / --stimulus-args options and the stimulus Child on top of
  the rig_nodes.supervise composition (fictrac via `python -m rig_nodes.fictrac_udp_adapter` only
  when not --no-fictrac; the udp 60000 preflight skipped the same way).
* foxglove_json.py — the arena wrapper around rig_nodes.foxglove_json.convert keeps #274's
  `enrich` hook (frame derivations, FicTrac columns) and adds the --stimulus dashboard replay as the
  rewriter's `derive` hook (whole-stream → new topics, foxglove.CompressedImage by well-known
  schema name); dashboard_replay.run_streams is unchanged. Needs rig-nodes PR #1 (derive hook).
* bias_health.py — moved to rig-nodes (rig_nodes.bias_health, rig-nodes PR #1); viz_node.py,
  dashboard_replay.py and the tests import it from there, test_stimulus's bias_health section
  moved with it (tests/test_pure.py in rig-nodes).
* viz_node.py / stimulus_node.py / test_stimulus_live.py — `_common` → `rig_nodes._common`,
  the launcher primitives → `rig_nodes.supervise`.

Until the next rig-nodes package set ships, run with `cd rig && pixi install -e dev` (a sibling
../../rig-nodes checkout on feat/bias-health or later) — the released 0.2.1 has no bias_health /
derive. Tests (dev env): test-stimulus 50/50, test-viz, `pixi run test`; root `pixi run test` 72/72.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ut; test_stimulus_live reads them from rig_nodes.zenoh

`pixi install -e dev` installs rig_nodes EDITABLE (a .pth into ../../rig-nodes/src/rig_nodes), so the
workspace-level ZENOH_ROUTER/SESSION_CONFIG_URI (…/site-packages/rig_nodes/config/…) named files that
do not exist in that environment: the router and every rclpy process failed with "Error configuring
Zenoh session" and `pixi run -e dev test` lost every check. `[feature.dev.activation.env]` (+ the
win-64 target) now points both URIs into the checkout. (Pre-existing on feat/rig-nodes-extraction,
where the dev environment had not been run through the harness.)

test_stimulus_live.py read `rig/config/zenoh-*.json5`, deleted by the extraction; it takes the
installed package's paths (`rig_nodes.zenoh.ROUTER_CONFIG` / `SESSION_CONFIG`) instead.

Verified in the dev environment: `pixi run test` 62/62, `test-stimulus-live` 10/10.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ency activation, bias_health from rig-nodes 0.3.0 (LAB-303)

The dev environment uses git source dependencies since 2026-10-27 (the package is installed, not
editable), so the sibling-checkout Zenoh URIs are gone. rig_nodes.bias_health and the derive hook
ship in rig-nodes 0.3.0 (rig-nodes#1), which the candidate's re-pin PR installs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…every run's bag

A generic node (nothing FicTrac- or arena-specific) that publishes, once a second, CPU per
core (window mean + busiest 100 ms sub-window, P/E-core class, sampler lateness, context
switches / interrupts / DPCs), memory + page file + hard faults, log-volume free space,
per-disk and per-adapter rates, NVIDIA GPU (incl. NVENC/NVDEC) and the top processes plus
pinned groups (FicTrac, BIAS, MATLAB, browser, Foxglove, router, each graph node). The
method is atlas-bench tools/cpu_sampler.py: cycle counters and one NtQuerySystemInformation
call for all processes on Windows; GetIfEntry2 for network; NVML through ctypes; psutil
for the rest and on Linux/macOS.

- rig/nodes/host_sampler.py (no ROS) + host_monitor.py: rig-nodes material, prototyped here.
  Typed rig_interfaces/HostStats when installed (requested for rig-nodes 0.3.0; spec in
  rig/docs/host-stats-request.md), else String JSON with the same field names.
- bridge_node.py records /rig/host into the bag; rig.py starts the monitor by default
  (--no-host-monitor, --host-monitor-args).
- Cost on ww18: 0.9 % of one core (median); 4.9 % of the harness run's compressed payload,
  about 1.0 MB/h. Gated in the harness (<= 2 % of a core, <= 5 % of the payload).
- tests/test-host-sampler.py (root suite, no ROS/psutil): fields and types against the .msg
  spec, rates, CPU mean vs peak, process selection, strict JSON.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…latform (#280, LAB-338)

Manifest only; the re-lock with pixi 0.83 follows once the v0.3.0 channel is tagged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rig-nodes

The generic host monitor (host_sampler.py, host_monitor.py, its unit test, design note and
the HostStats message spec) belongs in reiserlab/rig-nodes as rig_nodes.host_monitor; it is
being ported there from branch rig/host-monitor-port (f5cf5a6). What stays here is the arena
rig's composition and gateway:

- bridge_node.py records /rig/host into each run's bag (typed HostStats when rig_interfaces
  has it, else String).
- rig.py starts `python -m rig_nodes.host_monitor --log-dir rig/runlogs --py-root rig/` when
  the installed rig_nodes ships it (a note otherwise); --no-host-monitor, --host-monitor-args.
- test_ros2_poc.py runs it the same way and checks samples, fields, per-core sanity, pinned
  graph nodes, its CPU (<= 2 % of a core) and storage (<= 5 % of the compressed payload);
  skipped with an info line when the installed rig_nodes has no host monitor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…`channel` feature (default/typed/viz), dev from git alone

Channel read at the payload commit 5e20dee (the v0.3.0 tag sits one commit early; moving it is a
one-liner for Michael). `dev` no longer includes `typed` and the rig_nodes pin is no longer a workspace
dependency: one package name from a git source and the channel does not solve once the released version
is ahead of rig-nodes main. Verified on the Mac with the sibling rig-nodes checkout renamed away:
`pixi install --locked` (default + typed), check-typed lists the eight message types, `pixi run test`
59/59, `pixi run -e typed test` 62/62. Closes #280. LAB-338.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…7942b8

# Conflicts:
#	rig/nodes/rig.py
#	rig/tests/test_ros2_poc.py
…after the BIAS node, docstring)

Coordinated with the session building the candidate with #269 (stimulus node): its hunks edit
the --sim argparse neighbourhood, the --foxglove docstring line and the lines after
nodes.append(bridge). Ours now sit after --sim-args, after the BIAS node append and after the
--sim docstring example, so the two PRs merge without conflict. No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on record §3.3 amendment)

Michael's decision, 2026-10-28: everything specific to the 2P imaging experiments
lives in reiserlab/scanimage-2026-bergamo `2p-rig-nodes/` (a pixi workspace in the
rig-nodes layout on the public rig_nodes package; PROVENANCE.md there lists the
source commit of every file). Copied with provenance, not rewritten in history.

Removed here:
- tiff2mcap (#273): rig/tools/tiff_run_to_mcap.py, check_tiff2mcap.py,
  rig/tests/test_tiff2mcap_runlog.py and the tiff2mcap / test-tiff2mcap /
  check-tiff2mcap tasks (patfile.py stays: arena code bound for pyDisplayTools)
- tools/led_sweep_si.py, tools/led_sweep_quicklook.py
- records: rig/SCANIMAGE-DAY.md, rig/scanimage-day-2026-10-16.md,
  docs/development/2p-scanimage-signal-logging.md, 2p-line-sync-rig-checklist.md
- the arena composition's ScanImage node: rig.py --scanimage / --si-mock /
  --scanimage-args, the scanimage-node / scanimage-cmd / si-mock tasks, and the
  harness's ScanImage stand-in + its 5 checks (rig-nodes 0.4.0 drops the node,
  rig-nodes #4; re-pinning rig/ to 0.4.0 must not precede this change)

Kept public (the boundary): the gateway's connector dispatch and its scanimage
CONNECTOR_TOPICS entry, mcap_convert's connector derivation, the Studio's
ScanImagePlugin and the emulator's --scanimage-cmds path; the 2P protocols and
the Bergamo arena rig profile stay for now (comments repointed).

Also: the dated §3.3 amendment in rig-software-repos-and-runners.md, the
orientation skill's rig-nodes row, CLAUDE.md's rig line, and
tests/test-flasher-catalog.js (its exception for the moved checklist), the expected
harness counts in rig/WINDOWS-TEST.md.

Tests on the Bergamo PC: root `pixi run test` 72/72 files; rig/ harness
`pixi run test` 54/54 and `-e typed` 57/57 (main: 59 / 62, minus the 5 ScanImage
checks; rig/WINDOWS-TEST.md updated), run on
rig_nodes 0.2.1 with rig/pixi.lock unchanged (pixi 0.82 needed an unlocked
install, the known #280 lock-format issue the next candidate re-locks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ateway half of #261 / #266)

The 2P rig's nodes are private since 2026-10-28 (reiserlab/scanimage-2026-bergamo
`2p-rig-nodes/`; decision record §3.3 amendment). What stays public is the gateway's
side, ported from #266's head (a4442ad, which includes #261) onto main:

- bridge_node: the `sipm` connector (/sipm/cmd|reply|status in CONNECTOR_TOPICS,
  every bag's topic map and hello_ack), and the ScanImage frame-stream STREAM_TOPICS
  (/scanimage/frame_meta, frame_stats, preview/meta, preview/ch1-4 as
  sensor_msgs/CompressedImage) recorded on arrival, never derived into the run log
- mcap_convert: /sipm/reply|status → {"type":"connector","src":"sipm",…} events
- tests/test_gateway_registration.py (`pixi run test-gateway`, 5 checks): the
  gateway checks of #266's test_sipm (D1-D3) and #261's test_scanimage_frames (§G),
  which the private harnesses no longer carry

Not ported: the nodes, their harnesses and tasks, the rig.py flags (all private
now), and #261's rig_nodes._common SIGBREAK fix (_common lives in rig-nodes; the
private package carries it as a shim).

Tests on the Bergamo PC: test-gateway 5/5; harness `pixi run test` 59/59 (same
as main); rig/pixi.lock unchanged (installed unlocked for the test, #280).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… recorded schema

The converter's pure CDR decoder reads no nested message arrays (HostStats carries DiskStats[],
NetStats[], GpuStats[], ProcStats[]), and the converter never needs /rig/host, so the typed
check deserializes with ROS itself. The info line now says which type was recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…+ G6 Foxglove dashboard, uFMF tools, ww14 run records (LAB-303)
…e rig repo; gateway keeps the 2P topics (LAB-303, LAB-319)

# Conflicts:
#	rig/nodes/bridge_node.py
#	rig/nodes/rig.py
#	rig/pixi.toml
#	rig/tests/test_ros2_poc.py
Candidate for Production. PRs: #281, #269, #282, #284.

Release-Manifest: releases/2026-10-28.json
@mbreiser

Copy link
Copy Markdown
Contributor Author

✅ Validated 06bad57 — candidate 2026-10-28 rc2 — on ww14 + ww18 + mac by Michael Reiser (ww14, ww18), Claude (Mac)

Mac (osx-arm64, pixi 0.83), candidate SHA 06bad57: cd rig && pixi install --locked from the rig-nodes 0.3.0 channel (8 s, no sibling checkout); a plain pixi install leaves rig/pixi.lock unchanged (#280 fixed); harness 59/60 with the host monitor recorded in the bag (/rig/host 19 samples, 3.3 % of the compressed payload); the one FAIL is the host monitor's own CPU on macOS (6.7 % of one core via the psutil path vs 0.9 % on ww18's cycle counters), a dev-machine cost, follow-up in rig-nodes 0.3.1; typed env check-typed lists HostStats; /next/build.json at this SHA, Studio footer v0.100; no ScanImage / tiff2mcap leftovers in rig/ (checked by the Bergamo session).

ww18 (reiserlab-ww18), PR heads in this candidate: #281's lock installs clean on pixi 0.83; #282 typed run from rc1 + #282: /rig/host recorded as rig_interfaces/HostStats, all host-monitor checks pass except the typed storage gate (6.7 % vs 4.8 % String; quantization fix for 0.3.1, rigs run the String default); earlier on #274's head: two real-FicTrac arena runs, idx mismatch 0.00 %, runlog-check OK.

ww14 (okey-cokey rig), #269 on /next/: pixi 0.83 already; pixi install --locked 9.5 s + -e viz 6.2 s, git status rig/ clean (#280 fixed); pixi run rig -- --no-fictrac --bias --foxglove --viz-args "--sources bias" --stimulus-args "--panel-layout four-color" → [rig] up: router, bias, host, bridge, stimulus, viz, foxglove, foxglove_bridge 3.6.0 still up after 7 min (the #269 Windows PATH fix works), about 65 channels advertised; Foxglove app on ws://localhost:8766 with arena-okey-cokey.json: camera tiles live from BIAS (2161 frames, 0 bad, lat p50 0.98 ms / p99 2.07 ms), arena-display panels empty with the arena off (expected); /next/ Studio footer v0.100, wdt-build sha 06bad57 rc2. Not a candidate issue: Chrome on ww14 refuses the Pages origin a ws://localhost:8765 WebSocket (Local Network Access, LAB-304), while a Python client connects to the same bridge; the controller stayed off.

Bergamo PC, #284: root suite 72/72, harness 54/54 (+ 57/57 typed) on the removal branch, test-gateway 5/5; 2p-rig-nodes tests pass against rig-nodes 0.3.0.

@mbreiser
mbreiser marked this pull request as ready for review October 29, 2026 00:43
@mbreiser
mbreiser merged commit 59a377b into main Oct 29, 2026
5 checks passed
@mbreiser
mbreiser deleted the release/2026-10-28 branch October 29, 2026 00:43
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.

4 participants