From 30fb0e4975ea11e59a55c72d6b5052466cd47741 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Wed, 4 Mar 2026 20:49:17 +0100 Subject: [PATCH] docs: rewrite copilot-instructions.md for effective code review Comprehensive update to reflect the current state of the project and optimize the instructions for GitHub Copilot PR reviews. Key changes: - Add full package structure (fault_manager, serialization, etc.) - Document current architecture (LogManager, PluginManager, HandlerContext) - Add SOVD entity model with capability matrix - Document handler pattern with HandlerContext validation flow - Add error codes reference (SOVD standard + vendor x-medkit-*) - Document plugin framework and provider interfaces - Add CMake module documentation (Compat, Ccache, Linting) - Replace human-oriented checklists with AI-actionable review rules using "Flag when..." directives that Copilot can apply to PR diffs - Add granular test requirements: unit tests for handlers/managers, integration tests for endpoints, error case coverage - Add anti-patterns quick reference table with concrete code examples - Add documentation-as-part-of-every-change rule --- .github/copilot-instructions.md | 371 ++++++++++++++++++++++++-------- 1 file changed, 287 insertions(+), 84 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c60d239d..dd636dda 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,129 +2,332 @@ ## Project Overview -**ros2_medkit** is a ROS 2 diagnostics gateway that exposes ROS 2 system information via a RESTful HTTP API. It models robots as a **diagnostic entity tree** (Area → Component → Function → App) aligned with the SOVD (Service-Oriented Vehicle Diagnostics) specification. +**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 +## Package Structure + +Multi-package colcon workspace under `src/`: + +| Package | Purpose | +|---------|---------| +| `ros2_medkit_gateway` | HTTP gateway - REST server, discovery, entity management, handlers, plugin framework | +| `ros2_medkit_fault_manager` | Fault aggregation with SQLite, AUTOSAR DEM-style debounce, rosbag/snapshot capture | +| `ros2_medkit_fault_reporter` | Client library for nodes to report faults | +| `ros2_medkit_diagnostic_bridge` | Bridges `/diagnostics` topic to fault manager | +| `ros2_medkit_serialization` | Runtime JSON <-> ROS 2 message serialization via dynmsg | +| `ros2_medkit_msgs` | Custom service/message definitions | +| `ros2_medkit_integration_tests` | Python integration test framework + launch tests | + ## Architecture ``` GatewayNode (src/ros2_medkit_gateway/src/gateway_node.cpp) -├── DiscoveryManager - Discovers ROS 2 nodes, services, actions; organizes into Areas/Components -├── DataAccessManager - Topic sampling and publishing via native rclcpp + CLI fallback -├── OperationManager - Service calls and action goal handling -├── ConfigurationManager- ROS 2 parameter CRUD operations -└── RESTServer - HTTP endpoints using cpp-httplib (runs in separate thread) +├── DiscoveryManager - Entity discovery (runtime / manifest / hybrid) +│ └── EntityCache - Thread-safe in-memory entity store +├── DataAccessManager - Topic sampling and publishing +├── OperationManager - Service calls and action goals +├── ConfigurationManager - ROS 2 parameter CRUD +├── FaultManager - Fault query/clear, SSE streams (delegates to fault_manager package) +├── LogManager - /rosout ring buffer + plugin delegation +├── PluginManager - Dynamic plugin loading (.so), provider interfaces +└── RESTServer - cpp-httplib HTTP server (separate thread) + └── HandlerContext - Shared validation, entity lookup, error/JSON helpers ``` -**Key domain model** (see [models.hpp](src/ros2_medkit_gateway/include/ros2_medkit_gateway/models.hpp)): -- **Area**: Top-level namespace grouping (e.g., `/powertrain`, `/chassis`, `/body`, `root`) -- **Component**: Individual ROS 2 node with its topics, services, and actions -- **EntityCache**: Thread-safe in-memory cache of discovered Areas/Components +### Entity Model (SOVD-aligned) + +Defined in `include/ros2_medkit_gateway/models/`: + +- **Area** - namespace grouping (`/powertrain`, `/chassis`, `root`) +- **Component** - groups Apps by namespace (synthetic in runtime mode, explicit in manifest) +- **App** - individual ROS 2 node +- **Function** - capability grouping (functional view, aggregates Apps) + +Entity types: `SovdEntityType` enum in `entity_types.hpp`. Capability matrix in `entity_capabilities.hpp` (SOVD Table 8). + +### SOVD Resource Collections + +Each entity type supports specific collections: + +| Collection | Server | Area | Component | App | Function | +|-----------|--------|------|-----------|-----|----------| +| configurations | x | | x | x | | +| data | x | | x | x | x (aggregated) | +| faults | x | | x | x | | +| operations | x | | x | x | x (aggregated) | +| logs | x | | x | x | | ## Code Style & Conventions -- **C++ Standard**: C++17 with `-Wall -Wextra -Wpedantic -Wshadow -Wconversion` -- **ROS 2 Distribution**: Jazzy (Ubuntu 24.04), Humble (Ubuntu 22.04), or Rolling (Ubuntu 24.04, experimental) -- **Formatting**: Google-based clang-format with 120 column limit, 2-space indent -- **Pointer style**: Middle alignment (`Type * ptr`) per ROS 2 conventions -- **Namespace**: All gateway code lives in `ros2_medkit_gateway` namespace -- **Headers**: Include guards use `#pragma once` -- **Copyright**: Apache 2.0 header required on all source files +- **C++17** with `-Wall -Wextra -Wpedantic -Wshadow -Wconversion` +- **Formatting**: Google-based clang-format, 120 cols, 2-space indent, middle pointer alignment (`Type * ptr`) +- **Headers**: `#pragma once`, Apache 2.0 copyright (year 2026 for new files) +- **Namespace**: `ros2_medkit_gateway` +- **Error handling**: `tl::expected` for fallible operations - NOT exceptions in handlers +- **Thread safety**: Always get fresh `EntityCache` via `ctx_.node()->get_thread_safe_cache()` (in handlers) +- **Header-only libs**: nlohmann::json, tl::expected, jwt-cpp, cpp-httplib -## REST API Pattern +## Handler Pattern (follow for ALL new handlers) -All endpoints are versioned under `/api/v1`. Route handlers are in [rest_server.cpp](src/ros2_medkit_gateway/src/rest_server.cpp). +Handlers live in `src/http/handlers/`, one file per group. All handlers take `HandlerContext&` in constructor. ```cpp -// Pattern for adding a new endpoint: -server_->Get(api_path("/your-endpoint").c_str(), - [this](const httplib::Request & req, httplib::Response & res) { - handle_your_endpoint(req, res); - }); +void ExampleHandlers::handle_request(const httplib::Request & req, httplib::Response & res) { + // 1. Extract entity ID from regex match + auto entity_id = req.matches[1].str(); + + // 2. Validate entity (sends error response automatically if invalid) + auto entity = ctx_.validate_entity_for_route(req, res, entity_id); + if (!entity) return; // Error already sent + + // 3. Check collection support (static method) + if (auto err = HandlerContext::validate_collection_access(*entity, ResourceCollection::DATA)) { + HandlerContext::send_error(res, 400, ERR_COLLECTION_NOT_SUPPORTED, *err); + return; + } + + // 4. Get fresh thread-safe cache + const auto & cache = ctx_.node()->get_thread_safe_cache(); + + // 5. Business logic (use tl::expected for errors) + auto result = some_operation(); + if (!result) { + HandlerContext::send_error(res, 503, ERR_SERVICE_UNAVAILABLE, result.error()); + return; + } + + // 6. Return JSON response + HandlerContext::send_json(res, json{{"items", *result}}); +} ``` -## Testing Patterns +### HandlerContext Key Methods -- **Unit tests**: GTest-based, see `test/test_gateway_node.cpp`, `test/test_operation_manager.cpp` -- **Integration tests**: Python launch tests using `launch_testing`, see `test/test_integration.test.py` -- **Demo nodes**: Automotive-themed test fixtures in `test/demo_nodes/` for integration testing -- **Requirements traceability**: Use `// @verifies REQ_XXX` comments in tests to link to requirements in docs +| Method | Returns | Purpose | +|--------|---------|---------| +| `validate_entity_for_route(req, res, id)` | `optional` | Unified entity validation, sends error if invalid | +| `validate_collection_access(entity, collection)` | `optional` | Check SOVD capability support | +| `send_error(res, status, code, msg, params)` | void | SOVD GenericError response | +| `send_json(res, data)` | void | JSON success response | +| `node()` | `GatewayNode*` | Access gateway subsystems | -## Test Coverage Requirements +### Error Codes -**All new features must have corresponding tests.** Coverage is tracked via Codecov and enforced in CI: -- Unit tests cover individual manager classes and utilities -- Integration tests verify end-to-end REST API behavior with demo nodes -- Coverage reports are generated on every PR and uploaded to Codecov on main branch merges +Defined in `include/ros2_medkit_gateway/http/error_codes.hpp`: -When adding a new endpoint or feature: -1. Add unit tests for the underlying logic -2. Add integration tests for the REST API endpoint -3. For spec-compliant endpoints, include `// @verifies REQ_XXX` comments linking to requirements +**SOVD standard**: `ERR_ENTITY_NOT_FOUND`, `ERR_INVALID_REQUEST`, `ERR_INVALID_PARAMETER`, `ERR_COLLECTION_NOT_SUPPORTED`, `ERR_RESOURCE_NOT_FOUND`, `ERR_OPERATION_NOT_FOUND`, `ERR_SERVICE_UNAVAILABLE`, `ERR_INTERNAL_ERROR`, `ERR_NOT_IMPLEMENTED`, `ERR_UNAUTHORIZED`, `ERR_FORBIDDEN` -## Key Dependencies +**Vendor-specific** (`x-medkit-` prefix): `ERR_X_MEDKIT_ROS2_SERVICE_UNAVAILABLE`, `ERR_X_MEDKIT_ROS2_NODE_UNAVAILABLE`, `ERR_X_MEDKIT_ROS2_TOPIC_UNAVAILABLE`, etc. -- **ROS 2 Jazzy** (Ubuntu 24.04) / **ROS 2 Humble** (Ubuntu 22.04) / **ROS 2 Rolling** (Ubuntu 24.04, best-effort) -- **cpp-httplib**: HTTP server (found via pkg-config) -- **nlohmann_json**: JSON serialization -- **yaml-cpp**: Configuration parsing +Error response schema: +```json +{ + "error_code": "entity-not-found", + "message": "Component not found", + "parameters": {"entity_id": "my_component"} +} +``` -## Documentation +### Route Registration + +Routes in `rest_server.cpp::setup_routes()`. Dual-path pattern - apps and components share handlers: -Sphinx-based docs in `docs/`. Uses sphinx-needs for requirements traceability. +```cpp +srv->Get((api_path("/apps") + R"(/([^/]+)/data$)"), + [this](auto & req, auto & res) { data_handlers_->handle_list_data(req, res); }); +srv->Get((api_path("/components") + R"(/([^/]+)/data$)"), + [this](auto & req, auto & res) { data_handlers_->handle_list_data(req, res); }); +``` -- `docs/design/`: Architecture and design decisions (PlantUML, RST) -- `src/ros2_medkit_gateway/design/`: Component-specific design docs (PlantUML, RST) -- `docs/requirements/`: SOVD specs and project requirements -- `postman/`: API collections for manual testing -- `src/ros2_medkit_gateway/README.md`: Package-level documentation +Handler classes: `HealthHandlers`, `DiscoveryHandlers`, `DataHandlers`, `OperationHandlers`, `ConfigHandlers`, `FaultHandlers`, `LogHandlers`, `AuthHandlers`, `BulkDataHandlers`, `CyclicSubscriptionHandlers`, `UpdateHandlers` + +## Build System + +**Static library pattern**: `gateway_lib` bundles all source for shared use between executable and tests. + +**CMake modules** in `cmake/`: +- `ROS2MedkitCcache.cmake` - auto-detect ccache +- `ROS2MedkitCompat.cmake` - multi-distro compatibility (`medkit_find_yaml_cpp()`, `medkit_find_cpp_httplib()`, `medkit_target_dependencies()`) +- `ROS2MedkitLinting.cmake` - centralized clang-tidy config + +New packages must include all three and use `medkit_*` helpers for dependencies. ```bash -# Build docs (uses .venv) -.venv/bin/sphinx-build -b html docs docs/_build/html +colcon build --symlink-install && source install/setup.bash +colcon test && colcon test-result --verbose +``` + +## Testing + +### Unit Tests (C++ GTest) + +Location: `src/ros2_medkit_gateway/test/test_*.cpp` + +```cpp +// @verifies REQ_INTEROP_061 +TEST_F(LogHandlersTest, GetLogsReturnsBadRequestWhenMatchesMissing) { + httplib::Request req; + httplib::Response res; + handlers_.handle_get_logs(req, res); + EXPECT_EQ(res.status, 400); + auto body = json::parse(res.body); + EXPECT_EQ(body["error_code"], ERR_INVALID_REQUEST); +} +``` + +**ROS_DOMAIN_ID isolation**: GTest targets creating `rclcpp::Node` need unique domain IDs. Current: 62-66 (fault_manager), 99 (gateway). Next available: 67. + +### Integration Tests (Python launch_testing) + +Location: `src/ros2_medkit_integration_tests/test/features/*.test.py` + +Base class: `GatewayTestCase` in `ros2_medkit_test_utils/gateway_test_case.py` -# Serve with auto-reload -.venv/bin/sphinx-autobuild --host 0.0.0.0 --port 8000 docs docs/_build/html +```python +class TestLoggingApi(GatewayTestCase): + MIN_EXPECTED_APPS = 1 + REQUIRED_APPS = {'temp_sensor'} + + # @verifies REQ_INTEROP_061 + def test_app_get_logs_returns_200(self): + data = self.get_json('/apps/temp_sensor/logs') + self.assertIn('items', data) ``` -**Keep documentation up to date**: When adding or modifying endpoints, update the corresponding docs in `docs/`, `src/ros2_medkit_gateway/design/`, `src/ros2_medkit_gateway/README.md`, and `postman/` collections. Ensure tests use `// @verifies REQ_XXX` comments to maintain traceability between requirements, implementation, and tests. +Demo nodes in `test/demo_nodes/`. Registry in `launch_helpers.py` maps short keys to executables. + +### Requirements Traceability + +Tag tests with `// @verifies REQ_XXX` (C++) or `# @verifies REQ_XXX` (Python). Place BEFORE the test definition or inside body. + +## Plugin Framework + +Plugins provide custom backends via provider interfaces: + +| Provider | Interface | Purpose | +|----------|-----------|---------| +| `LogProvider` | `providers/log_provider.hpp` | Custom log backends | +| `UpdateProvider` | `providers/update_provider.hpp` | Software update management | +| `IntrospectionProvider` | `providers/introspection_provider.hpp` | Custom entity introspection | + +Plugins loaded as `.so` files with `extern "C"` factory. Provider interfaces return typed C++ structs (not JSON) - manager layer handles serialization. Plugin failures are caught and isolated. + +## Key Dependencies + +- **cpp-httplib**: HTTP server (header-only, found via pkg-config or cmake) +- **nlohmann_json**: JSON serialization (header-only) +- **yaml-cpp**: Configuration parsing +- **tl::expected**: Error handling (header-only, vendored) +- **jwt-cpp**: JWT authentication (header-only, vendored) +- **OpenSSL**: TLS support + +## Code Review Rules + +When reviewing pull requests, apply these rules to the diff. Flag violations as review comments with a brief explanation of the correct pattern. + +### Thread Safety + +- **Flag** any code that stores the result of `get_thread_safe_cache()` in a member variable or passes it across function boundaries. The cache must be obtained fresh before each use within the current scope. +- **Flag** mutable shared state accessed without a mutex or atomic. +- **Flag** blocking operations (sleep, long loops, synchronous I/O) inside ROS 2 callbacks. + +### Error Handling -## Design Principles +- **Flag** `throw` statements in handler or manager code. Use `tl::expected` and return `tl::make_unexpected(msg)` instead. +- **Flag** dereferencing a `tl::expected` or `std::optional` result without checking `if (!result)` first. +- **Flag** error responses that don't use `HandlerContext::send_error()` or use string literals instead of constants from `error_codes.hpp`. +- **Flag** custom vendor error codes that don't start with `x-medkit-` prefix. +- **Flag** any code after `validate_entity_for_route()` that doesn't check for `nullopt` and return early - the error response is already sent by the validator. -- **Modularity & Separation of Concerns**: Separate core business logic from ROS 2 infrastructure and HTTP handling. Logic should be testable in isolation. -- **Dependency Injection**: Explicitly pass dependencies to components to facilitate testing and loose coupling. Avoid global state. -- **Thread Safety**: Ensure thread-safe access to shared resources, as the system handles concurrent ROS 2 callbacks and HTTP requests. -- **Standardized Interfaces**: Use consistent data models and serialization patterns across the application boundaries. +### Handler Pattern -## Error Handling Strategy +- **Flag** handlers that manually look up entities (e.g., calling `cache.get_component()` directly) instead of using `ctx_.validate_entity_for_route(req, res, entity_id)`. +- **Flag** handlers that access entity collections without calling `HandlerContext::validate_collection_access()` first. +- **Flag** handlers that call `ctx_.node()->get_thread_safe_cache()` at class construction or store the cache - it must be called per request. +- **Flag** new routes in `rest_server.cpp` that register only for `/apps/` or only for `/components/` when the endpoint applies to both entity types (dual-path pattern). +- **Flag** calling `res.set_header("Content-Type", ...)` after `set_chunked_content_provider()` - the content provider already sets the header, duplicating it breaks responses. + +### SOVD Compliance + +- **Flag** capability lists that don't match the entity type per Table 8. Use `EntityCapabilities::for_type()` to verify. +- **Flag** entity responses missing HATEOAS `_links` (use `LinksBuilder`) or capability arrays (use `CapabilityBuilder`). +- **Flag** error responses that don't follow the GenericError schema (`error_code`, `message`, optional `parameters`). + +### Testing + +Every code change must include corresponding tests. A feature without tests is not complete. + +**Unit tests (C++ GTest)** - required for all new logic: +- **Flag** new or modified files in `src/http/handlers/` without a corresponding `test/test_*_handlers.cpp` in the diff. Handler unit tests verify request validation, error responses, and edge cases without ROS 2 runtime. +- **Flag** new or modified manager classes (`src/*.cpp`) without corresponding `test/test_*.cpp`. Manager tests verify business logic in isolation. +- **Flag** new utility functions or static methods without unit tests covering their behavior. + +**Integration tests (Python launch_testing)** - required for all endpoint changes: +- **Flag** new or modified routes in `rest_server.cpp` without a corresponding integration test in `src/ros2_medkit_integration_tests/test/features/`. Integration tests verify end-to-end REST API behavior through the running gateway with demo nodes. +- **Flag** integration test classes that don't extend `GatewayTestCase` or don't set `REQUIRED_APPS`/`MIN_EXPECTED_APPS` for discovery waiting. +- **Flag** new endpoint tests that only check the happy path (200 OK). Tests should also verify error cases (404 for missing entity, 400 for invalid parameters). + +**General test rules:** +- **Flag** any use of `GTEST_SKIP()`, `@pytest.mark.skip`, `unittest.skip`, or equivalent - tests must not be skipped, fix the code or the test instead. +- **Flag** GTest files that create `rclcpp::Node` without setting a unique `ROS_DOMAIN_ID` in CMakeLists.txt `set_tests_properties()`. Current IDs: 62-66, 99. Next available: 67. +- **Flag** integration tests that select `/parameter_events` or `/rosout` topics - these are ROS 2 system topics without continuous data flow. +- **Flag** test files for SOVD-spec endpoints that are missing `// @verifies REQ_XXX` traceability tags. + +### Build & CMake + +- **Flag** new `.cpp` source files that aren't added to the `gateway_lib` STATIC library target in CMakeLists.txt. +- **Flag** new test targets that don't link to `gateway_lib`. +- **Flag** use of `ament_target_dependencies()` - use `medkit_target_dependencies()` instead (removed in Rolling). +- **Flag** direct `find_package(yaml-cpp)` or `find_package(httplib)` - use `medkit_find_yaml_cpp()` / `medkit_find_cpp_httplib()` for multi-distro compatibility. + +### Documentation + +- **Flag** PRs that add or modify REST endpoints but don't include changes to `docs/api/`. +- **Flag** PRs that change architecture or public interfaces without updating design docs in `docs/design/` or `src/ros2_medkit_gateway/design/`. +- **Flag** new files missing Apache 2.0 copyright header (year 2026) or `#pragma once` (headers). + +### Anti-Patterns Quick Reference + +| If you see this... | Flag it and suggest... | +|---|---| +| `auto & cache = node_->get_thread_safe_cache();` stored as member | Call `get_thread_safe_cache()` fresh per request | +| `throw std::runtime_error(...)` in handler/manager | Return `tl::make_unexpected("message")` | +| `cache.get_component(id)` in handler without validation | Use `ctx_.validate_entity_for_route(req, res, id)` | +| `ament_target_dependencies(target ...)` | Use `medkit_target_dependencies(target ...)` | +| `find_package(yaml-cpp REQUIRED)` | Use `medkit_find_yaml_cpp()` | +| `res.set_header("Content-Type", ...)` + `set_chunked_content_provider(...)` | Remove `set_header` - provider sets Content-Type | +| `GTEST_SKIP()` or `@pytest.mark.skip` | Fix the test or the code, never skip | +| `set_tests_properties(... ENVIRONMENT "ROS_DOMAIN_ID=99")` reusing existing ID | Assign next available ID (67) | +| New endpoint route for `/apps/` only | Add matching route for `/components/` (dual-path) | +| Error string literal like `"not-found"` | Use constant `ERR_ENTITY_NOT_FOUND` from `error_codes.hpp` | +| `res.status = 404; res.set_content(...)` manually | Use `HandlerContext::send_error(res, 404, ERR_ENTITY_NOT_FOUND, msg)` | + +## Documentation -- **Exceptions**: Use custom exceptions from `exceptions.hpp` for domain-specific errors. -- **API Responses**: REST handlers must catch exceptions and return appropriate HTTP status codes: - - `400 Bad Request`: Validation failures - - `404 Not Found`: Unknown components/areas - - `500 Internal Server Error`: Unexpected exceptions (log these with `RCLCPP_ERROR`) - - `503 Service Unavailable`: ROS 2 timeouts or communication failures +Sphinx-based docs in `docs/`. Published to GitHub Pages. -## Code Review Guidelines +- `docs/design/` - Architecture and design decisions (PlantUML, RST) +- `docs/requirements/` - SOVD specs and project requirements (sphinx-needs) +- `docs/api/` - REST API endpoint documentation +- `src/ros2_medkit_gateway/design/` - Package-level design docs +- `src/ros2_medkit_gateway/README.md` - Package overview and usage +- `postman/` - API collections for manual testing -- **Modern C++**: Prefer modern features and standard library over custom implementations. -- **ROS 2 Safety**: Ensure callbacks are non-blocking and thread-safe. -- **Resource Management**: Check for proper lifecycle management of nodes, threads, and HTTP clients. -- **API Consistency**: JSON responses must match `models.hpp` serialization patterns. -- **Error Handling**: Ensure exceptions are caught and mapped to appropriate HTTP status codes. -- **Documentation**: Verify public headers have comments and Sphinx docs are updated for new features. +**Documentation is part of every change, not a follow-up task.** User-facing docs (API reference, design docs, README) must be updated in the same PR as the code change. A feature is not complete until its documentation is shipped. -## Feature Workflow (Traceability) +When adding or modifying endpoints, features, or architectural components, update: +1. REST API docs in `docs/api/` (endpoint behavior, request/response schemas) +2. Design docs in `docs/design/` or `src/ros2_medkit_gateway/design/` if architecture changes +3. Package README if public interface changes +4. Postman collections if API surface changes +5. Requirements traceability - link tests to specs via `// @verifies REQ_XXX` -1. **Check Requirements**: For external API endpoints, check `docs/requirements/` for relevant interoperability specs. -2. **Define Interface**: Add header in `include/ros2_medkit_gateway/`. -3. **Implement Logic**: Add source in `src/` + Unit Test in `test/`. -4. **Implement API**: Add endpoint in `rest_server.cpp` + Integration Test. -5. **Verify**: If implementing a spec-defined endpoint, link the integration test to the requirement via `// @verifies REQ_XXX`. +## Discovery Modes -## Common Tasks +Configured in `gateway_params.yaml` under `discovery.mode`: -**Add a new REST endpoint**: Modify `rest_server.cpp` setup_routes(), add handler method -**Add a new manager class**: Create header in `include/ros2_medkit_gateway/`, source in `src/`, update `CMakeLists.txt` gateway_lib sources -**Add demo node for testing**: Create in `test/demo_nodes/`, add executable target in `CMakeLists.txt` +- **runtime_only** (default) - ROS 2 graph introspection, synthetic components by namespace +- **manifest_only** - YAML manifest entities only +- **hybrid** - Manifest as source of truth + runtime linking