From 0a2c746501f7d77d02efb8ad27a9664495f4ccd7 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 26 May 2026 13:47:20 +0200 Subject: [PATCH 1/7] ci: swap Rolling for Lyrical Luth (Ubuntu 26.04) across matrix and docs ROS 2 Lyrical Luth is the new LTS released May 2026, supported until May 2031, targeting Ubuntu 26.04 Resolute Raccoon (Python 3.14, gcc 15, rclcpp 32). Drop the Rolling matrix entry in favour of Lyrical so all three tested distros are LTS. CI matrix: rolling/noble -> lyrical/resolute in ci.yml, docker-publish.yml, opcua-plugin.yml. Jazzy/noble and Humble/jammy entries unchanged. ROS2MedkitCompat.cmake docstrings extended to cover Lyrical (rclcpp 32+, yaml_cpp_vendor target export, ament_target_dependencies removal in ament_cmake 2.8.5+). Runtime detection already handles the new distro; no logic change needed. Docs (README, CONTRIBUTING, QUALITY_DECLARATION, installation, troubleshooting, tutorials, copilot-instructions, cmake/gateway design docs) updated with correct Ubuntu codename pairings (Resolute=26.04, Noble=24.04, Jammy=22.04). C++ comments and source comments swapped Rolling -> Lyrical where the behaviour carries forward; historical attribution preserved as "on Lyrical (originally observed on Rolling)" or "Rolling/Lyrical" where the bug was first reproduced on Rolling. snapshot_capture.cpp C++20 aggregate-init comment updated for gcc 15 (Lyrical). closes #404 --- .github/copilot-instructions.md | 4 +-- .github/workflows/ci.yml | 24 ++++++++++-------- .github/workflows/docker-publish.yml | 2 +- .github/workflows/opcua-plugin.yml | 10 ++++---- CONTRIBUTING.md | 2 +- QUALITY_DECLARATION.md | 8 +++--- README.md | 8 +++--- docs/installation.rst | 16 ++++++------ docs/troubleshooting.rst | 2 +- docs/tutorials/docker.rst | 4 +-- docs/tutorials/plugin-system.rst | 2 +- scripts/check_no_naked_subscriptions.sh | 3 ++- src/ros2_medkit_cmake/README.md | 4 +-- .../cmake/ROS2MedkitCompat.cmake | 25 +++++++++++-------- src/ros2_medkit_cmake/design/index.rst | 4 +-- .../ros2_medkit_beacon_common/CMakeLists.txt | 6 ++--- .../ros2_medkit_param_beacon/CMakeLists.txt | 6 ++--- .../src/param_beacon_plugin.cpp | 11 ++++---- .../ros2_medkit_topic_beacon/CMakeLists.txt | 6 ++--- .../src/topic_beacon_plugin.cpp | 13 +++++----- .../src/snapshot_capture.cpp | 4 +-- src/ros2_medkit_gateway/CMakeLists.txt | 2 +- src/ros2_medkit_gateway/README.md | 2 +- .../design/ros2_subscription_architecture.rst | 13 +++++----- .../compat/generic_client_compat.hpp | 2 +- .../ros2_subscription_executor.hpp | 2 +- src/ros2_medkit_gateway/src/main.cpp | 4 +-- .../test_openapi_response_drift.test.py | 6 ++--- .../ros2_medkit_graph_provider/CMakeLists.txt | 6 ++--- .../src/graph_provider_plugin.cpp | 14 +++++------ .../ros2_medkit_opcua/CMakeLists.txt | 6 ++--- .../ros2_medkit_opcua/src/opcua_client.cpp | 2 +- .../CMakeLists.txt | 6 ++--- src/ros2_medkit_serialization/CMakeLists.txt | 2 +- 34 files changed, 121 insertions(+), 110 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0202ae4ab..f652b8385 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,7 +4,7 @@ **ros2_medkit** is a ROS 2 diagnostics gateway that exposes ROS 2 system information via a RESTful HTTP API aligned with the **SOVD (Service-Oriented Vehicle Diagnostics)** specification. It models robots as a diagnostic entity tree: **Area -> Component -> App**, with optional **Function** groupings. -**Tech Stack**: C++17, ROS 2 Jazzy/Humble/Rolling, Ubuntu 24.04/22.04 +**Tech Stack**: C++17, ROS 2 Jazzy/Humble/Lyrical Luth, Ubuntu 26.04/24.04/22.04 ## Package Structure @@ -294,7 +294,7 @@ Every code change must include corresponding tests. A feature without tests is n - **Flag** new `.cpp` source files under `src/core/` that aren't picked up by `gateway_core`'s `GLOB_RECURSE` source list, or new ROS-adapter `.cpp` files that aren't added to the `gateway_ros2` STATIC library target in CMakeLists.txt. - **Flag** any `#include ` or message-package include in a file under `core/` - the layer must stay middleware-neutral. The `gateway_core_purity` linter and `test_gateway_core_smoke` link test enforce this; do not paper over their failures. - **Flag** new test targets that don't link to `gateway_ros2` (the default), unless the test is intentionally a core-only smoke test linking `gateway_core` directly. -- **Flag** use of `ament_target_dependencies()` - use `medkit_target_dependencies()` instead (removed in Rolling). +- **Flag** use of `ament_target_dependencies()` - use `medkit_target_dependencies()` instead (deprecated in Kilted, removed in ament_cmake 2.8.5+ which Lyrical ships). - **Flag** direct `find_package(yaml-cpp)` or `find_package(httplib)` - use `medkit_find_yaml_cpp()` / `medkit_find_cpp_httplib()` for multi-distro compatibility. ### Documentation diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a34a9c34..ec26d7288 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,8 @@ jobs: include: - ros_distro: humble os_image: ubuntu:jammy - - ros_distro: rolling - os_image: ubuntu:noble + - ros_distro: lyrical + os_image: ubuntu:resolute container: image: ${{ matrix.os_image }} timeout-minutes: 60 @@ -58,11 +58,12 @@ jobs: fi source /opt/ros/${{ matrix.ros_distro }}/setup.bash rosdep update - # Linters (clang-tidy / clang-format) are gated to the Jazzy lint job - # in quality.yml, but multiple package.xml files still list them as - # . Their rosdep keys are not registered for noble - # (Rolling), which breaks rosdep install on that runner. Skip them - # on every distro this workflow targets - the linters never run here. + # Linters (clang-tidy / clang-format) only run in the Jazzy quality + # job (quality.yml). Multiple package.xml files still list them as + # , so we skip the rosdep keys here to keep build-and- + # test runners from pulling in linter packages they never use. Also + # defensive against transient binary-deb gaps on newly-released + # distros. rosdep install --from-paths src --ignore-src -y \ --skip-keys "ament_cmake_clang_tidy ament_cmake_clang_format" @@ -85,10 +86,11 @@ jobs: # FastRTPS 2.6 on Humble has a known use-after-free in the # discovery-teardown path (EDP::unpairWriterProxy) that segfaults # peer nodes when the gateway shuts down, so we force CycloneDDS - # there. Rolling + Jazzy ship a newer FastRTPS without that bug - # and hit a separate iceoryx-shared-memory crash under CycloneDDS - # during shutdown ("string capacity was zero for allocated data"), - # so on those distros we keep the default FastRTPS. + # there. Lyrical ships a newer FastRTPS without that bug and hits + # a separate iceoryx-shared-memory crash under CycloneDDS during + # shutdown ("string capacity was zero for allocated data"), so on + # Lyrical we keep the default FastRTPS. (Jazzy still uses + # CycloneDDS - see jazzy-test job below for its rationale.) RMW_IMPLEMENTATION: ${{ matrix.ros_distro == 'humble' && 'rmw_cyclonedds_cpp' || '' }} run: | source /opt/ros/${{ matrix.ros_distro }}/setup.bash diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 8587fa301..8743b44d1 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - ros_distro: [jazzy, humble, rolling] + ros_distro: [jazzy, humble, lyrical] steps: - name: Checkout repository diff --git a/.github/workflows/opcua-plugin.yml b/.github/workflows/opcua-plugin.yml index 9c321ad99..bfaf13990 100644 --- a/.github/workflows/opcua-plugin.yml +++ b/.github/workflows/opcua-plugin.yml @@ -43,9 +43,9 @@ jobs: os_image: ubuntu:jammy - ros_distro: jazzy os_image: ubuntu:noble - - ros_distro: rolling - os_image: ubuntu:noble - continue-on-error: ${{ matrix.ros_distro == 'rolling' }} + - ros_distro: lyrical + os_image: ubuntu:resolute + continue-on-error: ${{ matrix.ros_distro == 'lyrical' }} container: image: ${{ matrix.os_image }} timeout-minutes: 60 @@ -84,8 +84,8 @@ jobs: source /opt/ros/${{ matrix.ros_distro }}/setup.bash rosdep update # Skip nav2_msgs (vda5050_agent declares it; not available on all - # distros) and the linter rosdep keys. The clang_format / clang_tidy - # keys are not registered for noble (Rolling), and the upstream + # distros) and the linter rosdep keys. Linters only run in the Jazzy + # quality job, so we don't need them installed here. The upstream # medkit packages have already been switched to QUIET + FOUND for # those find_package calls so the build degrades gracefully without # the linter packages installed. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad6b2093b..4df3f251c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,7 +107,7 @@ Open `coverage_html/index.html` in your browser. #### CI/CD -All PRs are tested on Ubuntu 24.04 (Jazzy) with parallel lint + test jobs, plus Humble and Rolling (allowed to fail). Coverage is uploaded to Codecov on push to main. All CI jobs use ccache. +All PRs are tested on Ubuntu 24.04 (Jazzy) with parallel lint + test jobs, plus Humble and Lyrical Luth. Coverage is uploaded to Codecov on push to main. All CI jobs use ccache. ### Pull Request Checklist diff --git a/QUALITY_DECLARATION.md b/QUALITY_DECLARATION.md index 6b276e7cb..558ff4e64 100644 --- a/QUALITY_DECLARATION.md +++ b/QUALITY_DECLARATION.md @@ -86,7 +86,7 @@ GitHub Copilot code review is used in addition to human review. All pull requests must pass CI before merging: -- **Build & Test job:** Full build + unit/integration tests on Ubuntu Noble / ROS 2 Jazzy, Ubuntu Jammy / ROS 2 Humble, and Ubuntu Noble / ROS 2 Rolling (best-effort, allow-failure). Linter tests on Jazzy only +- **Build & Test job:** Full build + unit/integration tests on Ubuntu Noble / ROS 2 Jazzy, Ubuntu Jammy / ROS 2 Humble, and Ubuntu Resolute / ROS 2 Lyrical Luth. Linter tests on Jazzy only - **Coverage job:** Debug build with coverage. Reports are generated for all PRs as artifacts and uploaded to [Codecov](https://codecov.io/gh/selfpatch/ros2_medkit) on pushes to `main` - Linting enforced: `clang-format`, `clang-tidy` via `ament_lint_auto` @@ -203,9 +203,9 @@ Linter tests are enforced in CI on every pull request. - **Ubuntu 24.04 (Noble)** with **ROS 2 Jazzy** (primary) - **Ubuntu 22.04 (Jammy)** with **ROS 2 Humble** -- **Ubuntu 24.04 (Noble)** with **ROS 2 Rolling** (experimental, best-effort) +- **Ubuntu 26.04 (Resolute Raccoon)** with **ROS 2 Lyrical Luth** (newest LTS, released May 2026) -Jazzy and Humble are the Tier 1 platforms per [REP-2000](https://www.ros.org/reps/rep-2000.html) and are tested in CI. Rolling is tested as best-effort (allow-failure) for forward-compatibility. +Jazzy and Humble are Tier 1 LTS platforms per [REP-2000](https://www.ros.org/reps/rep-2000.html); Lyrical Luth is the newest LTS (May 2026) and is also tested in CI. --- @@ -234,7 +234,7 @@ Security issues can be reported via GitHub Security Advisories on the | Feature tests | Met | 65 tests across unit + integration | | Coverage | Met | 75% line coverage | | Linting | Met | clang-format, clang-tidy, ament_lint | -| Platform support | Met | Ubuntu Noble / ROS 2 Jazzy + Ubuntu Jammy / ROS 2 Humble + Rolling (best-effort) | +| Platform support | Met | Ubuntu Noble / ROS 2 Jazzy + Ubuntu Jammy / ROS 2 Humble + Ubuntu Resolute / ROS 2 Lyrical Luth | | Security policy | Met | REP-2006 compliant | **Caveat:** Version is 0.3.0 (pre-1.0.0, requirement 1.ii). The REST API is versioned (`/api/v1/`) diff --git a/README.md b/README.md index 1508c6571..5098af266 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) [![ROS 2 Jazzy](https://img.shields.io/badge/ROS%202-Jazzy-blue)](https://docs.ros.org/en/jazzy/) [![ROS 2 Humble](https://img.shields.io/badge/ROS%202-Humble-blue)](https://docs.ros.org/en/humble/) -[![ROS 2 Rolling](https://img.shields.io/badge/ROS%202-Rolling-orange)](https://docs.ros.org/en/rolling/) +[![ROS 2 Lyrical Luth](https://img.shields.io/badge/ROS%202-Lyrical%20Luth-blue)](https://docs.ros.org/en/lyrical/) [![Discord](https://img.shields.io/badge/Discord-Join%20Us-7289DA?logo=discord&logoColor=white)](https://discord.gg/6CXPMApAyq) [![Quality Level 3](https://img.shields.io/badge/Quality-Level%203-yellow)](QUALITY_DECLARATION.md) @@ -42,7 +42,7 @@ cd selfpatch_demos/demos/turtlebot3_integration Open `http://localhost:3000` in your browser. You will see a TurtleBot3 with Nav2, organized into a browsable entity tree with live faults, topic data, and parameter access. -**Build from source** (ROS 2 Jazzy, Humble, or Rolling): +**Build from source** (ROS 2 Jazzy, Humble, or Lyrical Luth): ```bash source /opt/ros/jazzy/setup.bash # or humble - adjust for your distro @@ -148,8 +148,8 @@ This entity model follows the **SOVD (Service-Oriented Vehicle Diagnostics)** st ## 📋 Requirements -- **OS:** Ubuntu 24.04 LTS (Jazzy / Rolling) or Ubuntu 22.04 LTS (Humble) -- **ROS 2:** Jazzy Jalisco, Humble Hawksbill, or Rolling (experimental) +- **OS:** Ubuntu 26.04 LTS (Resolute Raccoon, for Lyrical Luth), Ubuntu 24.04 LTS (Noble, for Jazzy), or Ubuntu 22.04 LTS (Jammy, for Humble) +- **ROS 2:** Jazzy Jalisco, Humble Hawksbill, or Lyrical Luth (LTS, released May 2026) - **Compiler:** GCC 11+ (C++17 support) - **Build System:** colcon + ament_cmake diff --git a/docs/installation.rst b/docs/installation.rst index d5993934d..941e67c29 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -2,7 +2,7 @@ Installation ============ This guide covers installation of ros2_medkit on Ubuntu 24.04 with ROS 2 Jazzy, -Ubuntu 22.04 with ROS 2 Humble, or Ubuntu 24.04 with ROS 2 Rolling. +Ubuntu 22.04 with ROS 2 Humble, or Ubuntu 26.04 with ROS 2 Lyrical Luth. System Requirements ------------------- @@ -14,25 +14,25 @@ System Requirements * - Requirement - Version * - Operating System - - Ubuntu 24.04 LTS (Noble) or Ubuntu 22.04 LTS (Jammy) + - Ubuntu 26.04 LTS (Resolute), Ubuntu 24.04 LTS (Noble), or Ubuntu 22.04 LTS (Jammy) * - ROS 2 Distribution - - Jazzy, Humble, or Rolling + - Jazzy, Humble, or Lyrical Luth * - C++ Compiler - GCC 11+ (C++17 support required) * - CMake - 3.22+ * - Python - - 3.10+ (Humble) / 3.12+ (Jazzy / Rolling) + - 3.10+ (Humble) / 3.12+ (Jazzy) / 3.14+ (Lyrical Luth) Prerequisites ------------- -**ROS 2 Jazzy, Humble, or Rolling** must be installed and sourced. Follow the official installation guide +**ROS 2 Jazzy, Humble, or Lyrical Luth** must be installed and sourced. Follow the official installation guide for your distribution: - Jazzy: https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debs.html - Humble: https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debs.html -- Rolling: https://docs.ros.org/en/rolling/Installation/Ubuntu-Install-Debs.html +- Lyrical Luth: https://docs.ros.org/en/lyrical/Installation/Ubuntu-Install-Debs.html .. note:: @@ -136,8 +136,8 @@ ROS 2 distributions: # Humble docker run -p 8080:8080 ghcr.io/selfpatch/ros2_medkit-humble:latest - # Rolling - docker run -p 8080:8080 ghcr.io/selfpatch/ros2_medkit-rolling:latest + # Lyrical Luth + docker run -p 8080:8080 ghcr.io/selfpatch/ros2_medkit-lyrical:latest The gateway will be available at http://localhost:8080/api/v1/health. diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 29bddb6c0..bdaf23580 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -219,7 +219,7 @@ parameter changes) only happen when explicitly requested via the API. **Q: Can I use ros2_medkit with ROS 1?** -No. ros2_medkit requires ROS 2 (Jazzy, Humble, or Rolling). For ROS 1 systems, consider using +No. ros2_medkit requires ROS 2 (Jazzy, Humble, or Lyrical Luth). For ROS 1 systems, consider using the ``ros1_bridge`` and running ros2_medkit on the ROS 2 side. **Q: Is ros2_medkit production-ready?** diff --git a/docs/tutorials/docker.rst b/docs/tutorials/docker.rst index 629248689..8c51d5663 100644 --- a/docs/tutorials/docker.rst +++ b/docs/tutorials/docker.rst @@ -33,8 +33,8 @@ Images are available for all supported ROS 2 distributions: - ``ghcr.io/selfpatch/ros2_medkit-jazzy:latest`` * - Humble - ``ghcr.io/selfpatch/ros2_medkit-humble:latest`` - * - Rolling - - ``ghcr.io/selfpatch/ros2_medkit-rolling:latest`` + * - Lyrical Luth + - ``ghcr.io/selfpatch/ros2_medkit-lyrical:latest`` Each image includes the gateway and all open-core packages: diff --git a/docs/tutorials/plugin-system.rst b/docs/tutorials/plugin-system.rst index 5361f42bd..62f0169bd 100644 --- a/docs/tutorials/plugin-system.rst +++ b/docs/tutorials/plugin-system.rst @@ -271,7 +271,7 @@ providing access to gateway data and utilities: ``create_generic_subscription()``, or ``create_callback_group()`` directly on this node. Issue #375 showed that concurrent rcl mutations on the gateway node race its internal hash map and - SIGSEGV under load on Rolling. The regression gate in + SIGSEGV under load on Rolling/Lyrical. The regression gate in ``scripts/check_no_naked_subscriptions.sh`` is run in CI and will fail PRs that add such calls outside the allowlist. Use ``ros2_medkit_gateway::ros2_common::Ros2SubscriptionSlot::create_typed`` diff --git a/scripts/check_no_naked_subscriptions.sh b/scripts/check_no_naked_subscriptions.sh index 38f0309a4..57c64296a 100755 --- a/scripts/check_no_naked_subscriptions.sh +++ b/scripts/check_no_naked_subscriptions.sh @@ -5,7 +5,8 @@ # callback-group creation APIs from gateway and fault_manager code outside # `ros2_common/` is forbidden because it bypasses Ros2SubscriptionExecutor's # serial worker (or fault_manager's LockedSubscriptionGuard) and reintroduces -# the rcl hash-map race that triggered SIGSEGV on Rolling. +# the rcl hash-map race that triggered SIGSEGV on Rolling (still applicable +# on Lyrical and any future distro that ships the same rcl hash-map code). # # Callers in the gateway must go through: # ros2_medkit_gateway::ros2_common::Ros2SubscriptionSlot::create_typed / create_generic diff --git a/src/ros2_medkit_cmake/README.md b/src/ros2_medkit_cmake/README.md index 7f5bb5023..eb28abdf9 100644 --- a/src/ros2_medkit_cmake/README.md +++ b/src/ros2_medkit_cmake/README.md @@ -9,7 +9,7 @@ build acceleration, and centralized linting configuration across all packages. |--------|-------------| | `ROS2MedkitCcache.cmake` | Auto-detect and configure ccache with PCH-aware sloppiness settings | | `ROS2MedkitLinting.cmake` | Centralized clang-tidy configuration (opt-in locally, mandatory in CI) | -| `ROS2MedkitCompat.cmake` | Multi-distro compatibility shims for ROS 2 Humble, Jazzy, and Rolling | +| `ROS2MedkitCompat.cmake` | Multi-distro compatibility shims for ROS 2 Humble, Jazzy, and Lyrical Luth | ### ROS2MedkitCompat @@ -17,7 +17,7 @@ Resolves dependency differences across ROS 2 distributions: - `medkit_find_yaml_cpp()` - Finds yaml-cpp (namespaced targets on Jazzy, manual fallback on Humble) - `medkit_find_cpp_httplib()` - Finds cpp-httplib >= 0.14 via pkg-config, CMake config, or vendored fallback (`VENDORED_DIR` param) -- `medkit_target_dependencies()` - Drop-in replacement for `ament_target_dependencies` (removed on Rolling) +- `medkit_target_dependencies()` - Drop-in replacement for `ament_target_dependencies` (removed on Lyrical) - `medkit_detect_compat_defs()` / `medkit_apply_compat_defs()` - Compile definitions for version-specific APIs ## Usage diff --git a/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake b/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake index bcb7f5c8a..8825ef846 100644 --- a/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake +++ b/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake @@ -17,7 +17,7 @@ # ============================================================================= # # Centralizes all dependency resolution workarounds for supporting multiple -# ROS 2 distributions (Humble, Jazzy, Rolling) in a single place. +# ROS 2 distributions (Humble, Jazzy, Lyrical) in a single place. # # Usage (in each package's CMakeLists.txt): # find_package(ros2_medkit_cmake REQUIRED) @@ -31,7 +31,7 @@ # medkit_target_dependencies(target ...) - Drop-in ament_target_dependencies replacement # # Variables set by medkit_detect_compat_defs(): -# MEDKIT_RCLCPP_VERSION_MAJOR — integer (e.g., 16 for Humble, 28 for Jazzy) +# MEDKIT_RCLCPP_VERSION_MAJOR — integer (16=Humble, 28=Jazzy, 32+=Lyrical) # MEDKIT_ROSBAG2_OLD_TIMESTAMP — ON if rosbag2_storage < 0.22.0 (Humble) # @@ -40,9 +40,11 @@ include_guard(GLOBAL) # --------------------------------------------------------------------------- # medkit_find_yaml_cpp() # --------------------------------------------------------------------------- -# Jazzy's yaml_cpp_vendor exports a namespaced yaml-cpp::yaml-cpp cmake target. -# Humble's yaml_cpp_vendor bundles yaml-cpp but does NOT export the cmake target. -# This macro creates an IMPORTED INTERFACE target when find_package doesn't. +# Jazzy's and Lyrical's yaml_cpp_vendor export a namespaced yaml-cpp::yaml-cpp +# cmake target (Jazzy directly; Lyrical via its Findyaml-cpp.cmake module that +# aliases the upstream yaml-cpp 0.8+ target). Humble's yaml_cpp_vendor bundles +# yaml-cpp but does NOT export the cmake target. This macro creates an IMPORTED +# INTERFACE target when find_package doesn't. # # Prerequisite: find_package(yaml_cpp_vendor REQUIRED) must be called before. # --------------------------------------------------------------------------- @@ -120,7 +122,7 @@ endmacro() # Call AFTER find_package(rclcpp) and optionally find_package(rosbag2_storage). # # Sets: -# MEDKIT_RCLCPP_VERSION_MAJOR — integer (16=Humble, 21+=Iron, 28+=Jazzy) +# MEDKIT_RCLCPP_VERSION_MAJOR — integer (16=Humble, 21+=Iron, 28+=Jazzy, 32+=Lyrical) # MEDKIT_ROSBAG2_OLD_TIMESTAMP — ON if rosbag2_storage < 0.22.0 (Humble) # --------------------------------------------------------------------------- macro(medkit_detect_compat_defs) @@ -166,11 +168,14 @@ endfunction() # --------------------------------------------------------------------------- # medkit_target_dependencies(target [PUBLIC|PRIVATE|INTERFACE] dep1 dep2 ...) # --------------------------------------------------------------------------- -# Drop-in replacement for ament_target_dependencies that works on Rolling -# (where ament_target_dependencies was removed from ament_cmake). +# Drop-in replacement for ament_target_dependencies that works on Lyrical +# (ament_target_dependencies was deprecated in Kilted / ament_cmake 2.7.3 +# and removed in ament_cmake 2.8.5+, which Lyrical ships). # # On Humble/Jazzy: delegates to ament_target_dependencies (available). -# On Rolling: uses target_link_libraries with ${dep_TARGETS}. +# On Lyrical: uses target_link_libraries with ${dep_TARGETS}. +# The branch is selected at runtime via if(COMMAND ament_target_dependencies) +# so any future distro keeps working regardless of where the removal lands. # # When no visibility keyword (PUBLIC/PRIVATE/INTERFACE) is passed, the macro # uses the plain target_link_libraries signature. This avoids conflicts with @@ -185,7 +190,7 @@ macro(medkit_target_dependencies target) if(COMMAND ament_target_dependencies) ament_target_dependencies(${target} ${ARGN}) else() - # Rolling fallback: resolve dependency targets explicitly. + # Lyrical fallback: resolve dependency targets explicitly. # # CMake forbids mixing the "plain" and "keyword" (PUBLIC/PRIVATE/INTERFACE) # signatures of target_link_libraries on the same target. diff --git a/src/ros2_medkit_cmake/design/index.rst b/src/ros2_medkit_cmake/design/index.rst index 90741d3dd..f7981f98d 100644 --- a/src/ros2_medkit_cmake/design/index.rst +++ b/src/ros2_medkit_cmake/design/index.rst @@ -41,7 +41,7 @@ The package provides four CMake modules installed to the ament index: - ``medkit_find_cpp_httplib()`` - Finds cpp-httplib >= 0.14 via pkg-config, cmake config, or vendored fallback (``VENDORED_DIR`` param) - ``medkit_detect_compat_defs()`` - Detects rclcpp and rosbag2 versions, sets ``MEDKIT_RCLCPP_VERSION_MAJOR`` and ``MEDKIT_ROSBAG2_OLD_TIMESTAMP`` - ``medkit_apply_compat_defs(target)`` - Applies compile definitions based on detected versions - - ``medkit_target_dependencies(target ...)`` - Drop-in replacement for ``ament_target_dependencies`` that also works on Rolling (where ``ament_target_dependencies`` was removed) + - ``medkit_target_dependencies(target ...)`` - Drop-in replacement for ``ament_target_dependencies`` that also works on Lyrical (where ``ament_target_dependencies`` was removed) Design Decisions ---------------- @@ -60,5 +60,5 @@ Multi-Distro Strategy Rather than maintaining separate branches per ROS 2 distribution, the compat module detects version numbers at configure time and adapts. This keeps a single -source tree building on Humble, Jazzy, and Rolling without ``#ifdef`` proliferation +source tree building on Humble, Jazzy, and Lyrical Luth without ``#ifdef`` proliferation in application code. diff --git a/src/ros2_medkit_discovery_plugins/ros2_medkit_beacon_common/CMakeLists.txt b/src/ros2_medkit_discovery_plugins/ros2_medkit_beacon_common/CMakeLists.txt index b30e4190a..289365791 100644 --- a/src/ros2_medkit_discovery_plugins/ros2_medkit_beacon_common/CMakeLists.txt +++ b/src/ros2_medkit_discovery_plugins/ros2_medkit_beacon_common/CMakeLists.txt @@ -79,9 +79,9 @@ if(BUILD_TESTING) ) ament_lint_auto_find_test_dependencies() - # ci.yml skips the ament_cmake_clang_format rosdep key on Humble + Rolling - # (linters only run in the Jazzy quality job), so QUIET + FOUND check - # avoids hard-failing on those runners. + # ci.yml skips the ament_cmake_clang_format rosdep key in the build-and-test + # job (linters only run in the Jazzy quality job), so QUIET + FOUND check + # avoids hard-failing when the package is not installed. find_package(ament_cmake_clang_format QUIET) if(ament_cmake_clang_format_FOUND) file(GLOB_RECURSE _format_files diff --git a/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/CMakeLists.txt b/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/CMakeLists.txt index 556edce5f..68d04f6bc 100644 --- a/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/CMakeLists.txt +++ b/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/CMakeLists.txt @@ -65,9 +65,9 @@ if(BUILD_TESTING) ) ament_lint_auto_find_test_dependencies() - # ci.yml skips the ament_cmake_clang_format rosdep key on Humble + Rolling - # (linters only run in the Jazzy quality job), so QUIET + FOUND check - # avoids hard-failing on those runners. + # ci.yml skips the ament_cmake_clang_format rosdep key in the build-and-test + # job (linters only run in the Jazzy quality job), so QUIET + FOUND check + # avoids hard-failing when the package is not installed. find_package(ament_cmake_clang_format QUIET) if(ament_cmake_clang_format_FOUND) file(GLOB_RECURSE _format_files diff --git a/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/src/param_beacon_plugin.cpp b/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/src/param_beacon_plugin.cpp index 93f2d87e4..a00dc5ff5 100644 --- a/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/src/param_beacon_plugin.cpp +++ b/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/src/param_beacon_plugin.cpp @@ -35,9 +35,10 @@ using ros2_medkit_gateway::PluginContext; using ros2_medkit_gateway::SovdEntityType; ParameterBeaconPlugin::~ParameterBeaconPlugin() noexcept { - // On Rolling, ~rclcpp::Node can throw graph_listener::NodeNotFoundError - // once rclcpp::shutdown() has invalidated the context. An exception - // escaping a destructor calls std::terminate(), so swallow it here. + // On Lyrical (originally observed on Rolling), ~rclcpp::Node can throw + // graph_listener::NodeNotFoundError once rclcpp::shutdown() has invalidated + // the context. An exception escaping a destructor calls std::terminate(), + // so swallow it here. try { shutdown(); } catch (...) { @@ -157,8 +158,8 @@ void ParameterBeaconPlugin::shutdown() { backoff_counts_.clear(); skip_remaining_.clear(); } - // ~rclcpp::Node can throw graph_listener::NodeNotFoundError on Rolling - // when the context was already torn down by rclcpp::shutdown(). Swallow + // ~rclcpp::Node can throw graph_listener::NodeNotFoundError on Lyrical + // (and Rolling) when the context was already torn down by rclcpp::shutdown(). Swallow // it so the plugin_manager shutdown sequence (and the plugin destructor // that calls back into us) does not abort the process. try { diff --git a/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/CMakeLists.txt b/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/CMakeLists.txt index b20a45ef9..a9deaddf6 100644 --- a/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/CMakeLists.txt +++ b/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/CMakeLists.txt @@ -71,9 +71,9 @@ if(BUILD_TESTING) ) ament_lint_auto_find_test_dependencies() - # ci.yml skips the ament_cmake_clang_format rosdep key on Humble + Rolling - # (linters only run in the Jazzy quality job), so QUIET + FOUND check - # avoids hard-failing on those runners. + # ci.yml skips the ament_cmake_clang_format rosdep key in the build-and-test + # job (linters only run in the Jazzy quality job), so QUIET + FOUND check + # avoids hard-failing when the package is not installed. find_package(ament_cmake_clang_format QUIET) if(ament_cmake_clang_format_FOUND) file(GLOB_RECURSE _format_files diff --git a/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/src/topic_beacon_plugin.cpp b/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/src/topic_beacon_plugin.cpp index aa8ce05af..c133cb9c4 100644 --- a/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/src/topic_beacon_plugin.cpp +++ b/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/src/topic_beacon_plugin.cpp @@ -33,9 +33,10 @@ using ros2_medkit_gateway::PluginContext; using ros2_medkit_gateway::SovdEntityType; TopicBeaconPlugin::~TopicBeaconPlugin() noexcept { - // On Rolling, ~rclcpp::Subscription can throw graph_listener::NodeNotFoundError - // once rclcpp::shutdown() has invalidated the context. An exception - // escaping a destructor calls std::terminate(), so swallow it here. + // On Lyrical (originally observed on Rolling), ~rclcpp::Subscription can throw + // graph_listener::NodeNotFoundError once rclcpp::shutdown() has invalidated + // the context. An exception escaping a destructor calls std::terminate(), + // so swallow it here. try { shutdown(); } catch (...) { @@ -113,9 +114,9 @@ void TopicBeaconPlugin::shutdown() { if (shutdown_requested_.exchange(true)) { return; } - // ~rclcpp::Subscription can throw on Rolling when the rclcpp context - // was torn down before us; swallow so plugin_manager shutdown and the - // plugin destructor calling back into us do not abort the process. + // ~rclcpp::Subscription can throw on Lyrical (and Rolling) when the rclcpp + // context was torn down before us; swallow so plugin_manager shutdown and + // the plugin destructor calling back into us do not abort the process. try { subscription_.reset(); } catch (...) { diff --git a/src/ros2_medkit_fault_manager/src/snapshot_capture.cpp b/src/ros2_medkit_fault_manager/src/snapshot_capture.cpp index f833053df..625d0c046 100644 --- a/src/ros2_medkit_fault_manager/src/snapshot_capture.cpp +++ b/src/ros2_medkit_fault_manager/src/snapshot_capture.cpp @@ -44,9 +44,9 @@ struct LockedSubscriptionGuard { // C++20 [dcl.init.aggr] disqualifies a class as an aggregate if it has // any user-declared constructors, including ``= delete`` ones (the rule // tightened from "user-provided" in C++17 to "user-declared" in C++20). - // Rolling's gcc 14 / libstdc++ enforces the C++20 wording even when + // Lyrical's gcc 15 / libstdc++ enforces the C++20 wording even when // CMAKE_CXX_STANDARD is 17, so brace-init ``LockedSubscriptionGuard{ - // &mtx, sub, cg}`` would fail to find a matching constructor on rolling. + // &mtx, sub, cg}`` would fail to find a matching constructor on Lyrical. // An explicit constructor sidesteps the aggregate-init rules entirely. LockedSubscriptionGuard(std::mutex * m, rclcpp::GenericSubscription::SharedPtr s, rclcpp::CallbackGroup::SharedPtr cg) : mtx(m), subscription(std::move(s)), callback_group(std::move(cg)) { diff --git a/src/ros2_medkit_gateway/CMakeLists.txt b/src/ros2_medkit_gateway/CMakeLists.txt index 07896b50c..f5596f3fd 100644 --- a/src/ros2_medkit_gateway/CMakeLists.txt +++ b/src/ros2_medkit_gateway/CMakeLists.txt @@ -318,7 +318,7 @@ if(BUILD_TESTING) # Configure clang-format to only check our source files (not vendored). # ament_cmake_clang_format is intentionally only installed in the Jazzy - # quality job (ci.yml skips its rosdep key on Humble + Rolling), so use + # quality job (ci.yml skips its rosdep key in the build-and-test job), so use # QUIET + FOUND check instead of REQUIRED to gracefully degrade on the # build-and-test runners without breaking the build. find_package(ament_cmake_clang_format QUIET) diff --git a/src/ros2_medkit_gateway/README.md b/src/ros2_medkit_gateway/README.md index db7203a11..d9f79603f 100644 --- a/src/ros2_medkit_gateway/README.md +++ b/src/ros2_medkit_gateway/README.md @@ -1592,7 +1592,7 @@ All rcl subscription create/destroy calls must go through `Ros2SubscriptionSlot::create_typed` / `create_generic` (defined in `ros2_common/`). Calling `node->create_subscription()`, `create_generic_subscription()`, or `create_callback_group()` anywhere -else triggers the race from issue #375 and SIGSEGVs on Rolling under +else triggers the race from issue #375 and SIGSEGVs on Rolling/Lyrical under concurrent HTTP load. The regression gate is `scripts/check_no_naked_subscriptions.sh`. It diff --git a/src/ros2_medkit_gateway/design/ros2_subscription_architecture.rst b/src/ros2_medkit_gateway/design/ros2_subscription_architecture.rst index 918c95a68..54251a316 100644 --- a/src/ros2_medkit_gateway/design/ros2_subscription_architecture.rst +++ b/src/ros2_medkit_gateway/design/ros2_subscription_architecture.rst @@ -8,9 +8,10 @@ The gateway's original ``NativeTopicSampler`` created a short-lived ``rclcpp::GenericSubscription`` for every ``/data`` sample call. Under concurrent HTTP load, multiple cpp-httplib handler threads invoked ``Node::create_generic_subscription()`` on the same node, racing inside rcl's -internal hash map and corrupting its linked entries. The symptom was a Rolling -SIGSEGV in ``test_data_read`` (issue #375) and intermittent non-deterministic -crashes on sample-heavy deployments. +internal hash map and corrupting its linked entries. The symptom was a SIGSEGV +in ``test_data_read`` (issue #375, first reproduced on the Rolling distro that +later became Lyrical) and intermittent non-deterministic crashes on sample-heavy +deployments. This document describes the replacement architecture: a single-writer subscription executor, a RAII slot handle, and a per-topic pool. @@ -92,7 +93,7 @@ Public API (summary): Graph change detection uses the public ``rclcpp::Node::get_graph_event()`` API and a wall timer polling ``event->check_and_clear()`` on the subscription node. Internal ``GraphListener`` is intentionally avoided - it is not a stable -public API across Humble / Jazzy / Rolling. +public API across Humble / Jazzy / Lyrical Luth. Shutdown drains the queue: the worker processes any already-enqueued tasks so pending ``run_sync`` promises are fulfilled before the worker exits. Bounded @@ -226,8 +227,8 @@ executor:: node.reset(); // ~GatewayNode with executor still alive rclcpp::shutdown(); -``remove_node`` + explicit ``node.reset()`` are required on rolling / newer -jazzy: rclcpp aborts with ``Node ... needs to be associated with an executor`` +``remove_node`` + explicit ``node.reset()`` are required on Lyrical / newer +Jazzy: rclcpp aborts with ``Node ... needs to be associated with an executor`` if ``~GatewayNode`` touches a service client while stack-unwind has already destroyed the executor. diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/compat/generic_client_compat.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/compat/generic_client_compat.hpp index e095b38c7..a7a704ef4 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/compat/generic_client_compat.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/compat/generic_client_compat.hpp @@ -32,7 +32,7 @@ #include // Detect whether rclcpp::GenericClient is available. -// rclcpp/version.h exists in all supported distros (Humble, Jazzy, Rolling). +// rclcpp/version.h exists in all supported distros (Humble, Jazzy, Lyrical). #include #if defined(RCLCPP_VERSION_MAJOR) && RCLCPP_VERSION_MAJOR >= 21 diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp index aec601878..6cc7a240a 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp @@ -303,7 +303,7 @@ class Ros2SubscriptionExecutor final { std::array graph_in_flight_{}; std::condition_variable graph_in_flight_cv_; - // Public rclcpp graph API - stable across Humble / Jazzy / Rolling + // Public rclcpp graph API - stable across Humble / Jazzy / Lyrical rclcpp::Event::SharedPtr graph_event_; // Dedicated auxiliary thread driving the watchdog and graph-event polling. diff --git a/src/ros2_medkit_gateway/src/main.cpp b/src/ros2_medkit_gateway/src/main.cpp index 06e64e94c..b28f68b5f 100644 --- a/src/ros2_medkit_gateway/src/main.cpp +++ b/src/ros2_medkit_gateway/src/main.cpp @@ -80,7 +80,7 @@ int main(int argc, char ** argv) { // Stand up the ROS 2 subscription executor + topic data provider. // Issue #375: all subscription create/destroy calls are funneled through the // serial worker owned by sub_exec, eliminating the rcl hash-map race that - // previously killed /data on Rolling when concurrent HTTP handler threads + // previously killed /data on Rolling (now Lyrical) when concurrent HTTP handler threads // created subscriptions on the same node. const auto exec_cfg = declare_executor_config(*node); const auto dp_cfg = declare_data_provider_config(*node); @@ -104,7 +104,7 @@ int main(int argc, char ** argv) { // Teardown order (issue #375): stack-unwind destructs executor before node // which leaves ~GatewayNode running against a dead executor. Newer rclcpp - // (rolling; recent jazzy patch releases) asserts 'node needs to be + // (Lyrical; recent Jazzy patch releases) asserts 'node needs to be // associated with an executor' and aborts with exit -6 when the managers' // shutdown paths touch service clients. Explicit teardown avoids that: // 1. detach the provider from GatewayNode so the managers stop using it diff --git a/src/ros2_medkit_integration_tests/test/features/test_openapi_response_drift.test.py b/src/ros2_medkit_integration_tests/test/features/test_openapi_response_drift.test.py index 4591ede2c..aee3c2a97 100644 --- a/src/ros2_medkit_integration_tests/test/features/test_openapi_response_drift.test.py +++ b/src/ros2_medkit_integration_tests/test/features/test_openapi_response_drift.test.py @@ -52,9 +52,9 @@ import requests # Humble (Ubuntu 22.04) ships python3-jsonschema 3.2 which only has draft-7; -# Jazzy/Rolling (Ubuntu 24.04) ship 4.10+ with Draft202012. Prefer the newest -# draft for OpenAPI 3.1 alignment, fall back to Draft7 on Humble. The properties -# we validate (required, type, properties) behave identically across drafts. +# Jazzy (Ubuntu 24.04) / Lyrical Luth (Ubuntu 26.04) ship 4.10+ with Draft202012. +# Prefer the newest draft for OpenAPI 3.1 alignment, fall back to Draft7 on Humble. +# The properties we validate (required, type, properties) behave identically across drafts. try: from jsonschema.validators import Draft202012Validator as _Validator except ImportError: diff --git a/src/ros2_medkit_plugins/ros2_medkit_graph_provider/CMakeLists.txt b/src/ros2_medkit_plugins/ros2_medkit_graph_provider/CMakeLists.txt index 1f4e0f3a0..665ab812a 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_graph_provider/CMakeLists.txt +++ b/src/ros2_medkit_plugins/ros2_medkit_graph_provider/CMakeLists.txt @@ -74,9 +74,9 @@ if(BUILD_TESTING) ) ament_lint_auto_find_test_dependencies() - # ci.yml skips the ament_cmake_clang_format rosdep key on Humble + Rolling - # (linters only run in the Jazzy quality job), so QUIET + FOUND check - # avoids hard-failing on those runners. + # ci.yml skips the ament_cmake_clang_format rosdep key in the build-and-test + # job (linters only run in the Jazzy quality job), so QUIET + FOUND check + # avoids hard-failing when the package is not installed. find_package(ament_cmake_clang_format QUIET) if(ament_cmake_clang_format_FOUND) file(GLOB_RECURSE _format_files diff --git a/src/ros2_medkit_plugins/ros2_medkit_graph_provider/src/graph_provider_plugin.cpp b/src/ros2_medkit_plugins/ros2_medkit_graph_provider/src/graph_provider_plugin.cpp index ad3cf0f46..7ad0cb52c 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_graph_provider/src/graph_provider_plugin.cpp +++ b/src/ros2_medkit_plugins/ros2_medkit_graph_provider/src/graph_provider_plugin.cpp @@ -318,10 +318,10 @@ nlohmann::json build_graph_document_for_apps(const std::string & function_id, } // namespace GraphProviderPlugin::~GraphProviderPlugin() noexcept { - // On Rolling, destroying rclcpp resources (Subscription, Node) after - // rclcpp::shutdown() has invalidated the context can throw - // graph_listener::NodeNotFoundError. An exception escaping a destructor - // calls std::terminate(), so swallow it here. + // On Lyrical (originally observed on Rolling), destroying rclcpp resources + // (Subscription, Node) after rclcpp::shutdown() has invalidated the context + // can throw graph_listener::NodeNotFoundError. An exception escaping a + // destructor calls std::terminate(), so swallow it here. try { shutdown(); } catch (...) { @@ -332,9 +332,9 @@ void GraphProviderPlugin::shutdown() { if (shutdown_requested_.exchange(true)) { return; } - // ~rclcpp::Subscription can throw on Rolling when the rclcpp context - // was torn down before us; swallow so plugin_manager shutdown and the - // plugin destructor calling back into us do not abort the process. + // ~rclcpp::Subscription can throw on Lyrical (and Rolling) when the rclcpp + // context was torn down before us; swallow so plugin_manager shutdown and + // the plugin destructor calling back into us do not abort the process. try { diagnostics_sub_.reset(); } catch (...) { diff --git a/src/ros2_medkit_plugins/ros2_medkit_opcua/CMakeLists.txt b/src/ros2_medkit_plugins/ros2_medkit_opcua/CMakeLists.txt index b2a4fcd37..d66c3ecce 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_opcua/CMakeLists.txt +++ b/src/ros2_medkit_plugins/ros2_medkit_opcua/CMakeLists.txt @@ -133,9 +133,9 @@ if(BUILD_TESTING) ) ament_lint_auto_find_test_dependencies() - # ci.yml skips the ament_cmake_clang_format rosdep key on Humble + Rolling - # (linters only run in the Jazzy quality job), so QUIET + FOUND check - # avoids hard-failing on those runners. + # ci.yml skips the ament_cmake_clang_format rosdep key in the build-and-test + # job (linters only run in the Jazzy quality job), so QUIET + FOUND check + # avoids hard-failing when the package is not installed. find_package(ament_cmake_clang_format QUIET) if(ament_cmake_clang_format_FOUND) file(GLOB_RECURSE _format_files diff --git a/src/ros2_medkit_plugins/ros2_medkit_opcua/src/opcua_client.cpp b/src/ros2_medkit_plugins/ros2_medkit_opcua/src/opcua_client.cpp index 64850ac6f..f26a13e50 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_opcua/src/opcua_client.cpp +++ b/src/ros2_medkit_plugins/ros2_medkit_opcua/src/opcua_client.cpp @@ -44,7 +44,7 @@ inline rclcpp::Logger opcua_client_logger() { // Pre-gate for traces whose stream-build cost is non-trivial (e.g. per-arg // loops). RCLCPP_DEBUG_STREAM constructs the std::stringstream // unconditionally, so for hot paths we check the effective level first. -// Uses the rcutils-level API (available in Humble through Rolling) instead +// Uses the rcutils-level API (available in Humble through Lyrical) instead // of rclcpp::Logger::get_effective_level (Jazzy+ only). inline bool client_debug_enabled() { return rcutils_logging_logger_is_enabled_for("opcua.client", RCUTILS_LOG_SEVERITY_DEBUG); diff --git a/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/CMakeLists.txt b/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/CMakeLists.txt index 0e238b21c..63db59127 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/CMakeLists.txt +++ b/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/CMakeLists.txt @@ -73,9 +73,9 @@ if(BUILD_TESTING) ) ament_lint_auto_find_test_dependencies() - # ci.yml skips the ament_cmake_clang_format rosdep key on Humble + Rolling - # (linters only run in the Jazzy quality job), so QUIET + FOUND check - # avoids hard-failing on those runners. + # ci.yml skips the ament_cmake_clang_format rosdep key in the build-and-test + # job (linters only run in the Jazzy quality job), so QUIET + FOUND check + # avoids hard-failing when the package is not installed. find_package(ament_cmake_clang_format QUIET) if(ament_cmake_clang_format_FOUND) file(GLOB_RECURSE _format_files diff --git a/src/ros2_medkit_serialization/CMakeLists.txt b/src/ros2_medkit_serialization/CMakeLists.txt index d1ef66604..96d4aa2d7 100644 --- a/src/ros2_medkit_serialization/CMakeLists.txt +++ b/src/ros2_medkit_serialization/CMakeLists.txt @@ -138,7 +138,7 @@ if(BUILD_TESTING) # Configure clang-format manually for non-vendored files only. # ament_cmake_clang_format is intentionally only installed in the Jazzy - # quality job (ci.yml skips its rosdep key on Humble + Rolling), so use + # quality job (ci.yml skips its rosdep key in the build-and-test job), so use # QUIET + FOUND check instead of REQUIRED to gracefully degrade on the # build-and-test runners without breaking the build. find_package(ament_cmake_clang_format QUIET) From 98b156b331c64347ce01c4dc23c99113641be869 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 26 May 2026 14:03:21 +0200 Subject: [PATCH 2/7] docs(readme): shorten Lyrical badge label to match Jazzy/Humble style --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5098af266..861028eef 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) [![ROS 2 Jazzy](https://img.shields.io/badge/ROS%202-Jazzy-blue)](https://docs.ros.org/en/jazzy/) [![ROS 2 Humble](https://img.shields.io/badge/ROS%202-Humble-blue)](https://docs.ros.org/en/humble/) -[![ROS 2 Lyrical Luth](https://img.shields.io/badge/ROS%202-Lyrical%20Luth-blue)](https://docs.ros.org/en/lyrical/) +[![ROS 2 Lyrical](https://img.shields.io/badge/ROS%202-Lyrical-blue)](https://docs.ros.org/en/lyrical/) [![Discord](https://img.shields.io/badge/Discord-Join%20Us-7289DA?logo=discord&logoColor=white)](https://discord.gg/6CXPMApAyq) [![Quality Level 3](https://img.shields.io/badge/Quality-Level%203-yellow)](QUALITY_DECLARATION.md) From 7201783eaa968a4bfea8887d9dda55834428390e Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 26 May 2026 14:34:31 +0200 Subject: [PATCH 3/7] docs: shorten 'Lyrical Luth'/'Resolute Raccoon' to codenames for consistency --- .github/copilot-instructions.md | 2 +- CONTRIBUTING.md | 2 +- QUALITY_DECLARATION.md | 8 ++++---- README.md | 4 ++-- docs/installation.rst | 12 ++++++------ docs/troubleshooting.rst | 2 +- docs/tutorials/docker.rst | 2 +- src/ros2_medkit_cmake/README.md | 2 +- src/ros2_medkit_cmake/design/index.rst | 2 +- .../design/ros2_subscription_architecture.rst | 2 +- .../features/test_openapi_response_drift.test.py | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f652b8385..3aeb04381 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,7 +4,7 @@ **ros2_medkit** is a ROS 2 diagnostics gateway that exposes ROS 2 system information via a RESTful HTTP API aligned with the **SOVD (Service-Oriented Vehicle Diagnostics)** specification. It models robots as a diagnostic entity tree: **Area -> Component -> App**, with optional **Function** groupings. -**Tech Stack**: C++17, ROS 2 Jazzy/Humble/Lyrical Luth, Ubuntu 26.04/24.04/22.04 +**Tech Stack**: C++17, ROS 2 Jazzy/Humble/Lyrical, Ubuntu 26.04/24.04/22.04 ## Package Structure diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4df3f251c..deb931883 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,7 +107,7 @@ Open `coverage_html/index.html` in your browser. #### CI/CD -All PRs are tested on Ubuntu 24.04 (Jazzy) with parallel lint + test jobs, plus Humble and Lyrical Luth. Coverage is uploaded to Codecov on push to main. All CI jobs use ccache. +All PRs are tested on Ubuntu 24.04 (Jazzy) with parallel lint + test jobs, plus Humble and Lyrical. Coverage is uploaded to Codecov on push to main. All CI jobs use ccache. ### Pull Request Checklist diff --git a/QUALITY_DECLARATION.md b/QUALITY_DECLARATION.md index 558ff4e64..984074fb9 100644 --- a/QUALITY_DECLARATION.md +++ b/QUALITY_DECLARATION.md @@ -86,7 +86,7 @@ GitHub Copilot code review is used in addition to human review. All pull requests must pass CI before merging: -- **Build & Test job:** Full build + unit/integration tests on Ubuntu Noble / ROS 2 Jazzy, Ubuntu Jammy / ROS 2 Humble, and Ubuntu Resolute / ROS 2 Lyrical Luth. Linter tests on Jazzy only +- **Build & Test job:** Full build + unit/integration tests on Ubuntu Noble / ROS 2 Jazzy, Ubuntu Jammy / ROS 2 Humble, and Ubuntu Resolute / ROS 2 Lyrical. Linter tests on Jazzy only - **Coverage job:** Debug build with coverage. Reports are generated for all PRs as artifacts and uploaded to [Codecov](https://codecov.io/gh/selfpatch/ros2_medkit) on pushes to `main` - Linting enforced: `clang-format`, `clang-tidy` via `ament_lint_auto` @@ -203,9 +203,9 @@ Linter tests are enforced in CI on every pull request. - **Ubuntu 24.04 (Noble)** with **ROS 2 Jazzy** (primary) - **Ubuntu 22.04 (Jammy)** with **ROS 2 Humble** -- **Ubuntu 26.04 (Resolute Raccoon)** with **ROS 2 Lyrical Luth** (newest LTS, released May 2026) +- **Ubuntu 26.04 (Resolute)** with **ROS 2 Lyrical** (newest LTS, released May 2026) -Jazzy and Humble are Tier 1 LTS platforms per [REP-2000](https://www.ros.org/reps/rep-2000.html); Lyrical Luth is the newest LTS (May 2026) and is also tested in CI. +Jazzy and Humble are Tier 1 LTS platforms per [REP-2000](https://www.ros.org/reps/rep-2000.html); Lyrical is the newest LTS (May 2026) and is also tested in CI. --- @@ -234,7 +234,7 @@ Security issues can be reported via GitHub Security Advisories on the | Feature tests | Met | 65 tests across unit + integration | | Coverage | Met | 75% line coverage | | Linting | Met | clang-format, clang-tidy, ament_lint | -| Platform support | Met | Ubuntu Noble / ROS 2 Jazzy + Ubuntu Jammy / ROS 2 Humble + Ubuntu Resolute / ROS 2 Lyrical Luth | +| Platform support | Met | Ubuntu Noble / ROS 2 Jazzy + Ubuntu Jammy / ROS 2 Humble + Ubuntu Resolute / ROS 2 Lyrical | | Security policy | Met | REP-2006 compliant | **Caveat:** Version is 0.3.0 (pre-1.0.0, requirement 1.ii). The REST API is versioned (`/api/v1/`) diff --git a/README.md b/README.md index 861028eef..e089993e9 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ cd selfpatch_demos/demos/turtlebot3_integration Open `http://localhost:3000` in your browser. You will see a TurtleBot3 with Nav2, organized into a browsable entity tree with live faults, topic data, and parameter access. -**Build from source** (ROS 2 Jazzy, Humble, or Lyrical Luth): +**Build from source** (ROS 2 Jazzy, Humble, or Lyrical): ```bash source /opt/ros/jazzy/setup.bash # or humble - adjust for your distro @@ -148,7 +148,7 @@ This entity model follows the **SOVD (Service-Oriented Vehicle Diagnostics)** st ## 📋 Requirements -- **OS:** Ubuntu 26.04 LTS (Resolute Raccoon, for Lyrical Luth), Ubuntu 24.04 LTS (Noble, for Jazzy), or Ubuntu 22.04 LTS (Jammy, for Humble) +- **OS:** Ubuntu 26.04 LTS (Resolute, for Lyrical), Ubuntu 24.04 LTS (Noble, for Jazzy), or Ubuntu 22.04 LTS (Jammy, for Humble) - **ROS 2:** Jazzy Jalisco, Humble Hawksbill, or Lyrical Luth (LTS, released May 2026) - **Compiler:** GCC 11+ (C++17 support) - **Build System:** colcon + ament_cmake diff --git a/docs/installation.rst b/docs/installation.rst index 941e67c29..80626094b 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -2,7 +2,7 @@ Installation ============ This guide covers installation of ros2_medkit on Ubuntu 24.04 with ROS 2 Jazzy, -Ubuntu 22.04 with ROS 2 Humble, or Ubuntu 26.04 with ROS 2 Lyrical Luth. +Ubuntu 22.04 with ROS 2 Humble, or Ubuntu 26.04 with ROS 2 Lyrical. System Requirements ------------------- @@ -16,23 +16,23 @@ System Requirements * - Operating System - Ubuntu 26.04 LTS (Resolute), Ubuntu 24.04 LTS (Noble), or Ubuntu 22.04 LTS (Jammy) * - ROS 2 Distribution - - Jazzy, Humble, or Lyrical Luth + - Jazzy, Humble, or Lyrical * - C++ Compiler - GCC 11+ (C++17 support required) * - CMake - 3.22+ * - Python - - 3.10+ (Humble) / 3.12+ (Jazzy) / 3.14+ (Lyrical Luth) + - 3.10+ (Humble) / 3.12+ (Jazzy) / 3.14+ (Lyrical) Prerequisites ------------- -**ROS 2 Jazzy, Humble, or Lyrical Luth** must be installed and sourced. Follow the official installation guide +**ROS 2 Jazzy, Humble, or Lyrical** must be installed and sourced. Follow the official installation guide for your distribution: - Jazzy: https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debs.html - Humble: https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debs.html -- Lyrical Luth: https://docs.ros.org/en/lyrical/Installation/Ubuntu-Install-Debs.html +- Lyrical: https://docs.ros.org/en/lyrical/Installation/Ubuntu-Install-Debs.html .. note:: @@ -136,7 +136,7 @@ ROS 2 distributions: # Humble docker run -p 8080:8080 ghcr.io/selfpatch/ros2_medkit-humble:latest - # Lyrical Luth + # Lyrical docker run -p 8080:8080 ghcr.io/selfpatch/ros2_medkit-lyrical:latest The gateway will be available at http://localhost:8080/api/v1/health. diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index bdaf23580..5f5057b13 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -219,7 +219,7 @@ parameter changes) only happen when explicitly requested via the API. **Q: Can I use ros2_medkit with ROS 1?** -No. ros2_medkit requires ROS 2 (Jazzy, Humble, or Lyrical Luth). For ROS 1 systems, consider using +No. ros2_medkit requires ROS 2 (Jazzy, Humble, or Lyrical). For ROS 1 systems, consider using the ``ros1_bridge`` and running ros2_medkit on the ROS 2 side. **Q: Is ros2_medkit production-ready?** diff --git a/docs/tutorials/docker.rst b/docs/tutorials/docker.rst index 8c51d5663..61cbf9fb7 100644 --- a/docs/tutorials/docker.rst +++ b/docs/tutorials/docker.rst @@ -33,7 +33,7 @@ Images are available for all supported ROS 2 distributions: - ``ghcr.io/selfpatch/ros2_medkit-jazzy:latest`` * - Humble - ``ghcr.io/selfpatch/ros2_medkit-humble:latest`` - * - Lyrical Luth + * - Lyrical - ``ghcr.io/selfpatch/ros2_medkit-lyrical:latest`` Each image includes the gateway and all open-core packages: diff --git a/src/ros2_medkit_cmake/README.md b/src/ros2_medkit_cmake/README.md index eb28abdf9..8d2052f68 100644 --- a/src/ros2_medkit_cmake/README.md +++ b/src/ros2_medkit_cmake/README.md @@ -9,7 +9,7 @@ build acceleration, and centralized linting configuration across all packages. |--------|-------------| | `ROS2MedkitCcache.cmake` | Auto-detect and configure ccache with PCH-aware sloppiness settings | | `ROS2MedkitLinting.cmake` | Centralized clang-tidy configuration (opt-in locally, mandatory in CI) | -| `ROS2MedkitCompat.cmake` | Multi-distro compatibility shims for ROS 2 Humble, Jazzy, and Lyrical Luth | +| `ROS2MedkitCompat.cmake` | Multi-distro compatibility shims for ROS 2 Humble, Jazzy, and Lyrical | ### ROS2MedkitCompat diff --git a/src/ros2_medkit_cmake/design/index.rst b/src/ros2_medkit_cmake/design/index.rst index f7981f98d..c21709c41 100644 --- a/src/ros2_medkit_cmake/design/index.rst +++ b/src/ros2_medkit_cmake/design/index.rst @@ -60,5 +60,5 @@ Multi-Distro Strategy Rather than maintaining separate branches per ROS 2 distribution, the compat module detects version numbers at configure time and adapts. This keeps a single -source tree building on Humble, Jazzy, and Lyrical Luth without ``#ifdef`` proliferation +source tree building on Humble, Jazzy, and Lyrical without ``#ifdef`` proliferation in application code. diff --git a/src/ros2_medkit_gateway/design/ros2_subscription_architecture.rst b/src/ros2_medkit_gateway/design/ros2_subscription_architecture.rst index 54251a316..df2dc0e13 100644 --- a/src/ros2_medkit_gateway/design/ros2_subscription_architecture.rst +++ b/src/ros2_medkit_gateway/design/ros2_subscription_architecture.rst @@ -93,7 +93,7 @@ Public API (summary): Graph change detection uses the public ``rclcpp::Node::get_graph_event()`` API and a wall timer polling ``event->check_and_clear()`` on the subscription node. Internal ``GraphListener`` is intentionally avoided - it is not a stable -public API across Humble / Jazzy / Lyrical Luth. +public API across Humble / Jazzy / Lyrical. Shutdown drains the queue: the worker processes any already-enqueued tasks so pending ``run_sync`` promises are fulfilled before the worker exits. Bounded diff --git a/src/ros2_medkit_integration_tests/test/features/test_openapi_response_drift.test.py b/src/ros2_medkit_integration_tests/test/features/test_openapi_response_drift.test.py index aee3c2a97..9fe9bac8d 100644 --- a/src/ros2_medkit_integration_tests/test/features/test_openapi_response_drift.test.py +++ b/src/ros2_medkit_integration_tests/test/features/test_openapi_response_drift.test.py @@ -52,7 +52,7 @@ import requests # Humble (Ubuntu 22.04) ships python3-jsonschema 3.2 which only has draft-7; -# Jazzy (Ubuntu 24.04) / Lyrical Luth (Ubuntu 26.04) ship 4.10+ with Draft202012. +# Jazzy (Ubuntu 24.04) / Lyrical (Ubuntu 26.04) ship 4.10+ with Draft202012. # Prefer the newest draft for OpenAPI 3.1 alignment, fall back to Draft7 on Humble. # The properties we validate (required, type, properties) behave identically across drafts. try: From 48ce4aeb3cf23ce39d4491eb5393117dd53d32c1 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Wed, 27 May 2026 10:47:14 +0200 Subject: [PATCH 4/7] fix(cmake): cap cpp-httplib pkg-config at < 0.20 for Lyrical Ubuntu 26.04 Resolute ships libcpp-httplib-dev 0.26 which removed the multipart Request::has_file / get_file_value API used by BulkDataHandlers::handle_upload. Without a version cap, medkit_find_cpp_httplib picks up the system 0.26 package on Lyrical and the gateway build fails with "no member named 'has_file'" errors. Cap pkg-config at < 0.20 so Lyrical falls through to the vendored 0.14.3 header (same path Humble/Jammy already take). The handler can be migrated to the new cpp-httplib multipart API in a follow-up PR. --- src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake b/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake index 8825ef846..55e5d0567 100644 --- a/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake +++ b/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake @@ -74,14 +74,19 @@ endmacro() # --------------------------------------------------------------------------- # medkit_find_cpp_httplib() # --------------------------------------------------------------------------- -# Finds cpp-httplib >= 0.14 through a multi-tier fallback chain: +# Finds cpp-httplib in the [0.14, 0.20) range through a multi-tier fallback chain: # 1. pkg-config (Jazzy/Noble system package) # 2. cmake find_package(httplib) (source builds, Pixi) -# 3. VENDORED_DIR parameter (bundled header-only copy) +# 3. VENDORED_DIR parameter (bundled header-only copy, currently 0.14.3) # # On Humble/Jammy the system package is 0.10.x (too old); the vendored # fallback in ros2_medkit_gateway handles this automatically. # +# On Lyrical/Resolute the system package is 0.26.x which removed the +# multipart `Request::has_file` / `get_file_value` API used by +# BulkDataHandlers, so we cap pkg-config at < 0.20 and fall back to the +# vendored copy until the handler is migrated to the newer API. +# # Creates a unified alias target `cpp_httplib_target` for consumers. # --------------------------------------------------------------------------- macro(medkit_find_cpp_httplib) @@ -89,6 +94,10 @@ macro(medkit_find_cpp_httplib) find_package(PkgConfig QUIET) if(PkgConfig_FOUND) pkg_check_modules(cpp_httplib IMPORTED_TARGET cpp-httplib>=0.14) + if(cpp_httplib_FOUND AND cpp_httplib_VERSION VERSION_GREATER_EQUAL "0.20") + message(STATUS "[MedkitCompat] cpp-httplib: system package ${cpp_httplib_VERSION} removes the multipart Request::has_file API; falling back to vendored 0.14") + unset(cpp_httplib_FOUND) + endif() endif() if(cpp_httplib_FOUND) add_library(cpp_httplib_target ALIAS PkgConfig::cpp_httplib) From 6de154fefbc38f5c27e3c2cba8354e34fe2cf6d3 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Wed, 27 May 2026 10:57:16 +0200 Subject: [PATCH 5/7] fix(cmake): set FOUND=FALSE in macro instead of unset (caller-scope) --- src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake b/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake index 55e5d0567..e5f93460c 100644 --- a/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake +++ b/src/ros2_medkit_cmake/cmake/ROS2MedkitCompat.cmake @@ -96,7 +96,10 @@ macro(medkit_find_cpp_httplib) pkg_check_modules(cpp_httplib IMPORTED_TARGET cpp-httplib>=0.14) if(cpp_httplib_FOUND AND cpp_httplib_VERSION VERSION_GREATER_EQUAL "0.20") message(STATUS "[MedkitCompat] cpp-httplib: system package ${cpp_httplib_VERSION} removes the multipart Request::has_file API; falling back to vendored 0.14") - unset(cpp_httplib_FOUND) + # `unset` in a macro does not clear caller-scope variables set by + # pkg_check_modules, so explicitly mask FOUND to redirect through the + # find_package / VENDORED_DIR fallback chain below. + set(cpp_httplib_FOUND FALSE) endif() endif() if(cpp_httplib_FOUND) From 8059a3e6962410d04d6281557a5e5c21761154d4 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Wed, 27 May 2026 11:34:03 +0200 Subject: [PATCH 6/7] test(gateway): replace UB 1e20 cast with INT64_MAX in routing test EXPECT_LT(ts, static_cast(1e20)) is undefined behaviour: 1e20 exceeds INT64_MAX so the narrowing cast is unspecified. Pre-Lyrical toolchains happened to materialise it as INT64_MAX (test passed); gcc 15 on Resolute materialises it as INT64_MIN, flipping the comparison and breaking the test deterministically. Use std::numeric_limits::max() as the upper bound - that is the real invariant the test wants to express. --- .../test/test_data_access_manager_routing.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ros2_medkit_gateway/test/test_data_access_manager_routing.cpp b/src/ros2_medkit_gateway/test/test_data_access_manager_routing.cpp index 050dc1524..e414953ef 100644 --- a/src/ros2_medkit_gateway/test/test_data_access_manager_routing.cpp +++ b/src/ros2_medkit_gateway/test/test_data_access_manager_routing.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -162,7 +163,10 @@ TEST(DataAccessManagerRoutingTest, NativeSampleAlwaysIncludesNanosecondTimestamp ASSERT_TRUE(with_data["timestamp"].is_number_integer()); const auto ts_data = with_data["timestamp"].get(); EXPECT_GT(ts_data, static_cast(1e18)); // would only ever be true for ns - EXPECT_LT(ts_data, static_cast(1e20)); + // Upper bound stays inside int64_t range: 1e20 exceeds INT64_MAX and the + // narrowing cast is UB (gcc 15 / Lyrical materialises it as INT64_MIN, + // making the comparison silently fail). + EXPECT_LT(ts_data, std::numeric_limits::max()); // status == "metadata_only" mock->sample_publishers_ = 0; @@ -172,7 +176,7 @@ TEST(DataAccessManagerRoutingTest, NativeSampleAlwaysIncludesNanosecondTimestamp ASSERT_TRUE(meta["timestamp"].is_number_integer()); const auto ts_meta = meta["timestamp"].get(); EXPECT_GT(ts_meta, static_cast(1e18)); - EXPECT_LT(ts_meta, static_cast(1e20)); + EXPECT_LT(ts_meta, std::numeric_limits::max()); } // Failure-path coverage: publish() in the real transport throws on From 890049cc29bebb3c671ed88c1da7a69422d5e60a Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Wed, 27 May 2026 12:10:33 +0200 Subject: [PATCH 7/7] test(integration): add CA basicConstraints + keyUsage to test_tls fixture Python 3.14 / OpenSSL on Ubuntu 26.04 (Resolute) rejects CA certs that omit the keyUsage extension with "CA cert does not include key usage extension", failing every HTTPS verify in test_tls on Lyrical. Add the missing extensions when generating the test CA: basicConstraints=critical,CA:TRUE keyUsage=critical,keyCertSign,cRLSign --- .../test/features/test_tls.test.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ros2_medkit_integration_tests/test/features/test_tls.test.py b/src/ros2_medkit_integration_tests/test/features/test_tls.test.py index 0f7871065..1e7b09ed7 100644 --- a/src/ros2_medkit_integration_tests/test/features/test_tls.test.py +++ b/src/ros2_medkit_integration_tests/test/features/test_tls.test.py @@ -64,13 +64,18 @@ def generate_test_certificates(output_dir: str) -> dict: key_file = os.path.join(output_dir, 'key.pem') ca_file = os.path.join(output_dir, 'ca.pem') - # Generate CA key and certificate + # Generate CA key and certificate. + # `basicConstraints` + `keyUsage` are required by Python 3.14 / OpenSSL + # on Ubuntu 26.04 (Resolute) - omitting them triggers + # "CA cert does not include key usage extension" during HTTPS verify. subprocess.run([ 'openssl', 'req', '-x509', '-newkey', 'rsa:2048', '-keyout', os.path.join(output_dir, 'ca_key.pem'), '-out', ca_file, '-days', '1', '-nodes', - '-subj', '/C=US/ST=Test/L=Test/O=Test/CN=TestCA' + '-subj', '/C=US/ST=Test/L=Test/O=Test/CN=TestCA', + '-addext', 'basicConstraints=critical,CA:TRUE', + '-addext', 'keyUsage=critical,keyCertSign,cRLSign', ], check=True, capture_output=True) # Generate server key