feat!: la famille ORM est publiee enveloppee, et le ng publie cesse de rendre des promesses

This commit is contained in:
Sylvain Duchesne
2026-09-21 12:38:17 +02:00
parent 2aac703784
commit d0ea043a5b
21 changed files with 1102 additions and 35 deletions
@@ -4,8 +4,8 @@ title: Publish the ORM family with the rights filter
parent: T01
depends_on: [T01.b, T01.d]
created: 2026-09-16
claimed_by: null
claimed_at: null
claimed_by: worker-T01.e
claimed_at: 2026-09-21
blocked: false
---
@@ -39,4 +39,20 @@ Note also: `OrmSubscription` was renamed `RdfOrmSubscription` in `@ng-org/orm@0.
## Progress
- Read the two governing rules, T01.b's and T01.d's `## Result`, the parent's `## Learnings digest`, and `knowledge_what-the-orm-writes-and-deletes-upstream.md`. Baseline taken first: `bun test` 408/0, both `tsc` 0, lint 0 ERROR.
- Read the ORM family AT THE SOURCE and in the installed `@ng-org/orm@0.1.2-alpha.21`: `getObjects`, `insertObject`, `removeObject` (NEW, absent from the pinned `nextgraph-rs`), `RdfOrmSubscription`, `DiscreteOrmSubscription`, `ngSession`, plus `getRaw`/`watch`/`effect`. Decided each against the "nothing published as-is" rule; reasons recorded in `src/surface/orm.ts` and `docs/api-contract.md` section 6bis.
- Published `getObjects` and `insertObject` wrapped, at upstream's own names, parameters and returns, injected through `configure` like the shape query beside them. `getObjects`'s config parameter is `RdfOrmConfig` (alpha.21's widening of `Scope | string`), which forced publishing that type from the SDK's `/all` subpath.
- Closed the `graph_orm_update` rights hole in two pieces: the guard (an override in `ng-proxy.ts`, ownership via `assertMayWrite`, reading the document out of each patch's `path`), and the door it sits on (`initNg` now hands the ORM this package's wrapped `ng`, because both consumers in the repo hand it the raw SDK object).
- That substitution turned the e2e RED on the two `useShapeQuery` journeys; the reference run was green, so it was mine. Measured the cause: `makeNg()`'s passthrough did `Reflect.get(ng, prop).bind(ng)`, and `@ng-org/web`'s `ng` is itself a Proxy answering every key - `bind` included - with a path-carrying callable returning a Promise. The published `ng` therefore answered all 88 members with a promise. Forwarded with `Reflect.apply` instead; pinned by a test whose fake is shaped like the real proxy, and which was verified to FAIL on the old line.
- Contract leaf edited (Scope, Deployment requirements, Surface, Guarantees, Non-guarantees, Change policy), bumped to `1.0.0-dev.7` as a MAJOR under the leaf's own policy, and in `package.json`. `docs/api-contract.md` (new section 6bis, sections 2/3/14 and the appendix), `docs/internal-contract.md`, `README.md`, `docs/polyfill-reference.md` updated.
## Result
**Done.** `getObjects` and `insertObject` are published WRAPPED, at upstream's names, parameters and returns, injected through `configure`. The read is capability-filtered per `@graph` (collection shape preserved); the write takes `assertMayReach` + `assertMayWrite` BEFORE the call. `graph_orm_update` now carries the same ownership guard in `ng-proxy.ts`, and `initNg` substitutes this package's wrapped `ng` so the ORM knocks on that door - the rights hole is closed. NOT published, each with a checkable reason: `RdfOrmSubscription` (pooled with no identity in the key), `DiscreteOrmSubscription`, `ngSession`, `getRaw`, `watch`/`effect`, and `removeObject` (exists in alpha.21, absent from the pinned `nextgraph-rs`, so no citation resolves). `1.0.0-dev.7`, MAJOR: an ORM write into a document you do not own is now refused.
**Found and fixed, MEASURED.** `makeNg()`'s passthrough did `.bind(ng)`; the SDK's `ng` is itself a Proxy answering every key including `bind`, so the published `ng` returned a PROMISE for all 88 members - `orm_start_graph is not a function`, swallowed by the ORM, read pending for ever. Now `Reflect.apply`. The e2e proves it only since `initNg` routes the ORM through the wrapper.
**Gate.** `bun test` 424 pass / 0 fail; both `tsc` exit 0; lint 0 ERROR; `== Polyfill e2e summary: 42 passed, 0 failed, 42 total - batch 3.3 min, slowest cold sync 27s ==`.
**Follow-ups.** `examples/notebook` fails its OWN `tsc` on HEAD already (its shape literal needs `satisfies`). `discrete_orm_update` is unguarded. `removeObject` awaits a refreshed `nextgraph-rs`.
@@ -48,4 +48,5 @@ The polyfill's published surface has drifted from the SDK's: invented names, inv
- T01.c - `useShapeQuery` takes the SDK's `Scope`, re-exported as a passthrough. Our three literals became `StoreType`, internal only: VERIFIED they are upstream's own `store_type`, so only the NAME was invented. A store is now named by its REFERENCE (`privateStore()` / `protectedStore()` / `publicStore()`), and `createEntityDoc(store?)` takes one, private when omitted, as `doc_create` does. `listMyEntityDocs`, `resolveScopeGraph` and `resolveWriteGraph` unpublished, still internal - T01.d removes the read path's last caller. VERIFIED: public and protected share one store id here, so the reference must be the index document. `1.0.0-dev.5`.
- Package refresh (2026-09-21) - `@ng-org/*` moved to web alpha.14 / orm alpha.21 / shex-orm alpha.9 / alien-deepsignals alpha.13. The live ORM read now STARTS against the deployed broker: `6 passed, 0 failed, 6 declared`, ready in 16ms, delete reached the document. `bug_useshape-live-read-needs-a-newer-broker` DELETED - the deployment was never behind, our packages were. T01.d's blocker LIFTS. Also surfaced: `OrmSubscription` is now `RdfOrmSubscription` (T01.e's proposal names the old one); `Scope.graphs` is REQUIRED and its `[]` means the EMPTY set while `subjects: []` means NO filtering - the two axes read `[]` in opposite directions, which T01.d must not get wrong; six e2e files imported `ng-e2e-helpers` without the polyfill declaring it, fixed as `workspace:*`.
- T01.d - `useShapeQuery` reads through `RdfOrmSubscription.getOrCreate`, injected as `configure({ ormSubscription })`; absent, the read publishes `isError` naming it. Scope resolution, the `ensureReposOpen` barrier, `readUnion` and the `@type` filter are gone from that path; `graphs`/`subjects`/`did:ng:i` reach the engine verbatim. The observable, snapshot, state and capability filter stay ours. `isError` KEPT, wired to the one real failure (the query refusing to open). A start the ENGINE refuses is swallowed upstream, so it reads `isPending` for ever - recorded in code and contract, no timeout invented. `userStoreDoc` and `liveStartWithConfig` deleted. VERIFIED: `listMyEntityDocs` is NOT dead, its own suite and an e2e journey call it. The change silently broke `examples/notebook/`, repaired out of boundary and deliberately. `1.0.0-dev.6`, major, 42/42 e2e.
- T01.e - `getObjects` and `insertObject` published WRAPPED at upstream's names, parameters and returns. Read is capability-filtered per `@graph`; the write takes `assertMayReach` + `assertMayWrite` BEFORE the call, and `graph_orm_update` now carries the same ownership guard, so the ORM rights hole is closed. NOT published, each with a checkable reason: `RdfOrmSubscription` (pooled with no identity in the key), `DiscreteOrmSubscription`, `ngSession`, `getRaw`, `watch`/`effect`, `removeObject` (in alpha.21 but absent from the pinned `nextgraph-rs`, so no citation resolves). `1.0.0-dev.7`, MAJOR. ROOT CAUSE FOUND for the consumer's `orm_start_graph is not a function`: `makeNg()`'s passthrough did `.bind(ng)`, and the SDK's `ng` is an async proxy whose `get` trap answers EVERY key including `bind` with a path-carrying callable - so the published `ng` returned a PROMISE for all 88 members. Now `Reflect.apply`, pinned by `test/ng-proxy.test.ts`. The e2e only proves it since `initNg` routes the ORM through the wrapper - before, `polyfill-entry.ts` handed `initNg` the raw SDK object, which is why the suite stayed green while the documented path was dead.