diff --git a/.agents/skills/g6-orientation/SKILL.md b/.agents/skills/g6-orientation/SKILL.md index 9a4b6637..ffd8f56d 100644 --- a/.agents/skills/g6-orientation/SKILL.md +++ b/.agents/skills/g6-orientation/SKILL.md @@ -42,7 +42,7 @@ interface. |---|---| | **reiserlab/maDisplayTools** | **MATLAB** tools (G4+). Pattern math reference — **web output must match MATLAB exactly** (CI validates, tol 1e-4). Its protocol **runner is G4.1-only and frozen** (decision 2026-10-26); protocol authority = `webDisplayTools/docs/development/v3-spec.md` + conformance fixtures. (Its `docs/development/G4G6_ROADMAP.md` is largely historical now — use the umbrella docs for current G6.) | | **reiserlab/LED-Display_pyDisplayTools** (pyDisplayTools) | **Python** tools for the displays (G4 pattern + experiment-folder tools). **Accepted destination** for the Python arena library and the **headless runner** (`arena-run`), a peer of the web runner (decision 2026-10-26). | -| **reiserlab/rig-nodes** | **Accepted destination, not yet created:** shared ROS 2 infrastructure for every lab rig (`rig_interfaces`, device nodes for FicTrac / Kinefly / BIAS / ScanImage / SiPM, MCAP recording and supervision primitives). Today that code lives in `webDisplayTools/rig/` on the 2026-10-20 release candidate. Record: `webDisplayTools/docs/development/rig-software-repos-and-runners.md`. | +| **reiserlab/rig-nodes** | **Current location (since 2026-10-26)** of the shared ROS 2 infrastructure for every lab rig: `rig_interfaces` (FicTracFrame, ArenaFrame, ConnectorReply), the device adapters + simulators (FicTrac, Kinefly, BIAS, ScanImage; SiPM and the ScanImage frames node follow when their PRs land), the MCAP recorder/indexer/CDR decoder/Foxglove rewriter, the supervision primitives and the Zenoh configs, as the `rig_nodes` + `rig_interfaces` packages (one package-set version, conda channel at a release tag). `CONTRACT.md` there is the graph contract (topics, QoS, envelope, invariants). webDisplayTools' `rig/` installs the set and keeps only the arena gateway, composition and visualization. Record: `webDisplayTools/docs/development/rig-software-repos-and-runners.md`. | ### G6 firmware (what the web connects to over USB) | repo | role | @@ -120,13 +120,15 @@ interface. (`CE_DISPLAY_ACTIVE`); STOP also blanks the panels (they latch the last frame). - **"Web is the runner"** (CSHL) — the browser **executes** the protocol, host-timed: `js/arena-runner-g6.js`. -- **FicTrac closed loop** — `fictrac_sim.py` (or real FicTrac) → **`fictrac-bridge/bridge.py`** +- **FicTrac closed loop** — the FicTrac simulator (`rig_nodes.sims.fictrac_sim`, rig-nodes; or real FicTrac) → **`fictrac-bridge/bridge.py`** (WebSocket `ws://localhost:8765` ← UDP `:60000`) → browser. `pixi run bridge` + `pixi run sim` (start the bridge first). The web runner executes only the `fictrac` and `log` plugins; `backlight`/`camera`/`temperature` are declared for MATLAB and **skipped on the web**. -- **ROS 2 graph (LAB-303, candidate 2026-10-20)** — `rig/` replaces the bridge with a graph +- **ROS 2 graph (LAB-303, released 2026-10-20/26)** — `rig/` replaces the bridge with a graph (rmw_zenoh, MCAP record, BIAS + ScanImage connectors) behind the SAME WebSocket; the Studio is - unchanged. Where the pieces will live from here: `rig-software-repos-and-runners.md` (above). + unchanged. Since 2026-10-26 the device nodes, simulators and recording primitives come from the + installed `rig_nodes` package (reiserlab/rig-nodes); `rig/` keeps the gateway (`bridge_node.py`), + the composition (`rig.py`) and the arena visualization. Record: `rig-software-repos-and-runners.md`. ## Pointers (go here for depth) diff --git a/.github/workflows/rig-interfaces.yml b/.github/workflows/rig-interfaces.yml deleted file mode 100644 index 215eccf9..00000000 --- a/.github/workflows/rig-interfaces.yml +++ /dev/null @@ -1,140 +0,0 @@ -# Build rig/interfaces/rig_interfaces (the typed ROS 2 messages of the arena bridge graph, -# LAB-303) ONCE per platform in CI and publish the result as a conda channel, so a rig PC installs -# typed messages as a download — no MSVC, no build backend, no MAX_PATH workaround. Decision and -# the consumer-side manifest edits: rig/docs/typed-distribution-decision.md; the measurements -# behind it: rig/docs/typed-windows.md. -# -# Runs: build-only on a PR that touches the package or this file (proves the three platforms still -# build); the `rig-interfaces-channel` artifact on every run; the hosted-channel upload only on an -# `rig-interfaces-v*` tag AND only when the repository variable RIG_INTERFACES_CHANNEL names a -# prefix.dev channel (with the PREFIX_API_KEY secret). Until the lab owns one, the channel artifact -# is committed into rig/channel/ by hand (the decision note has the recipe). -name: rig-interfaces - -on: - pull_request: - paths: - - 'rig/interfaces/**' - - '.github/workflows/rig-interfaces.yml' - push: - tags: ['rig-interfaces-v*'] - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: rig-interfaces-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -env: - # The pixi + pixi-build-ros pair the package was last built and tested with (ww18 2026-10-16, - # docs/typed-windows.md). Bump deliberately: the backend is NOT in pixi.lock. - PIXI_VERSION: v0.80.0 - -jobs: - build: - name: build (${{ matrix.subdir }}) - strategy: - fail-fast: false - matrix: - include: - # windows-2022 carries VS 2022 → conda-forge's vs2022 activation finds the v143 - # toolset without the Build-Tools-2026 detour of docs/typed-windows.md W2. - - { os: windows-2022, subdir: win-64 } - - { os: macos-14, subdir: osx-arm64 } - - { os: ubuntu-24.04, subdir: linux-64 } - runs-on: ${{ matrix.os }} - defaults: - run: - shell: bash - working-directory: rig - steps: - - uses: actions/checkout@v7 - with: - persist-credentials: false - - uses: prefix-dev/setup-pixi@v0.10.2 - with: - pixi-version: ${{ env.PIXI_VERSION }} - run-install: false - # MAX_PATH: the runner's checkout (D:\a\webDisplayTools\webDisplayTools\rig, 40 - # chars) plus the ~211 chars the rosidl build adds crosses 260. detached-environments - # moves .pixi (build workspace included) to a 4-char root — the ww18 recipe. - - name: Windows build root - if: runner.os == 'Windows' - run: pixi config set --local detached-environments 'C:\px' - - name: pixi build rig_interfaces - run: | - rm -rf ../dist - pixi build --path interfaces/rig_interfaces/pixi.toml --output-dir ../dist - mkdir -p ../dist/${{ matrix.subdir }} - mv ../dist/*.conda ../dist/${{ matrix.subdir }}/ - ls -la ../dist/${{ matrix.subdir }} - # The archive must be a well-formed .conda for the subdir it claims; `..` in a packaged - # path (the Windows bug the CMakeLists workaround covers) would already have failed above. - - name: inspect the package - run: | - f=$(ls ../dist/${{ matrix.subdir }}/*.conda) - python3 - "$f" <<'EOF' - import sys, zipfile - path = sys.argv[1] - names = zipfile.ZipFile(path).namelist() # a .conda = zip{pkg-*.tar.zst, info-*.tar.zst, metadata.json} - assert any(n.startswith("pkg-") for n in names) and any(n.startswith("info-") for n in names), names - print(path, names) - EOF - - uses: actions/upload-artifact@v5 - with: - name: rig_interfaces-${{ matrix.subdir }} - path: dist/${{ matrix.subdir }}/*.conda - if-no-files-found: error - retention-days: 30 - - channel: - name: channel (index + artifact) - needs: build - runs-on: ubuntu-24.04 - steps: - - uses: prefix-dev/setup-pixi@v0.10.2 - with: - pixi-version: ${{ env.PIXI_VERSION }} - run-install: false - # One artifact per subdir → channel//.conda (upload paths are relative to - # dist/, so the subdir is restored here from the artifact name). - - uses: actions/download-artifact@v5 - with: - pattern: rig_interfaces-* - path: artifacts - - name: assemble + index the channel - run: | - mkdir -p channel - for d in artifacts/rig_interfaces-*; do - subdir=${d#artifacts/rig_interfaces-} - mkdir -p "channel/$subdir" - cp "$d"/*.conda "channel/$subdir/" - done - pixi exec rattler-index fs channel - find channel -type f | sort - python3 - <<'EOF' - import json, pathlib - for rd in sorted(pathlib.Path("channel").glob("*/repodata.json")): - pk = json.load(open(rd))["packages.conda"] - for name, rec in pk.items(): - print(rd.parent.name, name, rec["sha256"], [d for d in rec["depends"] if d.startswith("ros2-distro-mutex")]) - EOF - # The deliverable: a complete three-platform channel. Commit it into rig/channel/ - # (decision note §"Releasing a new build") or let the step below upload it. - - uses: actions/upload-artifact@v5 - with: - name: rig-interfaces-channel - path: channel - if-no-files-found: error - retention-days: 90 - # Hosted channel (prefix.dev), only when the lab has one: set the repository variable - # RIG_INTERFACES_CHANNEL to its name and the secret PREFIX_API_KEY. Tags only, so a - # PR build can never publish. - - name: upload to the hosted channel - if: startsWith(github.ref, 'refs/tags/rig-interfaces-v') && vars.RIG_INTERFACES_CHANNEL != '' - env: - PREFIX_API_KEY: ${{ secrets.PREFIX_API_KEY }} - RIG_INTERFACES_CHANNEL: ${{ vars.RIG_INTERFACES_CHANNEL }} - run: pixi exec rattler-build upload prefix --channel "$RIG_INTERFACES_CHANNEL" channel/*/*.conda diff --git a/CLAUDE.md b/CLAUDE.md index afbcb785..24ab1b0d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -107,11 +107,18 @@ When editing web tools, audit all buttons and controls in the modified code sect - Dependencies via CDN or vendored under `js/vendor/` (e.g. `yaml`); no runtime npm - Web outputs must match MATLAB outputs exactly -**Repository boundaries (decision 2026-10-26):** `docs/development/rig-software-repos-and-runners.md` -is the record. The browser tools and their rig-side gateway (`rig/nodes/bridge_node.py`) stay -here; the Python arena library + headless runner go to `LED-Display_pyDisplayTools`; shared ROS 2 -infrastructure (interfaces, device nodes, recording, supervision) goes to `rig-nodes`, which does not -exist yet. Until the extraction session, every file is where the record's inventory says it is today. +**Repository boundaries (decision 2026-10-26; extraction done the same day):** +`docs/development/rig-software-repos-and-runners.md` is the record. The browser tools, their rig-side +gateway (`rig/nodes/bridge_node.py`), the arena composition (`rig/nodes/rig.py`, `rig/pixi.toml`) and the +arena visualization stay here; the Python arena library + headless runner go to +`LED-Display_pyDisplayTools` (LAB-337); shared ROS 2 infrastructure lives in **`reiserlab/rig-nodes`** +(`rig_interfaces`, the device adapters + simulators, `rig_nodes.recorder` / `mcap_index` / `cdr` / +`foxglove_json`, `rig_nodes.supervise`, the Zenoh configs; contract: its `CONTRACT.md`) and is INSTALLED +into `rig/` as the pinned `rig_nodes` + `rig_interfaces` packages from that repo's channel. A node fix +is tested here with `pixi install -e dev` (rig-nodes `main` built from source — git source dependencies, +NEVER path dependencies on a sibling checkout: pixi validates every environment's source paths before +installing any environment, which broke `pixi install` on rig PCs on 2026-10-27); a release of the set +re-pins `rig/pixi.toml`. Never re-add a device node or recorder copy under `rig/`. ### Dev environment (pixi — the only tool you install) diff --git a/arena_studio.html b/arena_studio.html index 85e4b25f..ddf4b6b6 100644 --- a/arena_studio.html +++ b/arena_studio.html @@ -3426,7 +3426,7 @@

Import error