4.5 KiB
id, title, parent, depends_on, created, claimed_by, claimed_at, blocked
| id | title | parent | depends_on | created | claimed_by | claimed_at | blocked | ||
|---|---|---|---|---|---|---|---|---|---|
| T01.e | Publish the ORM family with the rights filter | T01 |
|
2026-09-16 | null | null | false |
Description
Wrap and publish the ORM family this package does not expose: getObjects and insertObject at identical signatures, with the rights filter; deletion in whatever shape T01.b established; and whatever T01.b's arbitration settled for OrmSubscription, DiscreteOrmSubscription and ngSession.
Why the dependencies. On T01.b: the deletion shape and the three arbitrations are established there — read its ## Result and the knowledge_ leaf it names, rather than re-reading nextgraph-rs. On T01.d: both children change the published surface and edit the same contract, and they must not run concurrently.
The problem is a rights hole, not a missing convenience. Today an application has to import these straight from @ng-org/orm, and then receives every identity's data out of the shared wallet with nothing signalling it. The filter that closes it is makeReadFilteredView (packages/polyfill/src/emulated-verifier/read-filter.ts, annotated kind=aligned level=1 ref=engine/verifier/src/verifier.rs:load_repo_from_read_cap): it keeps only items whose document — their @graph — the current holder has a cap for, applied per document on what comes back. That is the emulation of what the broker will bound at delivery, done where the target does it. packages/polyfill/src/surface/use-shape.ts is the existing example of a passthrough that filters results.
Identical signature means passed through, not translated. If a parameter cannot be passed through, stop and say what would have to be built beneath it — that is the real decision, and it is being made by the parameter (.project/rules/nextgraph/surface-mirrors-the-sdk.md). Do not invent an ergonomic wrapper that an application would have to unlearn.
Open questions to carry or close — do not invent past them:
- If T01.b left the deletion shape unestablished, this child does not specify one. Report it and publish the rest.
- A write path cannot be rights-filtered the way a read is. The filter is a read emulation.
packages/polyfill/src/surface/ng-proxy.tsalready overridessparql_updatewith an emulated write guard — read it before deciding whatinsertObjectdoes with an unauthorized write. Do not invent a write guard the target does not have; if the answer is "the existing guard covers it", say which line does. - If T01.b's arbitration for
OrmSubscription/DiscreteOrmSubscription/ngSessionis a proposal the user has not confirmed, and acting on it would remove or rename something, stop and ask. Adding is reversible; removing a published symbol is a major that a caller pays for.
This child owns the contract edit and the version bump for its own change. Edit .project/concepts/app-contract/polyfill-surface/contract_polyfill-surface.md — ## Surface, ## Guarantees (what the filter promises about what comes back), ## Non-guarantees, ## Change policy. By the contract's own rules, symbols added with nothing existing moved is a minor; if the arbitration removes or narrows anything it is a major. Apply the rule, do not assume a level. No other child edits the contract for this change.
Also in scope: packages/polyfill/src/index.ts (the export and its @provenance lines — each new symbol needs one, in the form T01.a installed), test/vocabulary.test.ts and test/app-surface.test.ts (they pin the export inventory), test/provenance.test.ts coverage, docs/api-contract.md, packages/polyfill/README.md, packages/polyfill/docs/polyfill-reference.md. New behaviour needs new tests, including the rights case: a second identity's data must not come back.
Hard gate: bun test → 0 fail; bunx tsc --noEmit -p packages/polyfill/tsconfig.json → exit 0; bunx tsc --noEmit -p packages/polyfill/e2e/tsconfig.json → exit 0; python3 ~/.claude/skills/concept/lint.py → 0 ERROR. Anti-cheat: no any, no @ts-ignore, no deleting or skipping a test, no widening an assertion.
Resolved since planning (2026-09-16). A write is not rights-filtered like a read: upstream bounds a write by write capability, not by hiding results. So insertObject gets a GUARD BEFORE the write, following the package's existing pattern (assertOwnInbox, mustNotAttempt, assertMayReach) — never a filter over what it returns.