Skip to content

feat(subscribe): add sourcePolicy and excludeSources to subscribe message#679

Open
dirkwa wants to merge 1 commit into
SignalK:masterfrom
dirkwa:feat-subscribe-source-policy-exclude
Open

feat(subscribe): add sourcePolicy and excludeSources to subscribe message#679
dirkwa wants to merge 1 commit into
SignalK:masterfrom
dirkwa:feat-subscribe-source-policy-exclude

Conversation

@dirkwa
Copy link
Copy Markdown

@dirkwa dirkwa commented May 30, 2026

Motivation

Closes #678 — follow-up to SignalK/signalk-server#2688.

The subscribe schema is silent on how a client controls source selection when a path has multiple producers. Server implementations (and the Node server specifically, as of #2688) support it; the spec needs to catch up so other clients and servers can interop on a documented contract.

The concrete gap: a derived-data plugin that publishes on the same path it consumes cannot benefit from source priority today. Under sourcePolicy: 'preferred' it would see its own output and feed back on itself; under 'all' it loses the user's priority cascade across the upstream sources.

What this PR adds

Two top-level fields on SubscribeMessage:

  • sourcePolicy ("preferred" | "all", default "preferred") — selects whether each subscribed path delivers a single priority-resolved value or every source unranked. Applies to every row in the message and to the bootstrap snapshot the server replays on subscribe.
  • excludeSources (array of $source refs) — drops the listed sources from the priority cascade's candidate set. The subscription still delivers a single priority-resolved value per path; the cascade just runs without the excluded sources, with the configured fallback timeouts honoured. Effective only under sourcePolicy: 'preferred'; ignored under 'all'.

The canonical use case for excludeSources is the derived-data plugin: with user ranking myPlugin > sourceB > sourceA, a subscription with excludeSources: ["myPlugin"] receives sourceB while it publishes, falls back to sourceA past sourceB's timeout, returns to sourceB when it resumes, and never sees myPlugin even though it ranks highest.

What this PR does not add

excludeSelf is a plugin-API shorthand only — the server resolves it to the plugin's id, which has no analogue on a WebSocket/TCP wire. The Node server exposes it on its in-process subscribe API; documentation calls it out as plugin-API-only and points wire clients at excludeSources. It is not added to the schema (would be misleading on the wire) and not added as a query parameter (same reason).

Changes

  • schemas/messages/subscribe.jsonsourcePolicy (string + enum) and excludeSources (array of strings) added as top-level optional properties.
  • mdbook/src/subscription_protocol.md — new "Source selection" section with both fields, the cascade-fallback example and the plugin-shorthand note.
  • mdbook/src/streaming_api.md — short note that servers MAY accept ?sourcePolicy=... as a connection default.
  • samples/subscribe/docs-subscription_protocol-excludeSources.json — the example referenced from the new prose, validated by the subscribe sample tests.
  • test/data/subscribe-valid/ — three new valid samples (preferred, all, excludeSources).
  • test/data/subscribe-invalid/ — one new invalid sample (sourcePolicy: "bogus") to lock in the enum.

Tested

  • npm test — 212 passing (was 207). The five new samples are picked up by the existing valid/invalid harnesses; the negative case confirms tv4 enforces the sourcePolicy enum.
  • node -e 'JSON.parse(...)' smoke check on subscribe.json.

…sage

The subscribe schema was silent on how a client controls source
selection when a path has multiple producers, leaving the
implementations that do support it without spec coverage.

Adds two top-level fields to SubscribeMessage:

- sourcePolicy ("preferred" | "all", default "preferred") — selects
  whether the subscription receives a single priority-resolved value
  per path or every source unranked.
- excludeSources (array of $source refs) — drops the listed sources
  from the priority cascade's candidate set, so a derived-data plugin
  that publishes on the same path it consumes can apply the user's
  source ranking across the upstream sources without seeing its own
  output.

Updates the Subscription Protocol doc with a Source selection section
covering both fields and the canonical excludeSources use case, and
notes the matching ?sourcePolicy=... query parameter in the Streaming
API doc.

Plugin-API implementations MAY offer a plugin-only shorthand for
self-exclusion (the Node server exposes excludeSelf:true). The
shorthand is plugin-API only; WebSocket and TCP clients use the
explicit excludeSources form, so it is described in prose without a
schema field.

Follows up signalk-server#2688.
Closes SignalK#678.
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.

FOLLOW-UP: Add the missing gap

1 participant