One-command fleet UI check: commit the wire-only robot fixture behind browser_check.mjs - #89
Merged
Conversation
M3's browser checks (browser_check.mjs) needed a stack assembled by hand, and the robots behind them were a throwaway script in a scratch directory — so the next person to touch server/ui/ needed hardware or had to rewrite it. mote_fleet/test/fake_robots.py is that script, committed: robots that exist only on the wire. Every payload is built by protocol.py, so it is the contract rather than a second robot implementation. It models what the UI renders differently — an ok robot and a degraded one, a moving pose, the task transitions including both refusals, a redelivered command recognised rather than re-run, and one robot that drops its socket without a DISCONNECT so the broker publishes its will. mote_fleet/test/ui_check.py (pixi run fleet-ui-check) wraps a whole stack around it: container broker, fleet server, the sim's office_world bundle as a basemap, enrolled robots and an operator token, then browser_check.mjs, then teardown. Ports are ephemeral and state is a temp directory, because the workstation already runs a broker and a server on 1883/9001 for a real robot; every process is setsid'd so teardown reaps this stack and nothing else. Two runs at once on different sites both pass. `-- --keep` leaves it up for UI work. browser_check.mjs now polls each assertion to a deadline instead of sleeping guessed intervals, finds chrome on PATH rather than assuming google-chrome, and takes an ephemeral debugging port so two runs cannot attach to one browser. test_fake_robots.py holds the fixture to protocol.py and to the task layer's grammar (no broker, no ROS, runs in CI). m3-verification.md §2 now cites the command, and records why this stays an operator's tool rather than a CI gate: it needs docker (conda's mosquitto still has no websockets) and a chrome, which the arm runner has not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XXRrpPSGvkTLHjFUAJfg4C
MJohnson459
force-pushed
the
fleet-ui-check
branch
from
August 2, 2026 09:28
ff662b0 to
7cb6dd1
Compare
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One command brings up a fake fleet, checks the dashboard in a real browser, and tears it down.
What changed
mote_fleet/test/fake_robots.py— the wire-only robot, committed. Every payload is built byprotocol.py, so it is the contract rather than a second robot implementation. It models what the UI renders differently: anokrobot and adegradedone, a pose that moves, task transitions (goto dropoff-> dispatched/accepted/succeeded,wibble-> rejected "unknown command",goto nowhere-> rejected "unknown zone"), a redelivered command recognised rather than re-run, and one robot that drops its socket without a DISCONNECT so the broker publishes its Last Will. Usable standalone against any broker for UI hacking.mote_fleet/test/ui_check.py+pixi run fleet-ui-check— the stack around it: container broker (shippedmosquitto.conf, listener ports rewritten), fleet server, the sim'soffice_worldsite bundle copied into a temp--maps-diras the basemap, robots enrolled through the realPOST /v1/enroll, an operator token, thenbrowser_check.mjs, then teardown.-- --keepleaves it up with the URL and token printed.--sitepicks another world.browser_check.mjs— every assertion now polls to a deadline (settle()) instead of sleeping a guessed interval; chrome is located on PATH rather than assuminggoogle-chrome(the old.find(Boolean)always returned the first name); the debugging port is ephemeral so two runs cannot attach to one browser.mote_fleet/test/test_fake_robots.py— 15 tests holding the fixture toprotocol.pyand to the task layer's grammar. No broker, no ROS, runs in CI, so the fixture can never drift into being a second definition of the wire.m3-verification.md§2 rewritten to cite the command (with the transcript) and to record the CI decision;mote_fleet/README.mdtest tiers;docs/fleet/README.md§9;CLAUDE.mdM3 paragraph.The CI decision (recorded, not left implied)
Not a gate. It needs docker — conda-forge's mosquitto is still built without websockets, re-measured at 2.0.20,
lddfinds no libwebsockets — and a chrome. Hostedubuntu-latesthas both;ubuntu-24.04-arm, the other half of the build matrix, has no chrome, so wiring it in buys one architecture's coverage of a page with no architecture-specific behaviour, for a ~40 s job gating every PR. The flakiness objection is answered (polling, not sleeps), so it is one workflow step away if that changes. Written intom3-verification.md§2 as a choice rather than an oversight, alongside the sim smoke test's answer (#51).Verified
pixi run fleet-ui-check: 9/9 checks, 6.5 s end to end, run five times. Screenshot shows three robots on the office_world corridor, mote-03 offline via the broker's will, the degraded roll-up, and the full dispatch lifecycle in the status log.office_world,hospital_world): 9/9 each, no shared port, container or directory.fleetctlagainst the fixture:goto dropoffexit 0 (dispatched/accepted/succeeded),wibbleexit 1 ("unknown command 'wibble'"),goto nowhereexit 1 ("unknown zone 'nowhere'") — the same transcript shape as §3's real robot.pytest mote_fleet/testin the ROS-freefleetenv: 162 passed, 4 skipped (was 147+4 before the new file).pre-commit run --all-files: clean.Committed on branch
fleet-ui-check(worktree at/home/michael/.claude/jobs/856562c1/wt), not pushed.