Files
ng-eventually/.tasks/done/T01.p-four-minor-surface-faults.md
Sylvain Duchesne 8ce9857346 chore: T01.p est close, item 2 se scinde en deux corrections et un point proprietaire
Le coordinateur a confirme le decoupage de l-item 2 et demande les deux sous-
constats determinables depuis ce depot. Verifie la precondition de chacun avant
d-agir : configure/EventuallyConfig sont bien deja sous la barriere (partie A),
et l-annonce citee par useShapeQuery contient bien le mot ShapeQuery et sa
forme exacte (partie B). Les deux sont appliques et committes separement.
ShapeObservable reste tel quel, sans decision prise a sa place - remonte au
proprietaire. Confirme aussi la lecture du coordinateur sur les sept imports
inutilises d-account-registry.ts (noUnusedLocals est desactive), sans y toucher.

Les quatre items de la tache sont clos ; le seul point ouvert (ShapeObservable)
est explicitement celui du proprietaire, pas un blocage de cette tache.
2026-09-28 14:06:06 +02:00

18 KiB

id, title, parent, depends_on, created, claimed_by, claimed_at, blocked
id title parent depends_on created claimed_by claimed_at blocked
T01.p Four minor faults on the published surface T01
T01.o
2026-09-24 T01p-agent 2026-09-24T18:50:06Z false

Description

The four minor findings of T01.g, all CONFIRMED there. None is a rights or correctness defect; each is a published-surface or annotation inaccuracy. Verify each still stands before changing it - T01.o may have moved some.

  1. Schema and DeepSignalSet are published with no published signature using them, against the rule stated at packages/polyfill/src/index.ts:78 (the same ReadCap/InboxScope rule, so this is a recurrence). Either a published signature uses them or they are unpublished.
  2. Seven symbols annotated kind=invention level=none ref=none sit ABOVE the polyfill-era divider, under the heading that promises a target counterpart for every symbol (index.ts:45, :111-123). Either the annotation is wrong or they are on the wrong side of the divider.
  3. docChangeType is published but absent from the concept contract's ## Surface, and nothing pins that block against the actual exports. Add it, and consider whether the block should be pinned by a test the way the deletion list already is.
  4. account-registry.ts:971 annotates storeRegistry.resolveScopeGraph, unpublished since 1.0.0-dev.5. A provenance annotation on an unpublished symbol claims a surface that does not exist.

Hard gate: bun test -> 0 fail; both typechecks exit 0; python3 ~/.claude/skills/concept/lint.py -> 0 ERROR. Anti-cheat as usual. Any symbol you unpublish is a MAJOR by the contract's own change policy - follow it rather than deciding the level yourself.

Progress

Items 1, 3 and 4 verified, fixed and committed. Item 2 investigated in full; the coordinator confirmed the split and asked for the two determinable sub-findings (the five EventuallyConfig field types, and ShapeQuery's kind) to be applied, with the third (ShapeObservable) left for the owner - see the "Item 2 - resolution" addendum below. All four items are now closed for this task; the one open item is ShapeObservable, explicitly the owner's.

Commits made (chronological): fix!: unpublish Schema/DeepSignalSet + version bump to 1.0.0-dev.12 (item 1); docs: add docChangeType to the concept contract's Surface and pin the block with a new test (item 3); fix: drop the stray provenance annotation on resolveScopeGraph (item 4); fix: move the five EventuallyConfig field types below the divider + version bump to 1.0.0-dev.13 (item 2, part A); fix: re-kind ShapeQuery to announced-not-written (item 2, part B).

Result

Status: done. ShapeObservable's divider placement is named below as the owner's open item - not a blocker on this task, per the coordinator's instruction.

Item 1 - Schema / DeepSignalSet (DONE)

VERIFIED by grep across src, test, e2e, examples: neither is used as an actual TypeScript type anywhere in this repo outside the re-export itself (DeepSignalSet only appears inside prose/JSDoc). Unpublished both from packages/polyfill/src/index.ts (removed the export type lines and their @provenance annotations), following the exact precedent already set for ReadCap/InboxScope - except neither has an internal use to stay DEFINED for, so they are simply gone rather than moved to model/types.ts.

Checked the sibling task's note about ShapeResult: VERIFIED that useShape now declares a literal ShapeResult return type (changed today, replacing any), but ShapeResult staying unpublished is an EXISTING, DOCUMENTED, deliberate pattern (its own comment in model/types.ts:81-99 says "Same discipline as {@link OrmSubscriptionHandle}"

  • a published call returning an unpublished, package-invented result type, matching the contract's own ## Surface entry useShape(...): ShapeResult). This does not violate the rule at index.ts:78 (which is one-directional: a published TYPE needs a published signature using it - not the reverse). Concluded this does NOT belong in item 1; no change made.

This is a MAJOR (published symbol removed). Version bumped 1.0.0-dev.11 -> 1.0.0-dev.12 in packages/polyfill/package.json, a new dated entry added to the concept contract's ## Change policy, and docs/api-contract.md updated (the "Today" code block in §4, the §14 ruling with a new paragraph matching the ReadCap/InboxScope one, and the appendix's direct: inventory line) - in the SAME commit as the code change.

