99 lines
14 KiB
Markdown
99 lines
14 KiB
Markdown
---
|
|
id: T01.g
|
|
title: Adversarial review of the whole published surface
|
|
parent: T01
|
|
depends_on: [T01.a, T01.b, T01.c, T01.d, T01.e, T01.f, T01.h, T01.i, T01.j, T01.k, T01.l, T01.m, T01.n]
|
|
created: 2026-09-16
|
|
claimed_by: adversarial-reviewer
|
|
claimed_at: 2026-09-24
|
|
blocked: false
|
|
---
|
|
|
|
## Description
|
|
|
|
An adversarial pass over the **whole** published surface — every symbol exported from `packages/polyfill/src/index.ts`, not only the ones this batch touched — trying to **refute** the parent task's success criterion: *every published symbol either mirrors an SDK symbol in name, parameters and return, or carries a justified annotation*.
|
|
|
|
**Method, in this order.** For each published symbol ask the two questions of `.project/rules/nextgraph/no-divergence-from-nextgraph.md` in their stated order: *does the target do this?* **first**, verified in `nextgraph-rs` or stated by its author; *would an application have to unlearn it?* second, and only to rank severity — never to authorise a divergence. Then, for the name and the shape (`.project/rules/nextgraph/surface-mirrors-the-sdk.md`): is this the target's own name, does the verb belong to something else upstream, is the parameter passed through or translated, is the return the SDK's.
|
|
|
|
**Check every `@provenance` line against the CLAIM, not just against the tree.** Same granularity on both sides: a function may cite a function; a composition, a pipeline or a policy cites nothing at level 2 and must say so. *"The reference resolves"* is not *"the annotation is true"* — that is precisely how `readUnion` survived. Use the mechanism as T01.a left it, including whatever the new kind for an announced-but-unwritten target requires as evidence.
|
|
|
|
**Known, and not findings.** The three open `bug_` leaves in `.project/concepts/app-contract/`: `bug_useshape-live-read-needs-a-newer-broker` (MAJOR), `bug_a-lost-inbox-watch-is-never-retried` (MAJOR), `bug_an-empty-inbox-list-can-mean-a-failure`. Do not re-report them as new. **Do** report it if a change in this batch altered their status, or invalidated a workaround they or the contract publish — the `useShape` bug leaf and the contract's `## Non-guarantees` both name `watchShape` and `readUnion` as the unaffected paths, and both were changed here.
|
|
|
|
**Check the contract as delivered**, since three children edited it in sequence: `## Surface` matches the actual exports symbol for symbol; `## Change policy` records a version whose bump level follows the contract's own rules for what actually changed; no section was half-edited or edited twice for the same change; nothing published is left described by a sentence that is no longer true.
|
|
|
|
**Findings are leads, not mandates, and this child fixes nothing.** A finding without a reproducible failure scenario or a checkable citation does not count. Report symptom, precise location (`file:line`, the failing assertion, the offending extract) and, where it is already known, the cause — but do not instrument, bisect or repair. Each fix is a new task.
|
|
|
|
**Deliverable.** In `## Result`: findings by severity (blocking / major / minor), atomic, numbered `1.1`, `1.2`, … so they can be answered precisely. Neutral tone, no first or second person. One line of verdict on the test suites, not a list of what passes.
|
|
|
|
**Pass condition for this child** (it writes no code): run `bun test`, `bunx tsc --noEmit -p packages/polyfill/tsconfig.json`, `bunx tsc --noEmit -p packages/polyfill/e2e/tsconfig.json` and `python3 ~/.claude/skills/concept/lint.py` to **establish** the delivered state and report it verbatim; the review covers every symbol exported from `packages/polyfill/src/index.ts`, with the ones found clean stated as a count rather than an inventory.
|
|
|
|
## Progress
|
|
|
|
## Result
|
|
|
|
Read-only pass. Nothing in the delivered code was changed; one throwaway probe was run and deleted, and `git status` shows only this task file's own move.
|
|
|
|
### Delivered state, measured
|
|
|
|
- `bun test` -> `465 pass / 0 fail`, 1316 `expect()` calls, 40 files. MATCHES the figure on record.
|
|
- `pnpm exec tsc --noEmit -p packages/polyfill/tsconfig.json` -> exit 0. MATCHES.
|
|
- `pnpm exec tsc --noEmit -p packages/polyfill/e2e/tsconfig.json` -> exit 0. MATCHES.
|
|
- `python3 ~/.claude/skills/concept/lint.py` -> **0 ERROR** (11 items across 4 WARNING classes). MATCHES.
|
|
- `packages/polyfill/src/index.ts` carries **21** `export` statements. MATCHES. It **DIFFERS** on the symbol count: those 21 statements name **37** top-level names, of which 3 are namespace groupings (`docs`, `inbox`, `storeRegistry`), so the published surface as `test/provenance.test.ts:publishedSymbols` itself computes it is **53** (34 direct + 3 `docs` + 11 `inbox` + 5 `storeRegistry`), which is also exactly what `docs/api-contract.md`'s appendix lists. Not 25.
|
|
- 123 `@provenance` annotations in `src`, covering the 53 published symbols plus 70 internal ones.
|
|
|
|
### Blocking
|
|
|
|
**1.1 The read filter on the published `useShape` is bypassed by the SDK version this repo builds against, and every identity's objects reach the caller out of the one shared wallet. PROVED.**
|
|
|
|
`src/surface/use-shape.ts:14-17` hands whatever the injected hook returned to `makeReadFilteredView`. `read-filter.ts:179-180` passes any non-function member through untouched, on the header's stated ground that "a plain property carries no items".
|
|
|
|
That ground held for `@ng-org/orm@0.1.2-alpha.18`, the version in the cited `nextgraph-rs` checkout: `sdk/js/orm/src/frontendAdapters/react/useShape.ts:123` ends `return state as DeepSignalSet<T>` - a bare set, whose item-yielding members are all functions the whitelist covers. It is FALSE of `@ng-org/orm@0.1.2-alpha.21`, which the `ANCHOR` calls the build and which is installed under `packages/polyfill/node_modules`: `dist/frontendAdapters/react/useShape.d.ts` declares the return `UseShapeResult`, an object carrying `data`, `promise`, `subscription`, `isLoading`, `nextPage`, `previousPage`. `data`, `promise` and `subscription` are plain PROPERTIES holding the items.
|
|
|
|
Repro run against the delivered `read-filter.ts` and `caps.ts`, with a `CapRegistry` in which alice and bob each minted one document, `isEnforcing() === true`, and bob the current holder, over an object of exactly the shape `useShape.d.ts` declares:
|
|
|
|
```
|
|
alpha.18 shape -> iterated: [ "bob-own" ]
|
|
alpha.21 shape -> .data items : [ "bob-own", "alice-private" ]
|
|
alpha.21 shape -> .subscription.signalObject items: [ "bob-own", "alice-private" ]
|
|
alpha.21 shape -> await .promise items: [ "bob-own", "alice-private" ]
|
|
did anything throw? no.
|
|
```
|
|
|
|
The contract instructs exactly the injection that opens this: `docs/api-contract.md:50` reads `useShape: UseShapeLike; // the REAL @ng-org/orm useShape`, and `contract_polyfill-surface.md:36` says the same. `EventuallyConfig.useShape` is not optional, so every application passes something, and `UseShapeLike = (...args: any[]) => any` (`src/model/types.ts:83`) accepts either return shape without a type error - which is why both typechecks stay at exit 0.
|
|
|
|
Two published statements are falsified by the run. `contract_polyfill-surface.md:256`: "**No unfiltered read through `useShape`.** Members that yield items are filtered and mutations pass through; anything else throws" - nothing throws, and the unfiltered items come back on three separate properties. And `docs/api-contract.md:345`'s rationale for wrapping the ORM, "an unwrapped ORM read returns EVERY identity's data out of the shared wallet with nothing signalling it", describes the WRAPPED `useShape`'s current behaviour on this version.
|
|
|
|
### Major
|
|
|
|
**2.1 `@ng-org/orm` does not export `useShape` at the specifier the contract names. CONFIRMED.** The installed manifest maps `"."` to `dist/core.d.ts`, and `core.d.ts` exports `initNg`, `ngSession`, `RdfOrmSubscription`, `DiscreteOrmSubscription`, `insertObject`, `removeObject`, `getObjects`, the `types.ts` re-export and three `alien-deepsignals` members. No `useShape`. The hook is at `@ng-org/orm/react` (also `/svelte`, `/svelte4`, `/vue`), or as `reactUseShape` from `@ng-org/orm/all`. An application following `contract_polyfill-surface.md:36` or `docs/api-contract.md:50` literally fails to resolve the import. Note the neighbouring claim that IS correct and was checked: `index.ts:162`'s reason for taking `RdfOrmConfig` from `/all` holds, since `core.d.ts` really does not carry it.
|
|
|
|
**2.2 Four present-tense claims that the SDK's `useShape` returns a bare `DeepSignalSet` are false of the version built against, and two of them are the stated ground of a provenance ruling. CONFIRMED.** The claim is at `src/model/types.ts:124`, `src/surface/use-shape-query.ts:11` and `:33`, and `contract_polyfill-surface.md:234` ("`useShape` returns a set you cannot tell from an empty one"). In `alpha.21` the return carries `isLoading` and `promise`. The two that are load-bearing:
|
|
|
|
- `src/surface/use-shape-query.ts:284`, the `announced-not-written` annotation, whose note reads "the SDK ships `useShape` returning a bare `DeepSignalSet`; the announced direction is a `useShapeQuery` returning a TanStack-shaped snapshot". The premise is false of what the SDK ships; the shipped hook already returns a load-state-carrying object.
|
|
- `src/surface/use-shape-query.ts:193`, `ShapeQuery kind=invention level=none ref=none`, whose note opens "no upstream type carries load state". `UseShapeResult.isLoading` is an upstream load state at level 3. `ref=none` and `level=none` assert that nothing answers at any level.
|
|
|
|
This is the failure mode the mechanism exists to catch, in its documented form: the citations resolve, and the claims attached to them do not hold at the version a consumer compiles against. `test/provenance.test.ts` cannot see it by construction (it pins that a claim was made, not that it is true), and the `ANCHOR`'s own comment predicted this class of error.
|
|
|
|
**2.3 The one gate that exercises the published `useShape` against a live broker injects a hand-written substitute rather than the SDK's hook, which is why 1.1 is green. CONFIRMED.** `packages/polyfill/e2e/orm-live-entry.ts:101-105` defines `realOrmUseShape` as `RdfOrmSubscription.getOrCreate(...)` returning `sub.signalObject`, and `:109` injects that. The file's header states the substitution and its reason ("without a React tree to mount"). The state it fabricates - a hook returning a bare set - is the one `alpha.21` no longer produces, so the suite measures the `alpha.18` shape exclusively. Every unit fake does the same (`test/orm-fake.ts`, `e2e/polyfill-entry.ts:191`).
|
|
|
|
### Minor
|
|
|
|
**3.1 Two published types have no published signature using them, against the entry's own rule. CONFIRMED.** `src/index.ts:78` states "A type is published only when a PUBLISHED SIGNATURE uses it", and `:87-96` enumerates the warrants. `Schema` (`index.ts:149`) appears in no signature anywhere: `grep -rn "\bSchema\b"` over the working copy outside `node_modules` returns only its own export line, its annotation, and three document copies of that line. `DeepSignalSet` (`index.ts:151`) appears in `src` only inside prose and one annotation, never in a type position; no published signature returns one, since `useShape` returns `unknown`. This is the defect for which `ReadCap` and `InboxScope` were unpublished on 2026-08-10, with the rationale still at `index.ts:79-86`.
|
|
|
|
**3.2 Seven published symbols carrying `kind=invention level=none ref=none` sit under the block headed "a target counterpart for every symbol". CONFIRMED.** `src/index.ts:45-46` heads the first block "SDK-SHAPED - a target counterpart for every symbol / At migration the build alias is removed and these resolve to the real SDK", and `:166-169` heads the second "POLYFILL-ERA - THE DELETION LIST / nothing below has a target counterpart". Exported above the divider and annotated `invention`, which the taxonomy defines as "nothing at any level answers": `NgLike`, `UseShapeLike`, `OrmSubscriptionLike`, `GetObjectsLike`, `InsertObjectLike` (`:111-120`) and `ShapeQuery`, `ShapeObservable` (`:123`). The five `...Like` types are used by exactly one published signature each, all of them fields of `EventuallyConfig`, which is itself on the deletion list. `docs/api-contract.md:822` states the matching count as "exactly ONE is polyfill-era with no target counterpart".
|
|
|
|
**3.3 A published function is absent from the contract's `## Surface`. CONFIRMED.** `docChangeType` is exported at `src/index.ts:132` and listed in the appendix, and `contract_polyfill-surface.md`'s `## Surface` block shows only the type `DocChangeType`, inside the two `subscribeDoc` signatures (`:97-98`). Nothing pins that block: `test/vocabulary.test.ts` checks `docs/api-contract.md`, never the concept leaf.
|
|
|
|
**3.4 A stale annotation claims a published namespace name for an internal symbol. CONFIRMED.** `src/shared-wallet/account-registry.ts:971` annotates `storeRegistry.resolveScopeGraph`, and the format's own rule (`test/provenance.test.ts:22-24`) reserves the qualified form for a published namespace member. `resolveScopeGraph` was unpublished in `1.0.0-dev.5` (`src/surface/placement.ts:135,144`; `contract_polyfill-surface.md:325`), `surface/placement.ts` does not re-export it, and it is absent from the 53-symbol set `publishedSymbols()` computes.
|
|
|
|
### Found clean
|
|
|
|
**41 of the 53 published symbols** were walked against `nextgraph-rs` or the installed `.d.ts` and faulted on nothing. The 12 named above are `useShape`, `useShapeQuery`, `ShapeQuery`, `ShapeObservable`, `Schema`, `DeepSignalSet`, `docChangeType`, `NgLike`, `UseShapeLike`, `OrmSubscriptionLike`, `GetObjectsLike`, `InsertObjectLike`.
|
|
|
|
Checked and HOLDING, listed only because each was a plausible refutation that failed: `getObjects` and `insertObject` mirror `alpha.21`'s declared signatures exactly, including `Omit<RdfOrmConfig<T>, "pageSize" | "maxActivePages">`, and their `passthrough` notes disclose the filter and the guard; `RdfOrmConfig`'s `/all` subpath justification is true of the installed manifest; `Scope` is genuinely on `core.d.ts` via `export * from "./types.ts"`; `ng`, `NG`, `init`, `initNg`, `subscribeDoc`, `subscribeDocs`, the three `docs` members, the eleven `inbox` members and the five `storeRegistry` members carry annotations whose claims match their code. `## Change policy` records `1.0.0-dev.10`, which `packages/polyfill/package.json:3` pins, and its "Nothing is added, renamed or removed from the entry" is true: `git diff de9b8a0..HEAD -- packages/polyfill/src/index.ts` moves no `export` line.
|
|
|
|
### Verdict on the suites
|
|
|
|
Green as delivered and reproduced verbatim above, and 1.1 shows the green is not evidence: no fake in `test/` or `e2e/` returns the shape the installed SDK returns, so the suites exercise a hook shape that `@ng-org/orm@0.1.2-alpha.21` does not produce.
|