Bug report
Steps to reproduce
- Run the gateway with
discovery.mode: hybrid and a protocol plugin that introspects an external App with an empty effective_fqn (e.g. the OPC-UA plugin's process App).
- Declare a manifest Function whose
hosted_by lists that App id.
- Report a fault to the fault_manager with
source_id = the App id.
GET /functions/<id>/faults.
Expected behavior
The fault rolls up into the Function (the external+empty-fqn rule in collect_app_fqn() grants the App its own id as fault-scope owner). This is exactly what happens under discovery.mode: manifest_only.
Actual behavior
Empty items - under hybrid the merged entity cache holds the App with external=false, so the external rule never fires and the host contributes no fqn. The fault silently vanishes from the rollup.
Suspected mechanism: src/ros2_medkit_gateway/src/discovery/merge_pipeline.cpp, METADATA group - external merges with scalar semantics, so when the target layer wins the plugin's external=true is discarded (target default false). The comment says "external is a classification, not a status flag", but the hybrid merge does not preserve the classification.
Environment
- ros2_medkit version: main (0d637f6)
- ROS 2 distro: Jazzy
- OS: Ubuntu 24.04
Additional information
Test-coverage gap that would have caught this: fa05ad8 ("surface external plugin-entity faults") added external-app fault-scope regressions for the APP and COMPONENT routes but not for FUNCTION-hosts-external-app. Worth adding that regression alongside the fix.
Bug report
Steps to reproduce
discovery.mode: hybridand a protocol plugin that introspects an external App with an emptyeffective_fqn(e.g. the OPC-UA plugin's process App).hosted_bylists that App id.source_id= the App id.GET /functions/<id>/faults.Expected behavior
The fault rolls up into the Function (the external+empty-fqn rule in
collect_app_fqn()grants the App its own id as fault-scope owner). This is exactly what happens underdiscovery.mode: manifest_only.Actual behavior
Empty
items- under hybrid the merged entity cache holds the App withexternal=false, so the external rule never fires and the host contributes no fqn. The fault silently vanishes from the rollup.Suspected mechanism:
src/ros2_medkit_gateway/src/discovery/merge_pipeline.cpp, METADATA group -externalmerges with scalar semantics, so when the target layer wins the plugin'sexternal=trueis discarded (target defaultfalse). The comment says "external is a classification, not a status flag", but the hybrid merge does not preserve the classification.Environment
Additional information
Test-coverage gap that would have caught this: fa05ad8 ("surface external plugin-entity faults") added external-app fault-scope regressions for the APP and COMPONENT routes but not for FUNCTION-hosts-external-app. Worth adding that regression alongside the fix.