5.7 KiB
type, summary, severity, opened, last_checked
| type | summary | severity | opened | last_checked |
|---|---|---|---|---|
| bug | A live read through the published `useShape` never starts against the deployed broker — its `orm_start_graph` expects a `config` argument the published `@ng-org/orm` does not send, so the subscription stays empty and pending for ever with one console error as the only trace | major | 2026-08-17 | 2026-09-16 |
useShape opens no live read against the deployed broker
The published useShape is a passthrough to @ng-org/orm's hook (packages/polyfill/src/surface/use-shape.ts) — this package adds the read filter and forwards. Against the broker deployed today, the subscription that hook opens never starts: its set stays empty, its readiness never settles, no engine update ever arrives, and the only trace is one console.error. An application sees "this scope holds nothing", indefinitely, which is the exact confusion the rest of the read surface is built to prevent.
The cause is upstream, in the disagreement between the deployed broker and the published client packages. Nothing in this package can work around it.
The mechanism — an ARGUMENT, not a name
MEASURED 2026-09-16 against the real broker by packages/polyfill/e2e/orm-live-read.ts, which drives the published useShape over the real @ng-org/orm. The engine answers:
Deserialization error of config Error: invalid type: JsValue(Function), expected any valid JSON value
A live ORM read is one call and it is streamed: OrmSubscription's constructor issues ng.orm_start_graph(graphs, subjects, shapeType, session_id, onBackendMessage) — five arguments, callback last — and the engine pushes into that callback rather than answering once. What comes back instead names a parameter, config, that the client never sent.
The same measurement establishes where that parameter sits, by calling the SDK member directly with {} in position 4: six arguments are ACCEPTED, and the engine then streams back. So the deployed signature is (graph_scope, subject_scope, shapeType, session_id, config, callback), and the published client's five-argument call lands its callback exactly where config is expected — which is precisely what the error describes.
The direction is the opposite of what this leaf said until 2026-09-16. The earlier reading — a broker built before orm_start was renamed orm_start_graph (upstream d5ecd0fd, 2026-01-16) — is refuted: the name resolves, and the call fails inside the function, on an argument. That arity exists in no commit of nextgraph-rs at 213338f6: the one window that carried a config at all (c38aa371 2026-04-12 → 7c8abd0a 2026-04-21, "rm unused config param") put it last, after the callback, where a five-argument call would leave it merely absent. The deployment is therefore built from a source ahead of that checkout, and it is the published @ng-org/orm@0.1.2-alpha.19 / @ng-org/web@0.1.2-alpha.13 this package pins that are behind it.
Why it fails in silence: orm_start_graph is awaited inside a try whose catch is console.error(e), and resolveReady() is called on one path only — the arrival of initial data (GraphOrmSubscription.ts:handleInitialResponse). A rejected start leaves the readiness promise pending for ever and the set permanently empty. This is the same upstream property already recorded in docs/api-contract.md (a failed read is an eternal pending upstream), reached here through a different door.
What is affected, and what is not
- Affected: the published
useShape, and only it. By the same argument,insertObjectandgetObjects— both built onOrmSubscription— cannot start either, so no ORM write or deletion can be exercised against this deployment. - Not affected:
watchShape,subscribeDoc,subscribeDocs,readUnion. These open onedoc_subscribeper document, anddoc_subscribe: 2has been in the method tables continuously under a stable name and arity.watchShapeis built on that path, not on the ORM subscription — it is a working reactive read today.
That is why the library's own suites and the reference application do not show it: nothing in this package calls useShape internally.
What to do
- Do not build on live
useShape. UsewatchShapefor a reactive read,readUnionfor a one-shot one. This is stated in the contract's## Non-guaranteesso a consumer meets it without reading this leaf. - The fix is not ours, and it is an ALIGNMENT, not an upgrade in one direction. Either the deployment rolls to a build whose
orm_start_graphmatches the published packages, or@ng-org/orm/@ng-org/webare republished against the deployed signature. Report it; do not patch around it, and do not pass aconfigargument from here — a client that guesses an unpublished arity breaks the day the two ends agree. - To check whether it is closed:
bun run e2e/orm-live-read.tsfrompackages/polyfill(it needs@ng-org/orm, an optional peerbun installdoes not fetch). It exits non-zero while this is open and names what the engine expected. Green means the two ends agree and this leaf can go.
The shape worth remembering
A method signature — name and arity together — duplicated across three independently-deployed artifacts, with a silent failure when they disagree, is a defect no single repository's tests can catch. Pinning the client packages does not help: the broker-side half (@ng-org/api-web, private: true, shipped only inside the broker build) is pinnable by nobody, so the two ends drift in either direction and the symptom is identical both ways. Anything this package routes through a streamed method inherits the same exposure — which is the reason subscribeDocs composing per-document doc_subscribe is worth more than it looks.