Uh oh!
There was an error while loading. Please reload this page.
docs(spec): state IPubSub's real delivery guarantee on the contract docblock (#12651) - #12837
Merged
Merged
Conversation
…ocblock
The IPubSub docblock claimed "At-least-once delivery; handlers MUST be
idempotent". No shipped driver provides that, and the repo's own measured
statements said so elsewhere: content/docs/kernel/cluster.mdx 4.2 ("No shipped
driver provides this yet."), service-cluster-redis's publish docblock
(at-most-once, fire-and-forget, no persistence), and the authz.invalidated
channel module in @objectstack/core, which recorded the contradiction inline
rather than resolving it in the wrong direction.
The interface docblock is the load-bearing one for the hazard it invites: it is
what a consumer's editor shows at the call site. "At-least-once" tells that
author their only obligation is to tolerate duplicates, while the transport's
actual failure mode is a LOST message with no replay and no upper bound on how
long a node that was down at publish time stays wrong.
State it driver-relatively instead -- delivery is whatever the configured driver
declares, and no shipped driver exceeds at-most-once -- so a future durable
driver lands without rewriting the contract. A missed message is expected;
handlers must be idempotent AND loss-tolerant; the staleness bound lives outside
the bus; deliverySemantics is named as the per-channel surface, along with what
it is (what a channel asks for, not what it gets). The driver-reach sentence is
unchanged -- it was never part of the false claim.
Prose only: no schema, no type, no accept/reject behaviour change.
Co-authored-by: Claude <noreply@anthropic.com>…ubsub-delivery-docblock
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Aug 28, 2026
os-sales
marked this pull request as ready for review
August 28, 2026 04:32
os-sales
enabled auto-merge
August 28, 2026 04:32
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#12651
The
IPubSubcontract docblock claimed a delivery guarantee no shipped driver provides, on the one surface a consumer reads before writing a subscriber.The contradiction, as it stood
packages/spec/src/contracts/cluster-service.ts:73said:Three measured statements in this repo disagreed with it, and they agree with each other:
content/docs/kernel/cluster.mdx§4.2, on theat-least-oncevalue: "No shipped driver provides this yet. Theredisdriver 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."@objectstack/service-cluster-redis'spublishdocblock: at-most-once, no delivery guarantee to subscribers, no replay — "acceptable only for events that are pure cache-invalidation hints, never the source of truth."@objectstack/core'sauthz.invalidatedchannel module, which recorded the contradiction inline rather than resolving it in the wrong direction.The interface docblock is the load-bearing one for the hazard it invites. "At-least-once" tells an author their only obligation is to tolerate duplicates; the transport's actual failure mode is the opposite — a lost message, no replay, no upper bound on how long a node that was down at publish time stays wrong. An author who designs for duplicates and not for loss has designed for the wrong hazard, and neither the type nor the tests contradict them.
What this changes
One docblock, in the shape triage adopted on the card:
attachAuthzInvalidationPubSuband theauthz.invalidatedbridge already state.deliverySemanticsas the per-channel surface, and says what that surface is: what a channel asks for, not what it gets.at-least-onceparses there and is the default forcluster/tenantscope, but no shipped driver provides it yet.The new text is worded to agree with
cluster.mdx§4.2 and the redis driver rather than introduce a third wording of the same facts.Prose only: no schema, no type, no accept/reject behaviour change. Out of scope per triage and left alone: type-readable per-driver guarantees, boot refusal of an
at-least-oncechannel declaration, and any subscriber sweep.Two PM mechanism assumptions, measured
packages/spec/scripts/build-docs.tsregeneratescontent/docs/references/**from JSON Schemas, andIPubSubis a plain TypeScript interface with no Zod schema; the only two spec artifacts naming it (api-surface/contracts.json,export-origins/contracts.json) record the symbol name, never docblock prose. Confirmed empirically: a fullpnpm --filter @objectstack/spec build(which runsgen:schemaandgen:openapi) leftgit statuscarrying nothing but the two files in this diff, andcheck:generated,check:docsandcheck:authorable-surfaceare all green with no regenerated artifact.cluster.mdx§4.2 may need its cross-reference touched" — it does not. §4.2 carries no reference to the interface docblock; the onlyIPubSubmention incontent/docsis atcluster.mdx:173, in §4.3 aboutpartitionKey, which this change does not touch. §4.2's correction now agrees with the interface instead of contradicting it, so it reads correctly unedited. No docs file is changed.Changeset, not
skip-changesetThis is not docs-only. The docblock is compiled into the published type declarations — verified in
packages/spec/dist/contracts/index.d.ts, which now carries the corrected text — so the repair reaches consumers' editors through a released@objectstack/spec, which is the entire point of it. Shipped aspatch.Verification
All runs anchored to the final commit
8368e05b(origin/mainmerged in first, per the landing relay). Heavy runs went throughscripts/pm/os-verify-lock.sh; every exit code was captured before any pipe.pnpm --filter @objectstack/spec build—os-verify-lock: VERDICT command-exit 0;check-dts-emitted: @objectstack/spec - 34/34 declared declaration file(s) present.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, re-derived after the merge against the actual changed set (2 paths, three-dot semantics): 32 families, 30 green. Includescheck:generated,check:docs,check:authorable-surface,check:liveness,check:strictness-ledger,check:empty-state,check:variant-docs,check:skill-refs,check:doc-authoring,check:doc-formula-expressions,check:merge-driver,check:adr-0087-registration,check:empty-changeset,check:changeset-no-major,check:nul-bytes.check-dev-prereqsexits on "The workspace is not built — 1 unmet precondition, not a list of problems" (onlyspec,formulaandlintare built in this worktree; a full workspace build is CI's run).scripts/pm/check-half-states.mjsexits 3 on "PREREQUISITE NOT MET — the token in the environment is not a valid GitHub credential ... Nothing was swept ... it is no reading at all"; it inspects board state, not this diff.pnpm --filter @objectstack/spec typecheck— exit 0, includingcheck:test-typecheck: OK.vitest run src/kernel/cluster.test.ts— 1 file, 19 tests passed.eslint . --no-inline-config --format jsonover 5339 files (eslint's own enumeration) — 0 errors, 0 warnings, 0 fatal, withcluster-service.tsconfirmed present in the run.One finding filed, not fixed here
#12836 records two docblocks elsewhere that reference the retired at-least-once claim and go stale exactly when this lands: the "known contradiction" paragraph in
packages/core/src/security/authz-invalidation-channel.ts(which declares its own expiry — "filed separately" is this card), andat-least-once semantics held vacuouslyinpackages/services/service-cluster/src/memory/pubsub.ts. Both sit outside this card's declared file surface and in two other packages, so they are out of scope here and #12836 stays open for a follow-up.Landing note: several spec PRs are ahead in the landing relay — left as a draft deliberately, PM lands.
Generated by Claude Code