Skip to content

M4.5 Gate Review

Gate review for M4.5 (docs/17), run 2026-09-27 as make m45-gate on the host, after slices 4.5a–4.5f. Every claim is made through fjarr-connect, the product, with the client relay-only and the direct path between the containers removed — the lab’s stand-in for a robot behind carrier NAT. One criterion was amended out rather than met, and the reason is below.

Promise (docs/06, docs/17)VerdictEvidence
a link up in under 3 s, and ssh logs inmet0.1 s direct, 1.6 s relay-only (TURN allocation included); tunnel-ssh-connect
a hash-verified 1 GB scp to a robot behind carrier NATmettunnel-scp-connect, 5 of 5 over TURN at 268–304 Mbps; the gate asserts that no host candidate was offered, so a pass cannot be the docker bridge
ros2 topic list with Fast DDS unconfiguredmet — after a fixtunnel-ros-connect: list and echo over the relay. It failed first; finding 1
ros2 topic list with the documented Cyclone fileamended out, then met the same day — 22 of 22 through fjarr-connect; the 4.5d failure was the check racing the ROS 2 daemon, and #28’s MTU. Its original evidence follows#29: the file fixes Cyclone’s hang, but discovery does not complete across the link. 4.5d measured that as a ROS 2 integration question, not a tunnel one, so docs/06 and docs/17 now state it as #29 where the criterion is stated
login through the dashboard, then list, pick and connect with nobody typing a robot id; the same with no browsermettunnel-login (4.5f), in CI; the code shape end to end, the loopback shape in halves (docs/15)
a second robot attached at once is unreachable from the first, in both directionsmettunnel-isolation, with a route forced into each robot’s tunnel before a negative is believed
the agent upgraded without the robot’s ROS stack restartingmettunnel-ros-ordering — facts A, B and C, nightly in CI
every open and close audit-loggedmettunnel-login correlates session.started (naming fjarr.net) with its session.ended by session_id
#SeverityFindingResolution
1highfjarr-connect dropped multicast. The pump chose a link by destination, and DDS discovery is addressed to a group, so ROS 2 had never worked through the product — only through opsim, whose single-link pump forwards everything. ADR-0026 had admitted multicast at the policy layer; the routing layer above it had not heardthe pump fans multicast out to every link, from the operator only, never link to link; route_for is a pure function with a test
2mediumfjarr-connect -- <cmd> exited 0 whatever the command did, so a failed check read green — which is how the ROS gate reported PASS on its first run while printing that the topic was missingthe command’s exit status is the CLI’s, once the links are down. The gate fixture already keyed its verdict on that exit code — it was right and the client under it was not
3mediumtun-up ROS=1 created the robot’s ROS participant before the agent had attached, so the participant never saw the tunnel — docs/27’s fact A, violated by the lab that tests itthe participant is created last
4mediuma docker compose up from inside dev hands the host daemon /workspace as the bind source, and every recreated service came up with an empty workspacerecreating targets run on the host and m45-gate refuses to run in dev; CLAUDE.md and docs/12

Findings 1 and 2 are the pattern this milestone kept teaching: the second implementation of a rule (opsim’s pump, then the client’s) is where the rule goes missing, and a check whose failure cannot reach the verdict passes.

  • #28 — a usrsctp-to-usrsctp association wedges under load with video beside it. The failing operator is the lab’s opsim; neither real operator is usrsctp, and the gate’s scp claim is made through fjarr-connect. Next: read both ends of a wedged association.
  • #29 — Cyclone DDS — closed the same day; see docs/27#ros2.
  • #31 — whether a view-only session should take the input lease.
  • macOS is written and type-checked in CI, and has never run on macOS hardware (docs/04).