Item 2 - seven invention/none/none symbols above the divider (BLOCKED, not changed)

VERIFIED the exact seven, by grepping every kind=invention level=none ref=none annotation in src and checking which are published above the POLYFILL-ERA divider in index.ts: NgLike, UseShapeLike, OrmSubscriptionLike, GetObjectsLike, InsertObjectLike (all in model/types.ts, all typing fields of EventuallyConfig) and ShapeQuery, ShapeObservable (both in surface/use-shape-query.ts, the return shape of useShapeQuery).

They do NOT all resolve the same way:

  • The five EventuallyConfig field types. Each one's own comment says it "exists only to describe what configure receives" - and configure/EventuallyConfig are themselves already, unambiguously, on the deletion list (knowledge_what-an-app-deletes- at-migration.md: "Deleted... today that is configure and its config type"). Their invention/none/none annotation is honest (no kind in the closed set fits better). INFERRED, with strong textual support: these five belong BELOW the divider, beside EventuallyConfig - but moving them is the exact action the task names as requiring a decision, so left untouched.
  • ShapeQuery. VERIFIED: its declared shape - { data, isPending, isSuccess, isError, error } - is the LITERAL shape .project/rules/nextgraph/surface-mirrors-the- sdk.md records as NextGraph developers' announced direction for useShapeQuery (the same document useShapeQuery itself cites with kind=announced-not-written). The word "ShapeQuery" appears in that record. Its invention/none/none annotation looks like the wrong kind - announced-not-written, citing the same record, would be consistent and would keep it above the divider with no relocation. Not applied: still a change to a load-bearing annotation on a currently-blocked item, held for the same decision.
  • ShapeObservable. VERIFIED: the word "ShapeObservable" does NOT appear anywhere in the announcement record, and VERIFIED in examples/notebook/app.ts:192-217 that this package's useShapeQuery is called as a plain factory (not a React hook) returning an object the caller manually .subscribe()s and .getSnapshot()s - i.e. the getSnapshot/subscribe/refetch wrapper is this package's OWN framework-agnostic composition, not something NextGraph announced. Its invention/none/none annotation is therefore honest. Whether this wrapper is deleted at migration (if the real, eventually-shipped useShapeQuery is itself a plain hook returning the snapshot directly, the way useShape does) or survives (if the real one needs the same kind of wrapper) cannot be determined from anything in this repo - this is the irreducible design question.

No code or annotation changed for item 2 at this point in the session (see "Item 2 - resolution" below for what the coordinator then asked to be applied).

Item 2 - resolution (PART A and B DONE; PART C left to the owner)

The coordinator reviewed the analysis above, agreed the split was right, and asked for Parts A and B to be applied since they are determinable from this repo, with Part C (ShapeObservable) left untouched for the owner.

Part A - the five EventuallyConfig field types (DONE). Verified the precondition before moving anything, as instructed: grepped index.ts for export { configure } and export type { EventuallyConfig } - both sit BELOW the POLYFILL-ERA divider (lines 174- 175 at the time of checking), i.e. already, unambiguously, on the deletion list. Since the precondition held, moved NgLike, UseShapeLike, OrmSubscriptionLike, GetObjectsLike and InsertObjectLike out of the SDK-SHAPED export type { Nuri, NuriLike, PrincipalId, ... } grouping and into a new export type { ... } from "./model/types"; placed right after EventuallyConfig's own export, with prose explaining the move on both sides of the divider. No signature changed - same five names, same five shapes, still exported from index.ts - only which section of the entry documents them.

