Skip to content

rig: pixi run qc — the five-minute release validation of a tier on a rig PC (LAB-222, LAB-338) - #285

Merged
7 commits merged into
mainfrom
rig/qc-five-minute
Oct 29, 2026
Merged

7 commits merged into
mainfrom
rig/qc-five-minute

Conversation

@mbreiser

@mbreiser mbreiser commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

One command on a rig PC validates a webDisplayTools tier end to end in about five minutes of wall time, with the person at the rig only confirming what they see. It replaces the hour of hand-driven QC of 2026-10-27/28 (docs/development/handover-qc-windows-2026-10-26.md; results on #274).

cd rig
pixi run qc -- --tier next            # the candidate on /next/, rig detected from the hostname
pixi run qc -- --tier next --rig ww14 --auto   # no Enter prompts: a Claude session drives it

What it does (rig/qc/qc.py): preflight (pixi ≥ 0.80, ports 7447/8765/60000 free, the rig's services up) → the tier's build.json → a scratch git worktree at exactly that SHA with its own pixi environment (pixi install --locked, plus typed/viz per rig; the rig's checkout and .pixi are never touched) → the candidate's pixi run rig with the rig's flags (flags that build does not know are dropped with a warning) → FicTrac started or found running, frames counted at the gateway, simulator fallback → tests/studio_emulator.py pre-check (a broken candidate fails here, before any browser) → Chrome (a QC profile with no course token) on the tier's arena_studio.html?mode=run&rig=…, driven over DevTools: build SHA + footer, protocol load, bridge connect, the one human click (Web Serial port picker), firmware + panels, Run experiment → pixi run export, runlog-check, closed-loop-report, bench-check → teardown, pass/fail table, validation-note.md and the exact pixi run tiers -- validate … line.

  • rig/qc/profiles.toml — the per-rig rows (ww18, ww14, bergamo, mac: flags, protocol, FicTrac command, Foxglove layout, required ports, report holds) and the checklist text Michael reads at each step. A new rig is a row.
  • rig/qc/qclib.py — the pure half, pinned by tests/test-rig-qc.py (77 checks, runs in the root pixi run test).
  • rig/QC.md — the procedure page: what to type on ww18 / ww14 / Bergamo, the two clicks, where artifacts land (C:\qc\<date>\), safety on a rig PC, adding a rig.
  • rig/pixi.toml — the qc task. The branch includes rig: pin rig-nodes 0.3.0 + re-lock with pixi 0.83 (#280, LAB-338) #281 (rig-nodes 0.3.0 re-lock) so the rig workspace installs on pixi 0.83.

Tested on this Mac against candidate 2026-10-28-rc2 (06bad57) on /next/: PASS end to end in 26–35 s wall with a warm cache — graph (router, fictrac, host, bridge, stimulus, viz, foxglove), FicTrac-MacOS on the looped sample video (50 fps), emulator pre-check, Chrome shows build 06bad57 / v0.100 with the protocol loaded and 51 frames/s at the bridge, Foxglove opened on ws://localhost:8766, export + bag closed + closed-loop report 0 % mismatch. --tier prod on main 8d5b952 fails cleanly at the install step (main's rig lock predates pixi 0.80, #280 — fixed by today's release). The controller path (click → firmware/panels → Studio.runOnce(true) → bench-check) could not run here (no controller); the first exercise is the ww18 dry run.

Finding on the way: a never-used Chrome profile holds ws://localhost:8765 from the Pages origin on the Local Network Access permission prompt (Chrome 155: no error, "connecting…" forever). A DevTools Browser.grantPermissions localNetworkAccess does not unblock it; --disable-features=LocalNetworkAccessChecks does (the flag the Foxglove desktop app itself runs with), so the QC Chrome uses it; --lna-prompt shows the prompt instead.

Linear: LAB-222 (two-tier releases — the validation step), LAB-338 §7 item 8 (the cross-repo smoke on a rig PC). No HTML, no footer, no release-notes file touched; nothing Prettier-formatted.

Tier

next candidate (rig-side tooling + scripts only).

Release notes

none

Test plan

  • pixi run test (root): 73/73 files, incl. the new tests/test-rig-qc.py
  • cd rig && pixi run qc -- --tier next --rig mac --auto end to end on this Mac (rc2 06bad57)
  • --no-browser, interactive mode (piped Enter + a remark), --tier prod failure path
  • ww18 dry run (pixi run qc -- --tier next --rig ww18) — controller path, real FicTrac via fictrac.bat
  • ww14 dry run (pixi run qc -- --tier next --rig ww14) — BIAS connector pre-check, four-color smoke

First run on ww18 (candidate 2026-10-29 rc1, 2026-10-29)

pixi run qc -- --tier next --rig ww18 --auto ran end to end in 104 s: candidate checked out and installed, graph + real FicTrac (96 fps), emulator pre-check PASS, Studio on /next/ with build f49f34f, controller connected on Michael's click, run completed, export, bag, runlog-check and closed-loop-report (0.00 % idx mismatch) all PASS. Two findings, fixed on this branch:

  • The start-frame check was the wrong test on a live rig. A live fly turned the ball −1108° in 8 s; the display tracked it (0.00 % idx mismatch), so bench-check's "holds frame 25/75 for the whole epoch" lines failed. Michael: with FicTrac live the ball can always move. The check is now "epochs open on their start frame": closed-loop-report emits first_idx_after_tare / opens_on_start_frame per epoch (the first post-tare index must be the trialParams frame_index, 25 / 75), qc.py records it, and the rest of the epoch is the idx-mismatch check. The ww18 profile drops holds; holds stays for a bare or blocked ball, where qclib.hold_verdict() turns a hold miss into SKIP when the ball turned.
  • Windows teardown orphans. signal_group(SIGINT) is CTRL_BREAK_EVENT on Windows, delivered to Python as SIGBREAK, which rig.py did not handle: it died before its finally, leaving the nodes and the router running ("ports free again" FAIL). rig.py registers SIGBREAK now.

Also: the bergamo profile runs the public g6_2x10_smoke protocol while the 2P diagnostics protocol lives in the private repo (LAB-227).

🤖 Generated with Claude Code

mbreiser and others added 3 commits October 28, 2026 17:28
…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>
…`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>
…a rig PC (LAB-338)

One command checks the candidate on /next/ (or Production) end to end: the tier's
build.json → a scratch worktree at that SHA with its own pixi environment, the
candidate's graph with the rig's flags, FicTrac (or the simulator), the Studio
emulator pre-check, the tier's Studio in a QC Chrome profile driven over DevTools
(build SHA, protocol load, bridge connect, the one Web Serial click, Run
experiment), export + runlog-check + closed-loop-report + bench-check, teardown,
a pass/fail table and a ready-to-paste validation note. Per-rig rows and the
checklist text live in rig/qc/profiles.toml (ww18, ww14, bergamo, mac); the
procedure is rig/QC.md; tests/test-rig-qc.py pins the pure half.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mbreiser and others added 2 commits October 29, 2026 16:00
…ostics moved to the private repo, LAB-227)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…on protocol needs FicTrac)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…EAK (ww18 rc1 QC findings)

Two findings from the first `pixi run qc` on ww18 (candidate 2026-10-29 rc1, 2026-10-29):

1. bench-check's hold checks assume a still ball. A live fly turned it −1108° in 8 s, the
   display followed FicTrac with 0.00 % idx mismatch, and the QC table said FAIL. New
   qclib.hold_verdict(): when ONLY hold lines failed and closed-loop-report shows an epoch with
   |net turn| >= 45°, the row is SKIP naming the turns; a hold miss on a still ball, or any other
   bench-check failure, stays FAIL. ww18's run/reports look text says so. Tests in test-rig-qc.py.

2. Teardown on Windows left the graph's nodes and the router as orphans ("graph stopped", then
   "ports free again" FAIL on 7447/8765/60000). qc.py stops rig.py with
   rig_nodes.supervise.signal_group(SIGINT), which on Windows is CTRL_BREAK_EVENT on the process
   group; Python delivers that as SIGBREAK, which rig.py did not handle, so it died before its
   `finally` stopped the children. rig.py now registers SIGBREAK where it exists (bridge_node and
   host_monitor already did). QC.md documents both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mbreiser added a commit that referenced this pull request Oct 29, 2026
…f a tier on a rig PC (LAB-222, LAB-338)
mbreiser added a commit that referenced this pull request Oct 29, 2026
Candidate for Production. PRs: #286, #285, #288, #289.

Release-Manifest: releases/2026-10-29.json
…a whole-epoch hold

Michael on the rc1 QC: with FicTrac live the ball can always move, so a check that the display
HOLDS frame 25 / 75 for a whole epoch is the wrong test on a rig. What the two epochs exist to
verify is the v0.91 start frame: the first post-tare index equals the trialParams frame_index
(closed-loop-start-frame.md). closed-loop-report now emits `first_idx_after_tare` +
`opens_on_start_frame` per epoch (and marks "200 @25 ✓" in the table); qc.py records "epochs open
on their start frame" from it; the rest of the epoch is the existing idx-mismatch check. The ww18
profile drops its `holds` (bench-check still judges completion, arena acks, channel, build; `holds`
stays available for a bare or blocked ball, with hold_verdict's SKIP when the ball turned). Tests
in test-closed-loop-report.py cover the open on 25 / 75 and a ≤ 3.3 bridge opening on 0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mbreiser added a commit that referenced this pull request Oct 29, 2026
…f a tier on a rig PC (LAB-222, LAB-338)
mbreiser added a commit that referenced this pull request Oct 29, 2026
Candidate for Production. PRs: #286, #285, #288, #289.

Release-Manifest: releases/2026-10-29.json
@mbreiser mbreiser closed this pull request by merging all changes into main in 62dbbe7 Oct 29, 2026
@mbreiser
mbreiser deleted the rig/qc-five-minute branch October 29, 2026 21:13
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