Skip to content

feat(dc_measurements): add the Mission Measurement Open-RMF adapter - #417

Merged
Minipada merged 3 commits into
jazzyfrom
feature/391-add-the-mission-measurement-open-rmf-ada
Aug 21, 2026
Merged

feat(dc_measurements): add the Mission Measurement Open-RMF adapter#417
Minipada merged 3 commits into
jazzyfrom
feature/391-add-the-mission-measurement-open-rmf-ada

Conversation

@Minipada

Copy link
Copy Markdown
Owner

Summary

Adds mission_open_rmf (class MissionOpenRmf), the Open-RMF adapter of the Mission
Measurement: it consumes Open-RMF's TaskState stream over a plain ws:// connection
(dc_common::WebSocketJsonClient, #390) and emits mission_start/mission_end Records in
#305/#387's contract — mission_id from booking.id, mission_type from category.

Open-RMF's task model is a continuously-updated 12-value status enum rather than a flat
start/end pair; the status names and TaskState field shapes used here (booking, category,
cancellation.labels, killed.labels, dispatch.errors, unix_millis_start_time/
unix_millis_finish_time) were verified against the real rmf_api_msgs task_state.json
schema, not guessed.

Per the acceptance criteria, two judgment calls are resolved explicitly (see
MissionOpenRmfCore's doc comment and doc/src/dc/measurements/mission_open_rmf.md) rather than
silently defaulted:

  • skipped is treated as task-terminal, mapping to outcome cancelled (DC's outcome contract
    has four values, not five).
  • blocked/error are treated as transient, not terminal — the task stays open until a real
    terminal status arrives.

reason/error_code are populated best-effort from whichever field Open-RMF actually supplied
(unlike nav2's always-present error_msg), and duration_sec prefers Open-RMF's own
unix_millis_start_time/unix_millis_finish_time over locally observed timestamps when both are
present.

Note on #305: this issue lists #305 (the still-open mission-lifecycle-contract design issue)
as a blocker. #388/#389, which share that same dependency, already implemented and merged against
the same mission_start/mission_end contract, so this PR follows that established precedent
rather than waiting on #305's tracking issue to be formally closed.

Note on build verification: local disk space constraints prevented a full colcon build/colcon test run of the whole workspace in this environment. The new ROS-free
MissionOpenRmfCore logic (the actual status-mapping/outcome decisions) was independently
compiled and unit-tested (16/16 passing) with g++ against gtest directly. dc_common,
dc_lifecycle_manager, and dc_bridge all compiled successfully during the interrupted
workspace build attempts, so CI's clean-runner colcon build/colcon test is the outstanding
signal for the full plugin + integration test.

Closes #391

Test plan

  • MissionOpenRmfCore unit tests (test_mission_open_rmf_core.cpp, 16 cases) — compiled and
    run standalone with g++/gtest, all passing
  • prek run --all-files --skip build-doc — clean
  • CI: colcon build + colcon test for dc_measurements (new plugin + integration test
    test_measurement_mission_open_rmf.cpp against a mock websocket TaskState fixture)

🤖 Generated with Claude Code

https://claude.ai/code/session_01Dsswe9mDB56HKL5x9igcma

…391)

Adds MissionOpenRmf, consuming Open-RMF's TaskState stream (via #390's
WebSocketJsonClient) and emitting mission_start/mission_end Records in
called for explicitly: `skipped` is treated as task-terminal and mapped
to outcome `cancelled`; `blocked`/`error` are treated as transient, not
terminal. Status enum and TaskState field names verified against the
real rmf_api_msgs task_state.json schema.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsswe9mDB56HKL5x9igcma
Signed-off-by: David Bensoussan <d.bensoussan@proton.me>
@Minipada
Minipada force-pushed the feature/391-add-the-mission-measurement-open-rmf-ada branch from 36a1449 to bc47332 Compare August 20, 2026 22:53
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.73516% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.80%. Comparing base (8ba8a53) to head (e2ee604).

Files with missing lines Patch % Lines
...urements/plugins/measurements/mission_open_rmf.cpp 84.06% 22 Missing ⚠️
...nts/plugins/measurements/mission_open_rmf_core.hpp 77.78% 18 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            jazzy     #417      +/-   ##
==========================================
+ Coverage   70.47%   70.80%   +0.34%     
==========================================
  Files         112      114       +2     
  Lines        7221     7440     +219     
==========================================
+ Hits         5088     5267     +179     
- Misses       2133     2173      +40     
Flag Coverage Δ
cpp-jazzy 70.80% <81.74%> (+0.34%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Minipada and others added 2 commits August 21, 2026 01:09
… test

The MeasurementServer fixture's constructor creates a LifecycleNode
before rclcpp::init() had ever run, since this test file was missing
the int main() every other ROS-node test in this package has --
CI failed all 9 cases with "failed to create guard condition: context
argument is null".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsswe9mDB56HKL5x9igcma
Signed-off-by: David Bensoussan <d.bensoussan@proton.me>
PushServer (the mission_open_rmf integration test's mock websocket
server) never issues a second async_accept and never reads from the
established connection, so once the handshake completed there was no
outstanding async operation left to keep io_context::run() from
returning on its own -- its background thread exited right after the
first connection formed. send()'s asio::post() then queued onto a
dead io_context and fut.wait() blocked forever, which is what CI's
"test did not generate a result file" (killed by CTest's timeout)
actually was.

Verified with a standalone repro (PushServer + the real
WebSocketJsonClient, run under a 20s watchdog outside colcon/ctest):
hung indefinitely before this fix, completes and round-trips a
message correctly after adding the executor_work_guard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsswe9mDB56HKL5x9igcma
Signed-off-by: David Bensoussan <d.bensoussan@proton.me>
@Minipada
Minipada merged commit 0ed5a64 into jazzy Aug 21, 2026
11 checks passed
@github-actions
github-actions Bot deleted the feature/391-add-the-mission-measurement-open-rmf-ada branch August 21, 2026 00:06
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