Files
ng-eventually/.tasks/done/T01.k-a-citation-must-say-which-version-it-describes.md
Sylvain Duchesne a7f9f4e18a chore: T01.k est close, la version vit dans l-ancre et non sur 94 citations
Zero annotation touchee, trois citations reparees sur 94 - Scope,
BaseType et le compte de membres de NG - et la refutation de
where/orderBy/pageSize retiree des deux feuilles.
2026-09-24 15:07:14 +02:00

14 KiB

id, title, parent, depends_on, created, claimed_by, claimed_at, blocked
id title parent depends_on created claimed_by claimed_at blocked
T01.k A provenance citation must say which version it describes T01
T01.n
2026-09-21 worker-T01.k 2026-09-24 false

Description

The provenance mechanism cites a source tree that is THREE RELEASES BEHIND what this repo compiles against, and nothing in an annotation says so. A citation therefore proves "this was true at orm alpha.18", while a reader takes it for "this is true of what we build against".

The established facts - VERIFIED, do not re-derive

Scanning every remote branch of /home/sylvain/projects/nextgraph/nextgraph-rs:

source @ng-org/orm version
upstream/main (the real upstream) 0.1.2-alpha.18
origin/main (a fork) 0.1.2-alpha.15
local checkout HEAD 213338f6 0.1.2-alpha.18
what this repo compiles against 0.1.2-alpha.21

So the local checkout is ALREADY at the newest source that exists anywhere reachable. alpha.19, 20 and 21 are published to npm from source that is in no branch of that repository. There is nothing to re-anchor to, and updating the checkout is not the answer. Do not spend time looking for a newer tree; that question is closed.

grep -rho "ref=[^ ]*" packages/polyfill/src/ | grep -cE "engine/|sdk/" counts 96 citations into that tree.

The second-order trap, which has already fired

A claim about alpha.21 REFUTED by reading the pinned tree is refuted against alpha.18 - which is not the same statement. This happened during T01.h: the agent first wrote that alpha.21's where/orderBy/pageSize "became reachable", then retracted it because the pinned engine still has start_orm as json!({}) behind a TODO. The retraction may be right, but the EVIDENCE does not support it at the strength claimed, because the pinned engine is not alpha.21. Re-examine that specific correction in .project/concepts/app-contract/knowledge_what-the-orm-writes-and-deletes-upstream.md and state what can honestly be said about it. A true citation attached to a claim it does not support is the exact failure .project/rules/nextgraph/surface-mirrors-the-sdk.md names.

What to establish - the design is yours

The question is where the version belongs, and the obvious economy is worth weighing before anything else: the version is a property of the CHECKOUT, not of each citation. 96 annotations do not each need to carry it; one place that says "citations into engine/ and sdk/ are anchored at 213338f6 = orm alpha.18, while the build is alpha.21" may carry the whole fact. Weigh that against the alternative, do not assume it.

Then decide what the mechanism should ENFORCE, if anything. packages/polyfill/test/provenance.test.ts already checks that a ref resolves when the sibling checkout is present, and deliberately does NOT check that a claim is true. Adding a version check is a real option; so is deciding that this is doctrine, not a test. Read .project/rules/nextgraph/no-divergence-from-nextgraph.md for the taxonomy before proposing anything, and remember announced-not-written already exists for "the target is stated but the tree carries nothing" - part of this gap may be the same shape.

Do NOT mass-rewrite 96 annotations unless you have established that the fact cannot be carried in one place. A 96-site sweep is a large, risky, low-information change, and this repo's doctrine is explicitly that a good repair usually leaves a leaf SHORTER.

Where a citation genuinely describes something that alpha.21 changed, that is a real finding: record it. But establish it from the published package's own shipped types (node_modules/@ng-org/orm), not by guessing - and say plainly when the shipped artifact cannot settle the question, which it often will not since it carries types, not behaviour.

Verification

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 deleted or skipped test, no weakened assertion.

An adversarial review is part of this task. Angles: a citation that still claims more than its anchor supports; a version statement that is itself already stale; and whether whatever is added would survive the checkout moving. A finding counts only with a concrete scenario.

Progress

Result

Status: done

1. Where the version now lives, and why not on each citation

In one place: the ANCHOR in packages/polyfill/test/provenance.test.ts, beside the resolver that opens the checkout. Annotations touched: 0 of 94. (The task file says 96; the same grep it prescribes returns 94 today, so the figure had drifted by 2 - VERIFIED, flagged here rather than silently reused.)

