Skip to content

feat(node-message-broker): resolve analysis participants via server-core#12

Merged
tada5hi merged 2 commits into
masterfrom
feat/participant-resolver
Jun 25, 2026
Merged

feat(node-message-broker): resolve analysis participants via server-core#12
tada5hi merged 2 commits into
masterfrom
feat/participant-resolver

Conversation

@tada5hi

@tada5hi tada5hi commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Slice S2 of the node message-broker build-out (Plan 013 Track B). Resolves which node clients participate in an analysis — and their ECDH public keys — from server-core, so the send (S5) and inbound-delivery (S6) flows can address and encrypt to peers.

What's here

  • core/analysisIAnalysisNodeProvider port (list(analysisId) → CoreNode[]) + CoreNode. AnalysisParticipant now carries the node's publicKey (consumed by S1's CryptoService).
  • adapters/coreParticipantResolver: maps server-core analysis-node entries → AnalysisParticipant, skips any participant missing a client_id or public_key (can't be addressed/encrypted to), and caches per analysis behind a short-TTL LRU to keep resolution off the Hub hot path. resolveSelf returns the entry matching this node's own client id.
  • app/modules/core-clientCoreClientModule wires a @privateaim/core-http-kit client (node-client credentials, mirroring the Hub link) behind the provider port and registers the resolver. Adds the @privateaim/core-http-kit dependency.

Design note

The resolver depends on the narrow IAnalysisNodeProvider, not the whole core client. The real client's analysisNode.getMany signature uses rapiq's BuildInput generics, which don't mimic cleanly as a structural fake-able interface — so the rapiq query (getMany({ filter: { analysis_id }, include: ['node'] })) lives at the module wiring site, and the resolver's logic stays unit-testable with a trivial fake provider. This also keeps rapiq's query shapes out of the domain.

Tests (8 resolver specs; 41 project-wide, all green)

Field mapping; skipping incomplete participants; resolveSelf hit/miss; unknown analysis → empty; per-analysis cache hit; failed resolution not cached; caching disabled.

Scope boundaries

  • No analysis policy yet (S3) and no send/deliver wiring (S5/S6) — the resolver is registered, ready to consume.

Closes #5

Summary by CodeRabbit

  • New Features

    • Added support for resolving analysis participants from core data, including participant IDs, client IDs, and public keys.
    • Added a new built-in core client integration for the message broker, with automatic setup during application startup.
    • Improved participant lookups with caching and a way to identify the current participant in an analysis.
  • Bug Fixes

    • Skips incomplete participant records and avoids keeping failed lookups cached.

Slice S2 of the node message-broker build-out (Plan 013 Track B): resolve which
node clients participate in an analysis (and their public keys) from server-core,
so the send/deliver flows can address and encrypt to peers.

- core/analysis: IAnalysisNodeProvider port + CoreNode; AnalysisParticipant now
  carries the node's ECDH publicKey.
- adapters/core: ParticipantResolver maps analysis-node entries to participants,
  skips ones missing a client id / public key, and caches per analysis behind a
  short-TTL LRU (off the Hub hot path); resolveSelf matches this node's client id.
- app/modules/core-client: CoreClientModule wires a @privateaim/core-http-kit
  client (node-client credentials, mirroring the Hub link) behind the provider
  port and registers the resolver. Adds the core-http-kit dependency.
- The resolver depends on the narrow IAnalysisNodeProvider (not the whole core
  client) so it stays unit-testable with a fake; the rapiq getMany query lives at
  the wiring site.

Closes #5
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR extends analysis participant types, adds a cached participant resolver, introduces a core-client module that wires the HTTP client into the container, and updates application bootstrap and tests.

Changes

Server-core participant resolution and wiring

Layer / File(s) Summary
Shared analysis contracts and resolver
apps/node-message-broker/src/core/analysis/types.ts, apps/node-message-broker/src/adapters/core/*
AnalysisParticipant gains publicKey, CoreNode and IAnalysisNodeProvider are added, and ParticipantResolver maps provider nodes into participants with caching and resolveSelf.
Resolver tests and fake provider
apps/node-message-broker/test/unit/adapters/core/*
FakeAnalysisNodeProvider records lookups and the resolver tests cover mapping, filtering, resolveSelf, unknown analyses, cache reuse, rejection eviction, and disabled caching.
Core client module and app wiring
apps/node-message-broker/package.json, apps/node-message-broker/src/app/modules/core-client/*, apps/node-message-broker/src/app/builder.ts, apps/node-message-broker/src/app/factory.ts
@privateaim/core-http-kit is added, CoreClientModule and CoreClientInjectionKey are introduced, the module creates the core HTTP client and registers ParticipantResolver, and the app builder/factory include the new module slot.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant ParticipantResolver
  participant IAnalysisNodeProvider
  participant CoreHttpKitClient

  Caller->>ParticipantResolver: resolve(analysisId)
  alt cache hit
    ParticipantResolver-->>Caller: cached AnalysisParticipant[]
  else cache miss
    ParticipantResolver->>IAnalysisNodeProvider: list(analysisId)
    IAnalysisNodeProvider->>CoreHttpKitClient: analysisNode.getMany({ analysis_id })
    CoreHttpKitClient-->>IAnalysisNodeProvider: CoreNode[]
    IAnalysisNodeProvider-->>ParticipantResolver: CoreNode[]
    ParticipantResolver-->>Caller: AnalysisParticipant[]
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Poem

I hopped through the broker, ears aloft,
Found public keys tucked in the nodes so soft.
With one neat cache and a core-client spin,
The rabbit says: let the resolves begin! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: resolving analysis participants from server-core in node-message-broker.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/participant-resolver

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@tada5hi

tada5hi commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/node-message-broker/src/app/modules/core-client/module.ts (1)

27-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Verify module ordering guarantees the logger is set up before coreClient.

dependencies only declares 'config', yet setup also reads LoggerInjectionKey. The tryResolve makes the logger optional, so this won't crash, but if orkos reorders modules by declared dependencies (rather than builder insertion order), coreClient could initialize before the logger and silently lose participant-skip warnings. Confirm ordering or add 'logger' to dependencies if those warnings matter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/node-message-broker/src/app/modules/core-client/module.ts` around lines
27 - 45, The CoreClientModule setup reads LoggerInjectionKey but only declares
config as a dependency, so module ordering may allow coreClient to initialize
before the logger and drop warnings. Update CoreClientModule.dependencies to
include logger if those participant-skip warnings must always be available, or
otherwise ensure the module ordering guarantees logger is registered before
CoreClientModule.setup runs; keep the logger lookup via tryResolve in sync with
that ordering choice.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/node-message-broker/src/app/modules/core-client/module.ts`:
- Around line 56-64: The provider.list implementation in module.ts currently
returns entry.node directly, which can let undefined nodes flow into
ParticipantResolver.fetch and crash on node.client_id. Update the mapping in
provider.list to guard at the boundary by filtering out any entries without a
node before returning the list, so only valid node objects are passed
downstream.

---

Nitpick comments:
In `@apps/node-message-broker/src/app/modules/core-client/module.ts`:
- Around line 27-45: The CoreClientModule setup reads LoggerInjectionKey but
only declares config as a dependency, so module ordering may allow coreClient to
initialize before the logger and drop warnings. Update
CoreClientModule.dependencies to include logger if those participant-skip
warnings must always be available, or otherwise ensure the module ordering
guarantees logger is registered before CoreClientModule.setup runs; keep the
logger lookup via tryResolve in sync with that ordering choice.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 56f90383-c967-4c40-8bbb-8ed501285a8e

📥 Commits

Reviewing files that changed from the base of the PR and between 9ab037d and 6b37aad.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • apps/node-message-broker/package.json
  • apps/node-message-broker/src/adapters/core/index.ts
  • apps/node-message-broker/src/adapters/core/participant-resolver.ts
  • apps/node-message-broker/src/app/builder.ts
  • apps/node-message-broker/src/app/factory.ts
  • apps/node-message-broker/src/app/modules/core-client/constants.ts
  • apps/node-message-broker/src/app/modules/core-client/index.ts
  • apps/node-message-broker/src/app/modules/core-client/module.ts
  • apps/node-message-broker/src/core/analysis/types.ts
  • apps/node-message-broker/test/unit/adapters/core/fake-analysis-node-provider.ts
  • apps/node-message-broker/test/unit/adapters/core/participant-resolver.spec.ts

Comment thread apps/node-message-broker/src/app/modules/core-client/module.ts
@tada5hi

tada5hi commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai pause

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

…elation

server-core types AnalysisNode.node as non-null, but may omit the relation when
`include` is not honored or data is incomplete; filter those out at the provider
boundary so ParticipantResolver never dereferences an undefined node.
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.

S2 — server-core client + participant resolver

1 participant