SQA Clients
rclpy clients submit orders, actions, faults, stop commands, concurrent work, and bounded deadlines.
Distributed ROS 2 / fleet orchestration / SQA
A deliberately testable warehouse-control POC for four AGVs, 24 SKU cases, two picker/palletizing stations, rack storage, traffic lanes, chargers, conveyors, and pallets. The engineering focus is the hard space between request and result: concurrency, uncertain outcomes, delivery semantics, recovery, observability, and fleet behavior.
Engineering brief
The visible Gazebo cell sits on top of a deterministic Python plant, a public ROS 2 contract, Fast DDS communication, and an optional SQLite checkpoint and event outbox. The suite treats a timeout as an uncertain outcome, duplicate delivery as a consumer-design problem, and concurrent order handling as an invariant problem rather than a happy-path API check.
Recorded qualification run
The recording pairs the live cell with the 105-case qualification collection. Tests drive ROS state, services, actions, faults, and process boundaries while Gazebo mirrors authoritative domain poses. The visual scene makes behavior inspectable; ROS state, events, responses, durable rows, timing, and process evidence decide the result.
System under test
rclpy clients submit orders, actions, faults, stop commands, concurrent work, and bounded deadlines.
Topics, services, an action, QoS profiles, callback groups, asynchronous futures, and isolated domains.
A four-thread executor adapts the deterministic engine for dispatch, A* routing, inventory, faults, and pallet flow.
Checkpoint/outbox state feeds snapshots, live events, metrics, diagnostics, Gazebo, and the health gateway.
Source of truth: the ROS-adapted domain engine, not rendered pixels.
Persistence boundary: one opt-in SQLite writer, not a replicated database.
Isolation: deterministic seeds, unique ROS domains, Gazebo partitions, and owned process groups.
Qualification strategy
WH-NETEM-001
Fast DDS is forced onto UDPv4 so shared memory cannot bypass Linux
tc netem. A 180 ms one-way delay measured 0.374 seconds
round trip; a 300 ms delay created a committed-but-unknown outcome;
100% packet loss isolated the request until the link healed.
WH-DIST / WH-NET
Stable request IDs and content fingerprints distinguish first-time acceptance, an equivalent replay, and conflicting reuse. Tests abandon or delay successful responses, reconcile authoritative state, retry, and require one reservation and one order effect.
WH-OUTBOX-CRASH-001
A failpoint kills the controller after DDS publication but before the SQLite outbox row is marked. The same event ID arrives twice after restore, while the consumer's atomic claim applies it once and the warehouse records one durable completion.
WH-TXN / WH-ROUTE
Two ROS clients are released together against scarce inventory. One wins, one receives a clean rejection, and no partial reservation or lost update survives. Surge scenarios also require bounded completion without collision, deadlock, or starvation of useful work.
WH-PAUSE / WH-RESTART
SIGSTOP freezes a live controller until independent
diagnostics report stale state, then coherent progress resumes.
A separate mid-order SIGKILL restores the same run,
revision, ownership, and work from SQLite and completes once.
WH-STREAM / WH-QOS / WH-GZ
Retained state serves late joiners while volatile events preserve live transition context through event, correlation, causation, run, and revision IDs. Separate checks reconcile event chains to state and verify stopped AGV poses converge into Gazebo.
Fleet scalability
The same deterministic surge workload -- three orders, 12 cases, and two picker docks -- ran five repeatability executions at each fleet size. Moving from one AGV to two reduced logical cycle time by 46.559%. Moving from two to four improved it by only 0.431%, showing that picker and dock capacity, not transport, had become the limiting resource.
These are deterministic model characterizations, not independent statistical samples or a physical warehouse capacity claim.
Deployment, observability, and evidence
A non-root ROS image, single-replica Recreate Deployment,
ClusterIP Service, PVC-backed SQLite state, and same-Pod health
gateway define a bounded controller-recovery topology without Gazebo.
The opt-in kind workflow records Pod UID, run ID, revision, and an active durable order; deletes the Pod; then requires a new UID, restored readiness, non-regressing revision, and retained work.
Static manifest and health-gateway checks executed successfully.
The Pod-restart run could not create a cluster on this host because
kind/kubectl and Docker access were unavailable,
so the tooling emitted a JIRA-ready prerequisite report instead of
implying runtime success.
An automated GDB scenario captures thread inventory, loaded libraries,
locals where available, and thread apply all bt full. The
retained 744-line stack traces rcl_wait through rclpy and
CPython alongside RMW/Fast DDS worker threads.
Versioned metrics, diagnostics, structured events, ROS/Gazebo logs,
health/readiness endpoints, process backtraces, core-dump guidance,
pdb, faulthandler, bags, and tracing support triage from
application state down to native waits.
Colcon-aware runners produce JUnit XML, machine-readable JSON, reviewer-friendly Markdown, raw evidence attachments, and bounded JIRA drafts with environment, reproduction command, expected result, actual result, and failure detail.
Reviewable evidence
The qualification report is the quickest read. The network JSON and full GDB stack provide raw scenario evidence; the master guide, test plan, architecture, and reporting guide show how the suite was designed.
Scope discipline