Skip to content

fix(gateway): plugin-provided entities own their bulk data and logs - #560

Merged
mfaferek93 merged 6 commits into
mainfrom
fix/plugin-entity-bulk-data-v2
Jul 27, 2026
Merged

fix(gateway): plugin-provided entities own their bulk data and logs#560
mfaferek93 merged 6 commits into
mainfrom
fix/plugin-entity-bulk-data-v2

Conversation

@mfaferek93

Copy link
Copy Markdown
Collaborator

Closes #558.

Fault scoping and bulk-data scoping disagreed about what source an entity owns,
so a plugin-provided entity could not download the rosbag its own fault detail
advertised.

  • The per-app rule (external -> bare entity id, checked before effective_fqn())
    moves out of the anonymous namespace into faults::resolve_app_source_fqn, and
    both collect_app_fqn and HandlerContext::resolve_app_host_fqns use it, so
    there is one definition of the rule rather than two that drift.
  • compute_bulkdata_source_filters gains the two branches it was missing: an APP
    entity resolves through the same helper instead of falling through to an empty
    fqn, and an external COMPONENT owns its own id alongside its hosted apps -
    the same rule collect_component_app_fqns already applies for faults.

Logs go through the same resolver, so LogManager::get_logs is fixed with it.

Tests: ExternalAppResolvesToItsBareEntityId,
ExternalAppWithStrayBindingStillResolvesToItsId,
ComponentWithExternalAppsReturnsBareEntityIds, ExternalComponentAlsoOwnsItsOwnId.
Each fails on the pre-fix resolver. Full gateway suite: 4289 tests, 0 failures,
484 skipped; clang-format clean.

One behaviour change worth naming: a component that hosts external apps no longer
falls through to the fqn / namespace_path prefix filter, because that
fall-through only fires on an empty source set. That affects a manifest component
whose bags are sourced from a ROS namespace and which also hosts external apps.

…logs

resolve_app_host_fqns() only looked at effective_fqn(), so an external
plugin app resolved to nothing and the rosbag download plus log query
for its component matched no source. Share the fault-scope resolver so
both paths agree on what an app owns.
Copilot AI review requested due to automatic review settings July 26, 2026 15:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes inconsistent “entity -> reporting source” resolution between fault scoping and the HTTP-side bulk-data/log scoping so that plugin-provided (external) entities correctly “own” their rosbags and logs under their bare entity IDs.

Changes:

  • Extracted the external-app source resolution rule into faults::resolve_app_source_fqn() and reused it from HandlerContext and bulk-data scoping.
  • Extended bulk-data source filter computation to handle APP entities via the shared resolver, and to include an external component’s own ID alongside its hosted apps.
  • Added targeted unit tests covering external apps/components and their expected source filters.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/ros2_medkit_gateway/test/test_handler_context.cpp Adds tests ensuring external apps resolve to bare entity IDs in resolve_app_host_fqns.
src/ros2_medkit_gateway/test/test_bulkdata_handlers.cpp Adds tests validating bulk-data source filters for external apps/components.
src/ros2_medkit_gateway/src/http/handlers/handler_context.cpp Updates app-host source resolution to use faults::resolve_app_source_fqn().
src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp Updates bulk-data source filter computation for APP and external COMPONENT cases.
src/ros2_medkit_gateway/src/core/faults/fault_scope.cpp Introduces resolve_app_source_fqn() and reuses it in fault scoping.
src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/handler_context.hpp Updates documentation to describe source resolution semantics (external apps -> bare ID).
src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/faults/fault_scope.hpp Declares resolve_app_source_fqn() (note: header doc needs a small terminology update per review comment).
Comments suppressed due to low confidence (1)

src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/faults/fault_scope.hpp:40

  • The doc comment for resolve_entity_source_fqns still says it resolves “App effective-FQNs”, but APP resolution now goes through resolve_app_source_fqn() (external apps resolve to their bare entity id, and unbound non-external apps resolve to nothing). The header comment should match the actual semantics so callers don’t accidentally rely on “effective FQN only” behavior.
