|
| 1 | +--- |
| 2 | +"@objectstack/spec": patch |
| 3 | +--- |
| 4 | + |
| 5 | +chore(spec): govern the realtime `SubscriptionSchema` surface in the liveness ledger (#14446) |
| 6 | + |
| 7 | +The `liveness/` ledgers ship inside this package's npm tarball (they are named in |
| 8 | +`files`), so this is a published-data change even though no runtime behaviour moves, |
| 9 | +no schema key changes spelling, and `packages/spec/src/api/realtime.zod.ts` is not |
| 10 | +edited at all. |
| 11 | + |
| 12 | +A new ledger file — `realtime_subscription.json` — classifies all six authorable |
| 13 | +properties of `SubscriptionSchema`, what a client declares to open a realtime |
| 14 | +subscription: the item type of `RealtimeConfigSchema.subscriptions` and the |
| 15 | +`Subscription` the generated API reference publishes. It is enrolled through the |
| 16 | +gate's `SPEC_ONLY_SCHEMAS` override, the route `query` / `qa` / `manifest` and the |
| 17 | +four `RestServerConfig` sub-objects already take. A transport-protocol surface is |
| 18 | +neither a metadata item nor stored metadata nor a manifest, so no registry has ever |
| 19 | +held it and no ratchet rooted in one could ask who reads it — and |
| 20 | +`RealtimeConfigSchema` is `.passthrough()`, so nothing downstream even refuses an |
| 21 | +unknown key. |
| 22 | + |
| 23 | +All six are `dead`, and the container is the finding: nothing outside |
| 24 | +`packages/spec` imports `SubscriptionSchema`, `SubscriptionEventSchema` or |
| 25 | +`RealtimeConfigSchema` at all, so no key beneath them can be read. The two the |
| 26 | +census filed with this card measured are the sharp ones. `events[].type` accepts |
| 27 | +`RealtimeEventType`, whose four members (`record.created` / `record.updated` / |
| 28 | +`record.deleted` / `field.changed`) are disjoint from what the engine publishes — |
| 29 | +`DataEventType`'s `data.record.*`, with a live emitter in `service-knowledge` — so |
| 30 | +an author who writes the enum's own `record.created` gets a subscription that |
| 31 | +silently never fires, and the enum is what the API reference shows them. |
| 32 | +`events[].filters` is `z.unknown().optional()`: an authorable key with no shape and |
| 33 | +no consumer, failing in the permissive direction, since the only payload matching |
| 34 | +the platform performs compares object name and event type. |
| 35 | + |
| 36 | +What this records, and what it deliberately does not. The enum's direction is |
| 37 | +settled and the row carries the 2026-09-02 triage ruling verbatim so the next reader |
| 38 | +does not re-open it: if the verdict is enforce it means repointing the enum, never |
| 39 | +changing what the runtime publishes, which would break a live event contract to |
| 40 | +satisfy a member nothing has ever used. `field.changed` is the same spelling the |
| 41 | +sibling `DataEventType` removed in 17.0.0 under ADR-0049 (#4673, PR #4685) for |
| 42 | +having no producer; it survives here only because this enum was never in a ratchet's |
| 43 | +denominator. No key is removed, enforced, deprecated or re-described here — the |
| 44 | +enforce-or-remove call per dead key is a follow-up on the human floor. |
| 45 | + |
| 46 | +Rooted on `SubscriptionSchema` rather than on `RealtimeConfigSchema`, which is |
| 47 | +measurement rather than taste: the ledger walk drills exactly one level, so with the |
| 48 | +config as the root `subscriptions` would be the drilled level and `events[].type` / |
| 49 | +`events[].filters` would have no row of their own, inheriting a container verdict — |
| 50 | +the same reasoning that rooted the four `RestServerConfig` sub-objects separately. |
| 51 | +`RealtimeConfigSchema`'s own three keys are not enrolled: whether enabling realtime |
| 52 | +does anything is a different question with no census behind it yet. |
| 53 | + |
| 54 | +One correction the ledger records because the next reader will hit it too. The card |
| 55 | +and its triage both name the two keys on `SubscriptionSchema`; they are declared on |
| 56 | +`SubscriptionEventSchema` (`realtime.zod.ts:46-50`), reached from this root as |
| 57 | +`events[].type` and `events[].filters`. The cited lines and quoted shapes are exact; |
| 58 | +only the owning symbol was misattributed, and this package's own authorable-surface |
| 59 | +census (`authorable-surface/api.json`) already spells the two schemas apart. |
0 commit comments