This is a PATCH by the concept contract's own ## Change policy: nothing under ## Surface or ## Guarantees changed (neither contract document ever separately listed these five as standalone entries - both already only show them as EventuallyConfig's field types, correctly tied to bootstrap), so none of the three major triggers (removed, renamed, narrowed/reshaped) applies, and "a symbol added" doesn't fit either - this is "changes neither the published surface nor anything above ## Guarantees" verbatim. Version bumped 1.0.0-dev.12 -> 1.0.0-dev.13 in packages/polyfill/package.json, a dated patch entry added to the concept contract's ## Change policy, and docs/api-contract.md §14 updated (code block split in two, plus a paragraph) - all in the same commit as the code move.

Part B - ShapeQuery's kind (DONE - the record exists). Checked the precondition the coordinator named: .project/rules/nextgraph/surface-mirrors-the-sdk.md already carries the record useShapeQuery itself cites (kind=announced-not-written ... announced-by= nextgraph-developers@2026-09-16), and that same document's prose states the announced shape verbatim as { data, isPending, isSuccess, isError, error } - identical, field for field, to ShapeQuery's own declared interface - and literally contains the word ShapeQuery (checked with the same word-boundary rule test/provenance.test.ts's deadCitations uses). The record exists, so the kind was re-annotated: ShapeQuery now carries kind=announced-not-written level=3 ref=.project/rules/nextgraph/surface-mirrors- the-sdk.md:ShapeQuery announced-by=nextgraph-developers@2026-09-16, citing the identical statement useShapeQuery cites. ref points at the .md in this working copy, never a source file, per the rule. No version bump: this changes a provenance comment only - invisible to a consumer, no change under ## Surface or ## Guarantees, and ShapeQuery's divider position (above it) was already correct and stays put.

Part C - ShapeObservable (LEFT UNTOUCHED, as instructed). Not moved, not re-kinded, not weakened. It remains kind=invention level=none ref=none, above the divider, exactly as found - the coordinator is putting its migration fate to the owner.

Verified after both parts: test/provenance.test.ts's well-formedness and citation checks pass on the new ShapeQuery annotation, and the announced-not-written malformation tests (which exercise the exact form useShapeQuery uses) still pass unchanged since they test against a literal fixture, not the source tree.

Item 3 - docChangeType absent from the concept contract's Surface (DONE, and pinned)

VERIFIED: docChangeType (lowercase, the function) is exported from index.ts but was absent from .project/concepts/app-contract/polyfill-surface/contract_polyfill- surface.md's ## Surface block. Also VERIFIED that docs/api-contract.md (a separate, still-actively-maintained document at the repo root, distinct from the concept contract - see Surprises) already had it correctly, and is pinned by three existing tests in test/vocabulary.test.ts; the concept contract had NO such test.

Added the docChangeType signature to the concept contract's Surface block, and added a new test, "every 'export' shown in the concept contract's Surface block is actually exported", reusing the same publishedNames()/isNamespaceMember() helpers the existing docs/api-contract.md check uses. VERIFIED the new test actually catches drift: temporarily removed docChangeType from index.ts's export list, re-ran the suite, saw it fail naming exactly docChangeType, then restored the file and confirmed green again (diff checked against the original afterward - clean revert).

Item 4 - stray provenance annotation on resolveScopeGraph (DONE)

VERIFIED: resolveScopeGraph is not re-exported by surface/placement.ts (which backs the published storeRegistry namespace), so storeRegistry.resolveScopeGraph names nothing a consumer can reach - confirmed unpublished since 1.0.0-dev.5 per surface/placement.ts's own comment. VERIFIED its two siblings, resolveWriteGraph and listMyEntityDocs (same file, same unpublished status), carry NO @provenance annotation at all - the established convention for internal/unpublished helpers. Removed the stray @provenance storeRegistry.resolveScopeGraph ... line to match; left the JSDoc comment above it untouched (still an accurate internal note). No test previously caught this because test/provenance.test.ts only checks that every PUBLISHED symbol has an annotation, never the reverse (an annotation naming something that isn't published) - this is a real, un-pinned gap in that test file, left as a follow-up (see below).

Gate (all measured on the final committed state, after item 2 parts A and B)

  • bun test -> exit 0, 492 pass / 0 fail (matches the coordinator's own measured baseline of 492 pass / 0 fail exactly - item 3's new pinning test is the +1 over the original 491 pass / 0 fail, and items 2A/2B added no test and changed none).
  • pnpm exec tsc --noEmit -p packages/polyfill/tsconfig.json -> exit 0.
  • pnpm exec tsc --noEmit -p packages/polyfill/e2e/tsconfig.json -> exit 0.
  • Example typecheck (pnpm run typecheck in examples/notebook) -> exit 0.
  • python3 ~/.claude/skills/concept/lint.py -> exit 0, 0 ERROR (5 pre-existing WARNING categories, none new).
  • e2e harness: NOT run. Nothing changed anywhere in this task (items 1, 3, 4, 2A, 2B) is exercised by it: type-only exports, an annotation moved or re-kinded, doc text, one new bun:test unit test, one dead annotation line removed.

