refactor(dc_measurements): deepen the Mission adapter lifecycle and pending-record queue - #418
Merged
Merged
Conversation
…ending-record queue The four Mission Measurement adapters (nav2 NavigateToPose/NavigateThroughPoses/ FollowWaypoints, Open-RMF) converge on one ADR-0010 Record shape but each duplicated the outcome vocabulary, UUID formatting, JSON record building, and bounded id bookkeeping. Extract the genuinely shared pieces into small, single-purpose modules and delegate to them: - dc_measurements/mission_outcome.hpp: one shared MissionOutcome enum + missionOutcomeName() + MissionStartFact, replacing four duplicated copies. - dc_measurements/mission_registry.hpp: PrunedMissionMap<Active>, the bounded id -> state bookkeeping (oldest-finished-first eviction, sequence counter) MissionNav2ThroughPosesCore and MissionOpenRmfCore had each reimplemented. - dc_measurements/mission_record_json.hpp: shared missionStartJson()/ missionEndJsonBase() builders, replacing MissionNav2/MissionNav2FollowWaypoints' static methods and the inline JSON blocks in the other two adapters. - dc_measurements/mission_uuid.hpp: the UUID formatter duplicated between MissionNav2 and MissionNav2FollowWaypoints. MissionNav2ThroughPoses' distinct (non-dashed) mission_id format is kept as a separate function rather than unified -- collapsing the two would change an already-shipped adapter's mission_id format for anyone already querying on it. - dc_measurements/pending_record_queue.hpp: the capped deque + drop-oldest + throttled-warning pattern duplicated across all four Mission adapters plus Fault and Ros2ControlStatus (six call sites total). Also fixes a real correctness drift the duplication had let through: MissionNav2ThroughPoses' status subscription was on plain QoS(10) while its two siblings use reliable().transient_local() for late-joiner correctness; it now matches. Deliberately not merged: MissionNav2Tracker/MissionFollowWaypointsTracker's state-machine internals -- once the above is factored out, what differs between them is each endMission()'s extra parameter (recoveries vs missed_waypoints), a small enough remainder that a shared base would add indirection for little gain. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VoPZP5DPoJuuCWtctZAfBe Signed-off-by: David Bensoussan <d.bensoussan@proton.me>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## jazzy #418 +/- ##
==========================================
- Coverage 70.80% 70.60% -0.19%
==========================================
Files 114 119 +5
Lines 7440 7363 -77
==========================================
- Hits 5267 5198 -69
+ Misses 2173 2165 -8
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… loader-backed $ref
The four Mission Measurement schemas (mission_nav2.json, mission_nav2_through_poses.json,
mission_nav2_follow_waypoints.json, mission_open_rmf.json) duplicated ~90% of their
property definitions -- the schema-level mirror of the C++ duplication the prior commit
addressed. Extract the shared property definitions (event, mission_id, sequence, outcome,
reason, error_code, duration_sec) into mission_base.json; each adapter schema now
allOf/$refs it and adds only its own mission_type/extra-property/required/conditional
rules on top. Verified against a real nlohmann_json_schema_validator that every
before/after pair of 21 representative Records (valid and invalid) validates identically.
Cross-file $ref needs a loader callback -- nlohmann_json_schema_validator's default
json_validator has none, and every existing schema in this codebase kept to same-file
"#/$defs/..." refs, which explains why this was never needed before. Without one,
set_root_schema()/validate() throws "external schema reference ... needs loading, but no
loader callback given" -- confirmed by hand against the real library before writing any
schema. Added makeSchemaFileLoader() to dc_measurements/measurement.hpp, resolving a $ref
against the directory the root schema was itself loaded from, and wired it into both
Measurement::validateSchema() overloads.
Four test files (test_measurement_mission_nav2{,_follow_waypoints,_through_poses}.cpp,
test_measurement_mission_open_rmf.cpp) each independently re-validate emitted Records
against a second, locally-constructed json_validator as a self-check; each needed the same
loader wired in, or that construction throws the same way production would have without
this commit's measurement.hpp fix.
Full colcon build + colcon test of dc_measurements (293 tests) verified green end to end
against a container image with the real ROS 2 Jazzy toolchain -- this and the prior commit
together are the first real compile/test run either has had.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoPZP5DPoJuuCWtctZAfBe
Signed-off-by: David Bensoussan <d.bensoussan@proton.me>
CI's Format check flagged these files as unformatted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJktRnyZZSEDnp16Cr2crJ Signed-off-by: David Bensoussan <d.bensoussan@proton.me>
github-actions
Bot
deleted the
refactor/mission-measurement-shared-modules
branch
August 21, 2026 15:56
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.
Summary
Architecture-review-driven refactor of
dc_measurements' Mission Measurement adapter family (nav2 NavigateToPose/NavigateThroughPoses/FollowWaypoints, Open-RMF) plusFault/Ros2ControlStatus— the hottest area of the repo by recent commit volume. All three review candidates are implemented.1. Mission adapter lifecycle boilerplate
The four Mission adapters converge on one ADR-0010 Record shape but each duplicated the outcome vocabulary, UUID formatting, JSON record building, and bounded-id bookkeeping. Extracted into small, single-purpose modules under
dc_measurements/include/dc_measurements/:mission_outcome.hpp— one sharedMissionOutcomeenum +missionOutcomeName()+MissionStartFact, replacing four duplicated copies.mission_registry.hpp—PrunedMissionMap<Active>, the bounded id → state bookkeeping (oldest-finished-first eviction, sequence counter)MissionNav2ThroughPosesCoreandMissionOpenRmfCorehad each reimplemented identically.mission_record_json.hpp— sharedmissionStartJson()/missionEndJsonBase()builders, replacingMissionNav2/MissionNav2FollowWaypoints' static methods and the inline JSON blocks in the other two adapters.mission_uuid.hpp— the UUID formatter duplicated betweenMissionNav2andMissionNav2FollowWaypoints.MissionNav2ThroughPoses' distinct (non-dashed)mission_idformat is kept as a separate function rather than unified, since collapsing the two would silently change an already-shipped adapter'smission_idformat.Bug fix riding along:
MissionNav2ThroughPoses' status subscription was on plainQoS(10)while its two siblings usereliable().transient_local()for late-joiner correctness. It now matches — this drift was direct evidence the duplication was letting real bugs through.Deliberately not done: merging
MissionNav2Tracker/MissionFollowWaypointsTracker's state-machine internals. Once the above is factored out, what differs between them is eachendMission()'s extra parameter (recoveriesvsmissed_waypoints) — a small enough remainder that a shared base would add indirection for little gain.2. Pending-record queue
pending_record_queue.hpp— the capped deque + drop-oldest + throttled-warning pattern duplicated across all four Mission adapters plusFaultandRos2ControlStatus(six call sites).3. Shared Mission Record JSON Schema
The four
mission_*.jsonschemas duplicated ~90% of their property definitions — the schema-level mirror of the C++ duplication above.mission_base.jsonnow holds the shared property definitions (event, mission_id, sequence, outcome, reason, error_code, duration_sec); each adapter schemaallOf/$refs it and adds only its ownmission_type/extra-property/required/conditional rules.Cross-file
$refneeds a loader callback thatnlohmann_json_schema_validator's defaultjson_validatordoesn't have (every existing schema in this codebase kept to same-file#/$defs/...refs, which is why this was never needed before — confirmed against the real library: without a loader,set_root_schema()/validate()throws"external schema reference ... needs loading, but no loader callback given"). AddedmakeSchemaFileLoader()tomeasurement.hpp, wired into bothMeasurement::validateSchema()overloads. Four test files each independently re-validate emitted Records via their own locally-constructedjson_validatoras a self-check; each needed the same loader wired in.Verification
Public class names, method signatures, and Record JSON shapes are unchanged (aside from the QoS fix above and the schema restructuring, which is validation-semantics-preserving — see below).
This was built and tested for real against a container image with the actual ROS 2 Jazzy toolchain (not just reviewed by hand):
colcon build --packages-up-to dc_measurements: clean, zero errors, under-Wall -Wextra -Wpedantic -Werror -Wdeprecated.colcon test --packages-select dc_measurements: 293 tests, 0 errors, 0 failures, 0 skipped.mission_base.jsonextraction, run directly againstnlohmann_json_schema_validator.Test plan
colcon build(dc_measurements) — verified in CI-equivalent containercolcon test— 293/293 passing, including all Mission/Fault/Ros2ControlStatus testsprek run --all-files(clang-format / lint) — not run locally (noclang-formatbinary in this environment); please run in CI🤖 Generated with Claude Code
https://claude.ai/code/session_01VoPZP5DPoJuuCWtctZAfBe