/// Resolve the set of App effective-FQNs that fall within an entity's scope by
/// walking the entity cache:
///   - APP: the app's own effective FQN
///   - COMPONENT: every hosted app's FQN
///   - AREA: every app under the area and its (recursive) subareas

Comment thread src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp Outdated
An external app has no ROS binding, so the fqn path produced no source filter
and the rosbag its own fault detail advertises answered "Bulk-data not found
for this entity" with the file on disk. External components have the same
hole for faults they report under their own id.
@mfaferek93
mfaferek93 force-pushed the fix/plugin-entity-bulk-data-v2 branch from e2e55da to d571e98 Compare July 26, 2026 20:27

@bburda bburda left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional findings outside the diff:

  • Could you also look at the APP branch in log_handlers.cpp (the last else)? It queries {entity.fqn}, which is "" for an external app, so GET /apps/<external_app>/logs returns nothing even though the entries are stored under the entity id. The logs claim in the description holds for functions, areas and components only.
  • Could you add the external component's own id in the COMPONENT branch there as well? Right now such a component owns its rosbags but not its logs.
  • Please check the cyclic subscription samplers in gateway_node.cpp. They still resolve with a raw effective_fqn() and use a private filter_faults_by_fqns, so a subscription on an external app returns "Entity no longer available" every cycle, and an external component gets an empty fault list.
  • Could you update the docs in this PR? docs/api/rest.rst says component logs query child apps "by exact FQN", and bulkdata_handlers.hpp still documents the old APP and COMPONENT behaviour of the function you changed.
  • Would you mind adding an integration test for the reported 404? test_external_app_fault_rollup.test.py and external_app_fault_manifest.yaml already set up an external app, so reporting a fault there and downloading the advertised bulk_data_uri would cover it.

Comment thread src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp Outdated
Comment thread src/ros2_medkit_gateway/src/http/handlers/handler_context.cpp
@mfaferek93 mfaferek93 self-assigned this Jul 27, 2026
Comment thread src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp Outdated
Comment thread src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp Outdated
…rule

Every entity type now computes its rosbag source filters via
resolve_entity_source_fqns, so AREA recurses subareas and FUNCTION follows
component hosts instead of 404ing bags their fault lists advertise. The
download ownership check reads the fault once and tests it with the
boundary-aware matcher, closing the prefix hole between sibling ids.
New logs::query_entity_logs resolves exact sources via the fault-scope rule
(external app bare id, external component own id) and merges the namespace
prefix query for COMPONENT/AREA, so hosting an external app no longer drops
namespace node logs. The faults and logs samplers route through the shared
resolvers; the private fault filter copy in gateway_node is gone.
Publish a capture topic so a real bag is flushed when the external app's
fault confirms, then assert the app download and the area-advertised
bulk_data_uri return 200 with bytes, plus area and function listings.
Fails against the namespace-path area scope with an empty area listing.
The namespace query now merges with resolved sources instead of
acting as a fallback; say so where the endpoint list summarises it.
@mfaferek93

Copy link
Copy Markdown
Collaborator Author

The outside-diff findings, all on the branch now:

  • App logs resolve through the shared rule (bare id for external apps), with the exact-fqn fallback kept when the resolver yields nothing - 7669b29.
  • The external component's own id is in the log scope, and component/area logs merge the namespace query instead of losing it.
  • Both cyclic samplers use the shared resolvers plus faults::filter_faults_by_sources; the private filter_faults_by_fqns copy is deleted. A cyclic subscription on an external app now returns the fault list instead of 'Entity no longer available'.
  • rest.rst, bulkdata_handlers.hpp and fault_scope.hpp describe the one rule.
  • test_external_app_fault_rollup.test.py now captures a real bag and downloads every advertised URI (app, area, function) - the area assert fails on the pre-fix binary.

Agreed on the last note: the namespace filter never matched an app source in the listing, so the visible change is only the stricter download check.

@mfaferek93
mfaferek93 merged commit 33d53ee into main Jul 27, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gateway: bulk-data and logs 404 for plugin-provided entities

3 participants