Unused imports in account-registry.ts (confirmed, not touched)

Confirmed the coordinator's reading exactly: publishInboxAddress, readInboxCapsFor, ownsDocument, documentInboxAddress, subscribePhysicalDoc, hasReadCap and mustNotAttempt are each imported into packages/polyfill/src/shared-wallet/account- registry.ts and appear NOWHERE else in that file as executable code - six have exactly 1 occurrence (the import line itself) and ownsDocument has 2, the second being a JSDoc mention ("a caller that genuinely prefers to carry on catches it itself, and one does: ownsDocument, ..."), not a call. VERIFIED noUnusedLocals and noUnusedParameters are absent from both packages/polyfill/tsconfig.json and the tsconfig.base.json it extends, so both default to false - that is why tsc passes despite this. Pre-existing (this task's item 4 commit removed exactly one line, the @provenance annotation on resolveScopeGraph, confirmed by its own diff). Left untouched, as instructed - recorded as a follow-up only.

Surprises

  • VERIFIED, corrected before acting on it: docs/api-contract.md genuinely exists at the repo root and is actively maintained (last touched today by the sibling task, T01.o)
    • I initially looked only under packages/polyfill/docs/ (which holds a different file, polyfill-reference.md) and briefly concluded the file referenced by index.ts's header comment and by test/vocabulary.test.ts was missing/stale. It is not. Two contract documents exist side by side: docs/api-contract.md (detailed, symbol-by-symbol, pinned by three tests) and the concept contract (terser, what a consumer's usage_ leaf pulls against, now pinned by one more test after item 3).
  • INFERRED, not verified, out of scope: the two documents' dual maintenance is itself a standing cost (item 3 is exactly this: one drifted, one didn't) - not something this task was scoped to resolve.

Owner's open item

  • ShapeObservable's migration fate (packages/polyfill/src/surface/use-shape- query.ts:218). Still kind=invention level=none ref=none, still above the POLYFILL-ERA divider, untouched by this task. VERIFIED it is this package's own framework-agnostic getSnapshot/subscribe/refetch composition (examples/notebook/ app.ts:192-217 calls useShapeQuery as a plain factory and manually .subscribe()s/.getSnapshot()s it, not as a React hook), and VERIFIED the word "ShapeObservable" does not appear anywhere in .project/rules/nextgraph/surface-mirrors- the-sdk.md, so the announced-not-written route Part B used for ShapeQuery is not available for it - honestly claiming it would require a record nobody has written. Its divider placement depends on whether NextGraph's eventually-shipped useShapeQuery needs the same wrapper or returns the snapshot directly (the way useShape does), which is not knowable from anything in this repo. The coordinator is putting this to the owner directly.

Follow-ups (not fixed, out of scope)

  • test/provenance.test.ts has no test for the direction item 4 exposed: an @provenance annotation naming a symbol that is not actually published. Only the reverse (every published symbol has an annotation) is pinned.
  • Several docs/api-contract.md / index.ts header comments cite line numbers (e.g. "index.ts:48-49", "index.ts:45, :111-123") rather than symbols, which the project's own citation discipline discourages (line numbers rot); pre-existing, not introduced here, and not mechanically checked.
  • .project/concepts/app-contract/polyfill-surface/contract_polyfill-surface.md is flagged by the concept linter as an oversized leaf (75 KB / 256 lines) - pre-existing, a WARNING not an ERROR, unrelated to this task's changes beyond the lines added across this session.
  • Seven imports in packages/polyfill/src/shared-wallet/account-registry.ts are unused in code (publishInboxAddress, readInboxCapsFor, ownsDocument, documentInboxAddress, subscribePhysicalDoc, hasReadCap, mustNotAttempt) - confirmed above, pre-existing, tsc passes only because noUnusedLocals is off.
  • docs/api-contract.md §1's shown EventuallyConfig interface is itself stale (it includes a pointerGuard field and omits getObjects/insertObject, neither matching the real interface) - noticed while reading that section for Part A, pre-existing, out of scope for this task.