Part of the node-message-broker build-out (Track B, Hub Plan 013 Phase 4). See .agents/plans/001-message-broker.md (local working doc).
Goal: the SDK-compatible send/participants surface (extend the existing messages controller). Keep the exact surface so flamesdk needs no change.
Steps
POST /analyses/:id/messages { recipients: [nodeId], message } and …/broadcast: assertMayUse (S3) → resolve participants (S2) → encrypt per recipient (S1; one Hub send per recipient since each is sealed under a distinct key) → HubClient.send with metadata.analysisId. Return 202.
GET /analyses/:id/participants and …/participants/self → { nodeId, nodeType } (SDK addresses by nodeId; broker maps to client_id), proxied + cached.
GET /analyses/:id/messages (pull) — additive, future polling SDK; unused today.
Depends on: S1, S2, S3.
Acceptance: policy-denied → 403; send fans out one sealed Hub send per resolved recipient; participants shape matches the SDK.
Part of the node-message-broker build-out (Track B, Hub Plan 013 Phase 4). See .agents/plans/001-message-broker.md (local working doc).
Goal: the SDK-compatible send/participants surface (extend the existing messages controller). Keep the exact surface so
flamesdkneeds no change.Steps
POST /analyses/:id/messages { recipients: [nodeId], message }and…/broadcast:assertMayUse(S3) → resolve participants (S2) → encrypt per recipient (S1; one Hubsendper recipient since each is sealed under a distinct key) →HubClient.sendwithmetadata.analysisId. Return 202.GET /analyses/:id/participantsand…/participants/self→{ nodeId, nodeType }(SDK addresses by nodeId; broker maps to client_id), proxied + cached.GET /analyses/:id/messages(pull) — additive, future polling SDK; unused today.Depends on: S1, S2, S3.
Acceptance: policy-denied → 403; send fans out one sealed Hub
sendper resolved recipient; participants shape matches the SDK.