Skip to content

IPubSub's contract docblock states a delivery guarantee no shipped driver provides ("At-least-once delivery") #12651

Description

@os-warren

Found while building the authz.invalidated channel for #11968 (PR on claude/issue-11968-authz-cache-substrate). Filed unassigned, no repair attempted there — it is a packages/spec change and out of that card's scope.

The contradiction, measured on origin/main

packages/spec/src/contracts/cluster-service.ts:73, the docblock on the IPubSub interface itself:

Fan-out messaging primitive. At-least-once delivery; handlers MUST be idempotent. The memory driver delivers synchronously within a process; remote drivers (redis pub/sub, postgres LISTEN/NOTIFY, nats) deliver across nodes.

content/docs/kernel/cluster.mdx §4.2, on the same at-least-once value:

No shipped driver provides this yet. The redis driver publishes over plain Redis pub/sub, which is at-most-once — fire-and-forget, no persistence, no replay for a node that was down at publish time.

And @objectstack/service-cluster-redis's own publish docblock says the same in its own words: at-most-once, "acceptable only for events that are pure cache-invalidation hints, never the source of truth." The memory driver does not cross a process boundary at all.

So the two statements disagree, and the one on the interface — the place a consumer reads before writing a subscriber — is the one that is wrong. cluster.mdx §4.2 and the driver docblocks are the measured statements.

Why this is worth a card rather than a shrug

The interface docblock is the load-bearing one for the failure mode it invites. A consumer that reads "At-least-once delivery; handlers MUST be idempotent" reasonably concludes that a message will arrive and that its only obligation is to tolerate duplicates. The actual transport's failure mode is the opposite — a lost message, with no replay and no upper bound on how long a node stays wrong. An author who designs for duplicates and not for loss has designed for the wrong hazard, and nothing in the type or the tests contradicts them.

Two things narrow the blast radius today and neither closes it:

Suggested shape (not a decision — this is a spec-seat call)

Correct the IPubSub docblock to state the shipped guarantee (at-most-once; a missed message is expected; handlers must be idempotent and tolerate loss), and point at deliverySemantics for the per-channel declaration. Whether the interface should say "at-most-once" flatly or "whatever the driver declares, and no shipped driver exceeds at-most-once" is the question worth answering deliberately, because the second phrasing keeps the door open for a durable driver without re-writing the contract when one lands.

Anything stronger — a declared per-driver guarantee the type system can read, or refusing an at-least-once channel declaration at boot while no driver can honour it — is a larger design question and deliberately not proposed here.

Not in scope of this report

Whether any existing consumer of IPubSub was written against the wrong guarantee. Only metadata.changed and (with #11968) authz.invalidated are in production use, and both are cache-invalidation hints, which is the one thing the transport is documented as acceptable for. A sweep of subscribers is a separate task if someone wants it.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions