Skip to content

RSDK-14642: composite engine — server-side resolution & advertisement (1/5) - #6539

Open
Daniel Botros (danielbotros) wants to merge 12 commits into
composable-apis-assub-rolloutfrom
composable-apis-p3a-server-core
Open

Daniel Botros (danielbotros) wants to merge 12 commits into
composable-apis-assub-rolloutfrom
composable-apis-p3a-server-core

Conversation

@danielbotros

@danielbotros Daniel Botros (danielbotros) commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

RSDK-14642 — PR 1/5 of the Composable APIs server-side work (epic RSDK-14329). Stacked on #6521.

The in-process engine that makes a composite resolvable and advertised on one machine. It consumes the graph machinery from #6520 (the single-node model + compositeByAPI index) and wires it into the robot's resolution, dependency, lifecycle, and advertisement paths. Three files:

local_robot.go — resolution, dependencies, lifecycle

  • Resolution. ResourceByName splits on whether the lookup carries an API. An API-qualified lookup goes to FindBySimpleNameAndAPI, which fetches the graph node and unwraps it to that API's sub-resource (SubresourceForAPI) — so an in-process consumer that type-asserts sees the real typed instance, not the multi-API wrapper. An api-less (bare SimpleName) lookup goes to resourceBySimpleName → resolveSimpleNameMatch: a local composite is already one graph node, so it returns that whole multi-API handle; a remote composite arrives as one per-API sub-client node per co-equal API, so it assembles a MultiAPIResource view over those sub-clients. A genuine same-name collision across distinct resources still errors — the dedup only ever collapses one composite.
  • Dependencies. A composite dependency is keyed in a dependent's Dependencies under each of its co-equal API names (coequalAPIsOf reports the set — from APIsOf for a modular composite, or the node's model for a builtin one), so a consumer resolves it by whichever API it expects. The weak-dependency matcher scan likewise runs per served API and stores the unwrapped sub under each, so a weak-dep consumer (e.g. data capture) gets a typed sub rather than the wrapper.
  • Lifecycle. StopAll dedups on the raw pre-unwrap node, so a composite advertised under N actuator APIs is stopped exactly once.
  • Status. MachineStatus fills cloud metadata for a remote composite's non-canonical API rows (findRemoteMetadataByName).

resource_manager.go — advertisement, in-place reconfigure

AllNonCollidingResourceNames expands each composite to its per-API names for advertisement (ExpandCompositeNames), and updateRemoteResourceNames exempts a remote composite's own co-equal siblings from the collision check (same-remote exemption), so a composite isn't torn down as a self-collision.

A model-only reconfigure swaps a resource in place (gNode.SwapResource) and keeps the same graph node, bypassing the set/rename paths that maintain compositeByAPI — so after a composite changed models its co-equal index would still point at the old API set and the new non-canonical APIs would stop resolving. ReindexComposite (added to resource.Graph in #6520's helper) is now called right after the in-place swap, re-running the index so the composite resolves under its current co-equal APIs.

robot.go

ResourceFromRobot unwraps via resource.AsType, so <pkg>.FromProvider(robot, name) returns the typed sub of a composite; the LocalRobot.FindBySimpleNameAndAPI interface doc states that unwrap contract.

Testing

robot/impl/multiapi_composite_test.go — in-process + remote end-to-end suite: api-less + per-API resolution with close-once, dependency aliasing, genuine simple-name collision handling (local and remote, incl. cross-API), remote composites (direct, prefixed, nested — one table-driven test), in-process typed lookup (the MultiAPIResource unwrap), StopAll dedup, and frame-system membership. TestCompositeModelReconfigureReindexes covers the in-place model-reconfigure case end to end: a resource reconfigured from a single-API model to a composite model resolves under its new co-equal API. A graph-level unit test for ReindexComposite lives in #6520's resource_graph_test.go.

🤖 Generated with Claude Code

@danielbotros
Daniel Botros (danielbotros) added this pull request to stack #6544 September 24, 2026 21:18
@danielbotros
Daniel Botros (danielbotros) removed this pull request from stack #6544 September 24, 2026 21:32
@danielbotros
Daniel Botros (danielbotros) added this pull request to stack #6545 September 24, 2026 21:32
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 24, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 24, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 24, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 24, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 25, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 25, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 25, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 25, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 25, 2026
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Sep 25, 2026
@viambot viambot removed the safe to test This pull request is marked safe to test from a trusted zone label Sep 25, 2026
robot/impl server-side: local_robot resolution (api-less resourceBySimpleName /
resolveSimpleNameMatch, specific-API unwrap, StopAll dedup, weak-dep + dependency
composite-aliasing, MachineStatus metadata), resource_manager advertisement
(ExpandCompositeNames, remote-collision skip, remote metadata), and
ResourceFromRobot unwrap. Consumes the resource-graph remote-composite machinery
from the core PR. First of the ticket-3 split.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 202fdae)
…onfigure

An in-place model rebuild swaps a new resource onto the existing graph node
without passing through Set/UpdateSimpleName, so the compositeByAPI index was
never refreshed. Growing a composite's served API set left the new co-equal API
unresolvable (FindBySimpleNameAndAPI 404), and shrinking it left a dropped API
resolving to a node that no longer serves it.

Add Graph.ReindexComposite and call it after the in-place SwapResource in the
resource manager. Covered by a graph unit test (grow+shrink) and a robot e2e
that reconfigures a resource from a single-API model to a composite model and
asserts the newly-served API resolves.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit d9d62d8)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tem test to p3e-consumers; rename Modular->Composite in-process test

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The weak-dep matcher runs against each API a composite serves, not only the
one its Name() carries. Reword the comment so it no longer implies that API is
canonical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Name a composite's node logger composite/<name> via resource.LogName so its logs
are not filed under a single co-equal API, and derive the per-resource log-level
pattern the same way so log_configuration still matches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A composite is one graph node reached under each of its co-equal API names, so it
appears in AllNonCollidingResourceNames once per API. SubsByName already fans every
served sub in a single pass, so dedupe on the resolved node rather than re-fanning it
per alias.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… sub

A weak-dependency matcher wired a composite in as the already-unwrapped sub for each
matched API, leaving a weak-dep consumer with a single-API resource. Store the wrapper
instead; both weak-dep consumers (data capture and motion) unwrap with
resource.SubresourceForAPI, and composite data capture needs the full co-equal set to
resolve a method to its owning API. An ordinary resource is its own only sub.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test This pull request is marked safe to test from a trusted zone

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants