5.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.c | watchShape becomes useShapeQuery and takes the SDK's Scope | T01 |
|
2026-09-16 | null | null | false |
Description
watchShape becomes useShapeQuery and takes the SDK's Scope — { graphs?: string[] | string; subjects?: string[] } (sdk/js/orm/src/types.ts) — in place of the three invented literals "public" | "protected" | "private" (packages/polyfill/src/model/types.ts).
The name and the parameter only. The read path underneath stays as it is in this child; T01.d replaces it. The translation from the SDK Scope down to what the current pipeline needs lives here and is explicitly temporary — say so beside the code, because a parameter that must be translated is the tell that a mechanism below it is about to become ours (.project/rules/nextgraph/surface-mirrors-the-sdk.md).
What stays, and why that is not a fault. The ShapeQuery return shape (TanStack-like: { data, isPending, isSuccess, isError, error }) and the capability filter both survive. That is the justified kind of difference: NextGraph's direction, as reported by its developers, is a useShapeQuery returning exactly that shape, and deviating toward the announced target is alignment. useShape (the existing passthrough to the SDK's current hook, packages/polyfill/src/surface/use-shape.ts) is a different symbol and keeps its own life — do not collapse the two.
Facts — cite them, do not re-derive them. .project/concepts/app-contract/knowledge_what-a-read-scope-is-upstream.md: a graphs entry is one document's graph, never a set of them; did:ng:i or "" discards every other entry and means the whole local dataset with no permission narrowing; a store's graph holds only its containment triples, so "search my private store" returns empty silently; [] or undefined returns no objects at all; the graph filter is literal, with no prefix or hierarchy matching; scoping a read by store is not expressible at all.
The boundary that must not be lost. The store axis survives for creation — docs.docCreate takes a destination upstream, and storeRegistry.createEntityDoc(scope) keeps its three literals — and dies for reading.
Open question — settle it in the open, or escalate. After this change two different types would want the name Scope. The published Scope today is the three literals and is used by storeRegistry.createEntityDoc / listMyEntityDocs / resolveScopeGraph / resolveWriteGraph. The SDK's Scope is the object. The rule says publish the SDK's names, so the SDK's type should take the name and the placement axis needs a name of its own — but what that name is, and whether listMyEntityDocs (a read keyed by the store axis) survives at all, is settled by no leaf. Propose it in ## Progress; if listMyEntityDocs's fate is genuinely in question, stop and ask rather than removing a published symbol on your own judgment.
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 (the signature, the Scope type block), ## Non-guarantees (every mention of watchShape), ## Change policy (the new pre-release string and what it narrows). By the contract's own ## Change policy this is a major — a published symbol is removed, and an existing call changes a parameter a caller must react to. No other child edits the contract for this change; do not touch the sections another child owns.
Also in scope: packages/polyfill/src/surface/watch-shape.ts, packages/polyfill/src/index.ts (export and the comments around it), packages/polyfill/src/model/types.ts, test/vocabulary.test.ts and test/app-surface.test.ts (they pin the export inventory and the vocabulary), test/watch-shape.test.ts, test/watch-shape-surfaces-failure.test.ts, docs/api-contract.md, packages/polyfill/README.md, packages/polyfill/docs/polyfill-reference.md, examples/notebook/app.ts, and the packages/polyfill/e2e/ callers.
The annotation. useShapeQuery has zero occurrences in nextgraph-rs; its justification is NextGraph's own direction as stated by its developers. Read T01.a's ## Result and use the form it installed. Do not cite an approximate symbol — that is the readUnion failure this whole task exists to undo.
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). Our Scope type is NOT renamed — it DISAPPEARS. A renamed invented name is still an invented name. This extends to creation: the earlier note that "the store axis survives for creation" was preserving an invention because it looked necessary. Upstream docCreate(sessionId, crdt, cls, dest, store?) does take a store, so the NOTION survives; what is invented is our three-literal encoding. The creation path aligns on docCreate's own parameters. listMyEntityDocs is DELETED: no upstream equivalent exists (no doc_list, no list_docs, nothing in the binding), and listing one's documents is an ordinary query over the store graph's ldp:contains — sugar over an expressible query, the same shape as readUnion.