Summary
The per-package loops in rust-stable.yml, rust-minimal.yml and rust-win.yml select packages with awk '$3 == "(ament_cargo)"', but colcon list prints (ros.ament_cargo). The loops match nothing, so the fmt --check, clippy -D warnings, cargo test and rustdoc -D warnings steps report success while processing zero packages.
The selector has read (ament_cargo) in every revision of rust-stable.yml and rust-minimal.yml since 2024-11-15 (b4e975cd), and in rust-win.yml since it was added on 2025-06-03 (205b84be). CI has installed colcon-ros-cargo from unpinned git main throughout. colcon-ros-cargo #32 changed the type string on 2024-12-06, so with those two facts together the steps have selected zero packages since then.
The problem is the false green, not the diagnostics behind it. PRs merged with these workflows received passing lint, test and doc checks that had not run.
Why the string changed
colcon_ros/package_identification/ros.py sets desc.type = f'ros.{build_type}'. colcon-ros-cargo #32 removed its own identification extension and re-keyed its task entry points from ament_cargo to ros.ament_cargo. CI installs colcon-ros-cargo from git main (rust-stable.yml:83), so it runs the post-#32 code.
Evidence
Measured in a container matching the humble leg (ros:humble, colcon-ros-cargo at dc26ba5f), with the repo and every ros2_rust_humble.repos entry checked out:
$ colcon list
rclrs src/ros2_rust/rclrs (ros.ament_cargo)
(ament_cargo) appears on 0 lines. Same result with and without colcon-ros-cargo installed, since the type string comes from colcon_ros.
In the CI logs, the loop body's own echo "Running clippy in $path" never appears as runtime output. In run 33553913917 (main, 2026-09-01) and run 27496259196 (main, 2026-06-14), each of the humble, jazzy and kilted legs shows Running clippy in, Running cargo test in and Running rustdoc check in exactly once, inside the step's own script listing, and never again. As a positive control the same legs print 107, 114 and 118 runtime Compiling lines. (The rolling leg is continue-on-error and did not reach these steps in either run.)
Affected lines: rust-stable.yml:95,114,130,146, rust-minimal.yml:95,114,130,146, rust-win.yml:79. The same stale literal is in rust-win.yml; I have not run the Windows leg myself.
The staleness is also user-facing in docs/building.md:110-116, which tells a reader that seeing
rclrs src/ros2_rust/rclrs (ament_cargo)
means "the colcon-ros-cargo plugin works as expected". Someone following that today sees (ros.ament_cargo) and has reason to think their setup is broken when it is correct.
What turning them back on surfaces
Running the workflow's commands verbatim, including the per-package feature branches and the three package exclusions, in a fully built workspace on that container:
| step |
packages |
red |
| clippy |
9 |
4 |
| cargo test |
6 |
1 |
| rustdoc |
6 |
1 |
I did not run the fmt step (it needs the nightly toolchain).
Nearly all of it is style debt on rclrs. One item is worth a decision rather than a fix: clippy::let_underscore_future fires on six let _ = ... sites, four of them calls to ExecutorCommands::run, whose docstring tells callers to do exactly that ("You can safely discard the promise ... Use let _ = promise; to suppress the warning"). The returned Promise is a oneshot receiver for a task that run has already queued, so the lint is not reporting a dropped task, but -D warnings will reject the documented pattern. Either the docstring should suggest a different spelling or the lint needs an allow with that explanation.
One red I am not claiming: cargo test on rosidl_runtime_rs fails to link its test binary with cannot find -lrosidl_runtime_c. That may well be my container rather than the project, and CI is the place to find out.
Full diagnostic inventory (rclrs, Rust 1.85.0)
clippy, 137 diagnostics across 32 lint kinds on rclrs: 23 elidable lifetimes ('msg), 20 very-complex-type, 15 useless conversion, 14 needless deref, 11 needless borrow, 5 redundant pattern matching, 5 let_underscore_future (2 of them in test modules), 4 unit let-binding, 4 elidable lifetimes ('a), 4 doc list indentation, and 22 kinds with one or two hits each (among them two unannotated transmutes, an unsafe fn without a # Safety section, and a 9-argument function). Three other packages carry one clippy lint each (unwrap_or constructing a default, an unnecessary raw-pointer cast, and the sixth let_underscore_future in examples/rclrs/rust_pubsub).
let_underscore_future sites:
rclrs/src/action/action_server.rs:376 let _ = self.board.node.commands().run(f);
rclrs/src/action/action_server.rs:425
rclrs/src/node/node_options.rs:410
rclrs/src/subscription.rs:588 (test module)
rclrs/src/worker.rs:820 (test module)
examples/rclrs/rust_pubsub/src/simple_subscriber.rs:36
rustdoc, 8 errors on rclrs: unresolved intra-doc links (crate::spin, crate::Node::create_action_client, NodeState::create_action_server, NodeState::create_action_goal_receiver) and public docs for begin / begin_cancelling linking to the private item CancellingGoal.
CI uses dtolnay/rust-toolchain@stable, so today's stable will report a different, probably larger, set than 1.85.0 does.
Proposed next step
I can open a PR that updates the nine selectors and the docs/building.md example. Because that will expose the failures above, I am raising it here first so you can decide whether the revived steps should start blocking or continue-on-error. Happy to take any part of the cleanup that would be useful.
Environment: ros:humble on arm64, Rust 1.85.0 (the version this repo's Dockerfile pins), clippy 0.1.85.
Assisted-by: Claude Code:claude-fable-5-1
Summary
The per-package loops in
rust-stable.yml,rust-minimal.ymlandrust-win.ymlselect packages withawk '$3 == "(ament_cargo)"', butcolcon listprints(ros.ament_cargo). The loops match nothing, so thefmt --check,clippy -D warnings,cargo testandrustdoc -D warningssteps report success while processing zero packages.The selector has read
(ament_cargo)in every revision ofrust-stable.ymlandrust-minimal.ymlsince 2024-11-15 (b4e975cd), and inrust-win.ymlsince it was added on 2025-06-03 (205b84be). CI has installed colcon-ros-cargo from unpinned gitmainthroughout. colcon-ros-cargo #32 changed the type string on 2024-12-06, so with those two facts together the steps have selected zero packages since then.The problem is the false green, not the diagnostics behind it. PRs merged with these workflows received passing lint, test and doc checks that had not run.
Why the string changed
colcon_ros/package_identification/ros.pysetsdesc.type = f'ros.{build_type}'. colcon-ros-cargo #32 removed its own identification extension and re-keyed its task entry points fromament_cargotoros.ament_cargo. CI installs colcon-ros-cargo from gitmain(rust-stable.yml:83), so it runs the post-#32 code.Evidence
Measured in a container matching the humble leg (
ros:humble, colcon-ros-cargo atdc26ba5f), with the repo and everyros2_rust_humble.reposentry checked out:(ament_cargo)appears on 0 lines. Same result with and without colcon-ros-cargo installed, since the type string comes fromcolcon_ros.In the CI logs, the loop body's own
echo "Running clippy in $path"never appears as runtime output. In run 33553913917 (main, 2026-09-01) and run 27496259196 (main, 2026-06-14), each of the humble, jazzy and kilted legs showsRunning clippy in,Running cargo test inandRunning rustdoc check inexactly once, inside the step's own script listing, and never again. As a positive control the same legs print 107, 114 and 118 runtimeCompilinglines. (The rolling leg iscontinue-on-errorand did not reach these steps in either run.)Affected lines:
rust-stable.yml:95,114,130,146,rust-minimal.yml:95,114,130,146,rust-win.yml:79. The same stale literal is inrust-win.yml; I have not run the Windows leg myself.The staleness is also user-facing in
docs/building.md:110-116, which tells a reader that seeingmeans "the
colcon-ros-cargoplugin works as expected". Someone following that today sees(ros.ament_cargo)and has reason to think their setup is broken when it is correct.What turning them back on surfaces
Running the workflow's commands verbatim, including the per-package feature branches and the three package exclusions, in a fully built workspace on that container:
I did not run the
fmtstep (it needs the nightly toolchain).Nearly all of it is style debt on
rclrs. One item is worth a decision rather than a fix:clippy::let_underscore_futurefires on sixlet _ = ...sites, four of them calls toExecutorCommands::run, whose docstring tells callers to do exactly that ("You can safely discard the promise ... Uselet _ = promise;to suppress the warning"). The returnedPromiseis a oneshot receiver for a task thatrunhas already queued, so the lint is not reporting a dropped task, but-D warningswill reject the documented pattern. Either the docstring should suggest a different spelling or the lint needs anallowwith that explanation.One red I am not claiming:
cargo testonrosidl_runtime_rsfails to link its test binary withcannot find -lrosidl_runtime_c. That may well be my container rather than the project, and CI is the place to find out.Full diagnostic inventory (rclrs, Rust 1.85.0)
clippy, 137 diagnostics across 32 lint kinds on
rclrs: 23 elidable lifetimes ('msg), 20 very-complex-type, 15 useless conversion, 14 needless deref, 11 needless borrow, 5 redundant pattern matching, 5let_underscore_future(2 of them in test modules), 4 unit let-binding, 4 elidable lifetimes ('a), 4 doc list indentation, and 22 kinds with one or two hits each (among them two unannotatedtransmutes, anunsafe fnwithout a# Safetysection, and a 9-argument function). Three other packages carry one clippy lint each (unwrap_orconstructing a default, an unnecessary raw-pointer cast, and the sixthlet_underscore_futureinexamples/rclrs/rust_pubsub).let_underscore_futuresites:rustdoc, 8 errors on
rclrs: unresolved intra-doc links (crate::spin,crate::Node::create_action_client,NodeState::create_action_server,NodeState::create_action_goal_receiver) and public docs forbegin/begin_cancellinglinking to the private itemCancellingGoal.CI uses
dtolnay/rust-toolchain@stable, so today's stable will report a different, probably larger, set than 1.85.0 does.Proposed next step
I can open a PR that updates the nine selectors and the
docs/building.mdexample. Because that will expose the failures above, I am raising it here first so you can decide whether the revived steps should start blocking orcontinue-on-error. Happy to take any part of the cleanup that would be useful.Environment:
ros:humbleon arm64, Rust 1.85.0 (the version this repo'sDockerfilepins), clippy 0.1.85.Assisted-by: Claude Code:claude-fable-5-1