The economy holds, and it is stronger than "one fact stated 94 times". What a reader needs is not a version but the gap, and a gap has two ends. A per-citation version would record only the near end, would be wrong at all 94 sites at once the day the checkout moves, and would still leave the far end - the installed releases - unstated. The anchor records four rows, (package, cited, built), and three tests check them:

check scope behaviour when it cannot ask
the checkout declares the cited versions 4 rows passes empty-handed, like deadCitations
every workspace manifest pins the built versions discovered from packages/*, examples/* never absent
packages/polyfill/node_modules resolves the built versions 4 rows never absent

Each was mutation-tested: falsifying cited -> "@ng-org/orm - the checkout declares 0.1.2-alpha.18, the anchor says 0.1.2-alpha.19"; falsifying built -> two manifest lines plus the installed-tree line; renaming a row to a package nothing pins -> "the anchor names it, no workspace manifest pins it". With NEXTGRAPH_RS=/nonexistent-checkout the suite is 10 pass / 0 fail. So it survives the checkout moving, by going red with the repair named.

A source-side pointer sits in src/index.ts's provenance block (no numbers - numbers live in one place), and the doctrine sits in .project/rules/nextgraph/no-divergence-from-nextgraph.md.

2. What the mechanism enforces, and what it deliberately does not

It enforces that the gap statement is still true at both ends - the same class of check the file already made (a citation still resolves), never the class it refuses (a claim is true).

It is NOT a new kind. The taxonomy classifies what evidence ONE symbol has; how old ALL the evidence is belongs to the tree. announced-not-written is a different shape: there the tree carries nothing, here it carries an older something. A kind would have pushed a checkout-wide property onto 94 per-symbol labels.

It does not check the commit hash. 213338f6 is recorded as a git show pointer and explicitly labelled not the enforced identity: a checkout at another commit declaring the same releases describes the same code, and going red for a local commit is the red that teaches people to skip the suite.

3. where / orderBy / pageSize - what can honestly be said

The retraction is refuted, and the original claim was closer to right than the retraction. All VERIFIED, each from the artifact that can answer it:

  • Level 3: @ng-org/orm@0.1.2-alpha.21, dist/connector/RdfOrmSubscription.js calls ng.orm_start_graph(options.graphs, options.subjects, shapeType, session.session_id, options, this.onBackendMessage) - the config is sent, at index 4.
  • Level 2: @ng-org/web@0.1.2-alpha.14, dist/index.d.ts declares orm_start_graph(graph_scope, subject_scope, shapeType, session_id, config, callback) - six parameters, the config is accepted. The pinned tree's sdk/js/lib-wasm/src/lib.rs declares five, no config slot, which proves by arity that the pinned tree is older than the binding in this build. A claim about alpha.21 cannot be refuted there.
  • Level 1, at 213338f6: OrmConfig (engine/net/src/orm.rs) declares where_, order_by, select, page_size, max_active_pages; from_json parses all five and refuses a pageSize > 0 without an orderBy; and every field is consumed - schema_shape_to_sparql emits FILTER (|lt/|gt), ORDER BY, LIMIT, OFFSET, and initialize.rs drives the paging window and page eviction. The json!({}) is at the entry point only: start_orm takes no config argument, request_processor.rs calls it with three, and from_json's own TODO names the missing hop - "Use json in libwasm context" - which is exactly the binding parameter the shipped binding now has.

So "the richness is expressible at level 3 and discarded at level 1" / "no caller can reach any of it" was false at the pinned commit too, and it is inference from an absent implementation, which this repo's own rule forbids. Not settled by anything reachable: whether the engine behind that binding feeds the JSON to from_json. The shipped wasm carries no source; only a live measurement answers it, and none has been made. (INFERRED corroboration, not proof: T01.h's live finding that the deployed orm_start_graph already took a config at index 4.)

Both leaves now say this. knowledge_what-a-read-scope-is-upstream.md owns the detail (+10 net lines, 78 lines total, still under the oversize threshold) and knowledge_what-the-orm-writes-and-deletes-upstream.md got shorter (-0 lines, the paragraph shortened and delegates).

4. Citations the installed releases actually invalidated: three of 94

Established from the shipped artifacts, never guessed. Unaffected and verified identical on both sides: the eleven level-2 citations (doc_subscribe, sparql_update, sparql_query, doc_create), plus ShapeType, Schema, DeepSignalSet.

  1. Scope - the cited revision declares graphs? OPTIONAL; @ng-org/orm@0.1.2-alpha.21 makes it required, and index.ts re-exports the installed one. No version note, unlike its neighbours RdfOrmConfig and OrmSubscriptionHandle, which already carried one. Repaired in that same established form.
  2. BaseType - the cited revision keeps "@graph" commented out behind a TODO; @ng-org/shex-orm@0.1.2-alpha.9 declares it. This one matters: the writes leaf documents that an insert must carry @graph, and a reader checking the citation would find the type does not declare it.
  3. NG - the member count. The annotation and eight other places said 88 members. The installed @ng-org/web@0.1.2-alpha.14 declares 90 in its NGModule namespace (84 functions + 6 RDF classes), and two of the ninety - graph_orm_next_page, graph_orm_previous_page - appear 0 times in the cited checkout's lib-wasm/src/lib.rs. Worst instance: docs/api-contract.md carried the 88 under a VERIFIED label, with the stale line range index.d.ts:136-231 (the namespace is at 157 now), one paragraph after saying "MEASURED against @ng-org/web@0.1.2-alpha.14". Repaired by naming the count ONCE with its release (in surface/ng-proxy.ts, where the type lives) and deleting it from the other eight, where the sentence said "all N members" and N added nothing but an occasion to rot. That leaves the claims shorter. INFERRED, not asserted anywhere: that 88 was alpha.13's count - alpha.13 is not on disk, so the text says only that the recorded figure was two short.

No engine/ citation carries a quantitative claim of that kind (checked); engine/ has no published version at all, and the anchor now says so rather than letting a reader think it can refute a release by opening it.

5. The gate, verbatim

  • bun test -> 465 pass, 0 fail, 1316 expect() calls, Ran 465 tests across 40 files. Baseline before any change was 462 pass / 0 fail across 40 files - exactly the figure this task's caller measured, so no discrepancy to flag there. +3 is the three anchor checks.
  • pnpm exec tsc --noEmit -p packages/polyfill/tsconfig.json -> exit=0
  • pnpm exec tsc --noEmit -p packages/polyfill/e2e/tsconfig.json -> exit=0
  • python3 ~/.claude/skills/concept/lint.py -> 0 ERROR; warnings identical to baseline (3 oversized leaves, 2 open _debt.md, 1 unlisted usage_, 5 banned aliases), none added.

No any, no @ts-ignore, no test deleted, skipped or weakened. No citation was made to look right by changing what it claims.

6. Surprises

  • VERIFIED - the gap is four packages wide, not one. The task frames it as orm alpha.18 vs alpha.21. In fact all four installed @ng-org packages are ahead of the checkout: orm 18->21, web 13->14, shex-orm 8->9, alien-deepsignals 11->13. The anchor records all four; an anchor naming only orm would have been a true statement covering a quarter of the surface.
  • VERIFIED - the pinned tree is provably older than the binding in the build, by arity, not by version string. That single fact is what refutes the retraction, and it was available in two greps.
  • VERIFIED - sdk/js/lib-wasm has no package.json. It is the Rust crate that builds the binding; twelve citations point into it and their published identity is @ng-org/web. The anchor says so explicitly.
  • VERIFIED - the published artifacts ship JS, not only types. The task expected the shipped artifact would usually fail to settle behaviour. @ng-org/orm's dist/ carries the real call sites, which is what settled level 3 here.
  • VERIFIED, self-inflicted and caught by the gate - a literal /* written inside a // annotation silently disabled the comment-stripping regex (.replace(/\/\*[\s\S]*?\*\//g, "")) in moduleExports, swallowing seven export type { ... } lines and failing vocabulary.test.ts. Fixed by rewording. The parsers in provenance.test.ts and vocabulary.test.ts are fragile this way: they strip block comments before line comments, so any /* inside a // comment eats the file to the next */. Reported below.

Follow-ups, none fixed

  • provenance.test.ts / vocabulary.test.ts moduleExports: strips /* ... */ before // ..., so a /* inside a line comment silently swallows source. A one-line reorder would close it.
  • The NG member count is still hand-measured. It is now version-named in one place, but a test could count the installed NGModule and pin it, turning doctrine into a gate.
  • docs/api-contract.md still cites line ranges into installed .d.ts files elsewhere; line numbers rot, and the repo's own rule says a ref cites a symbol.
  • Whether the deployed engine honours where/orderBy/pageSize is open and only a live measurement closes it. It would be a real finding either way.