Skip to content

Decouple local client subscriptions from network subscriptions #2075

@sanity

Description

@sanity

Problem

Currently, local client application subscriptions and network-wide subscriptions are conflated in the operations layer (particularly in crates/core/src/operations/subscribe.rs and crates/core/src/operations/update.rs), leading to increased coupling between the transport/websocket layer and the logical network operations.

As noted by @iduartgomez in #2064:

I think fundamentally there is a problem with conflating network subscriptions and local client application subscriptions. IMO we should distinguish them and handle them differently via different flows (e.g. sending internal event notifications for local ones)

This problem has been permeating across multiple bug fixes and changes and looks like we should address the root cause instead of keep working around it.

And in the general PR comment:

Taking an overall look at the PR I think we have successfully managed to couple local subscriptions/updates to network subscriptions/updates, which is ... NOT good. The goal long-term would be to separate them absolutely, we shouldn't have to worry about local connections inside ops/ module neither viceversa at the websocket/contract layer.

Current Architecture Issues

  1. Mixed concerns in operations layer: The ops/ module handles both network-wide subscription propagation and local client subscriptions in the same code paths.
  2. Websocket/contract layer coupling: The websocket and contract handlers need to understand network operation semantics, when ideally they should be isolated.
  3. Complex workarounds: Bug fixes have increasingly added workarounds to handle the coupling (e.g., the allow_self logic in update.rs:690-716 to handle local auto-subscribes during UPDATE propagation).
  4. Handshake handler bypass: This stack "has nuked" the handshake handler's role in isolating logically-connected peers from those that are not, further eroding architectural boundaries.

Proposed Solution

Separate local and network subscriptions into distinct flows:

  1. Network subscriptions handled entirely in ops/, concerned only with peer-to-peer subscription tree maintenance and routing.
  2. Local subscriptions managed via internal event notifications isolated to the websocket/contract layer without involving network operations.
  3. Clear boundaries so ops/ no longer needs to know about local client connections and the websocket/contract layer does not need network routing details.
  4. Restore handshake isolation so the handshake handler once again separates transport-level connections from logical network membership.

Benefits

  • Simpler reasoning about subscription behavior
  • Easier debugging (separate traces for local vs network events)
  • Reduced coupling between layers
  • Fewer edge cases and workarounds
  • Better long-term maintainability

References

Priority

High — this architectural coupling is creating recurring bugs and costly workarounds, so we should address it soon after #2064 merges.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-contractsArea: Contract runtime, SDK, and executionA-networkingArea: Networking, ring protocol, peer discoveryE-hardExperience needed to fix/implement: Hard / a lotP-highHigh priorityS-needs-designStatus: Needs architectural design or RFCT-enhancementType: Improvement to existing functionality

    Type

    No type

    Projects

    Status

    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions