Files
ng-eventually/.tasks/done/T01.n-a-peer-range-that-excludes-what-we-need.md
T
Sylvain Duchesne a0bedbf696 chore: T01.n est close - les quatre peers sont fixes par resolution, le script ajoute
Digest complet dans le fichier de tache : les quatre ranges "*" du
polyfill mesurees contre le registre (orm etait le cas le pire, "*"
n'y admettait aucune version), le plancher choisi par paquet a partir
du devDependencies actuel plutot que copie de ng-e2e-helpers, le
verdict peerDependenciesMeta confirme par lecture du code (imports
type-only uniquement), et l'installation fraiche verifiee a une seule
copie de chaque @ng-org.
2026-09-24 14:46:03 +02:00

9.4 KiB

id, title, parent, depends_on, created, claimed_by, claimed_at, blocked
id title parent depends_on created claimed_by claimed_at blocked
T01.n The polyfill's peer ranges exclude exactly the versions it needs T01
T01.m
2026-09-24 worker-T01.n 2026-09-24T12:39:21Z false

Description

Two loose ends from T01.l, the first of which is a published-surface defect waiting for the first publish.

1. Four peer ranges that admit nothing usable

packages/polyfill/package.json declares all four @ng-org/* peers as "*". In semver, * matches NO pre-release version. MEASURED by T01.l against the registry: of the 16 published versions, that range admits ONLY the bare 0.1.2 (dated 2025) and EXCLUDES every 0.1.2-alpha.N - which is precisely what this package is built against and needs.

It is inert today only because the polyfill itself is not published (a registry query for it returns E404), so no consumer has ever resolved these peers. It is certain to surface at the first publish, as an unsatisfiable or wrongly-satisfied peer for every application installing this package.

Fix the four ranges so they admit the alphas this package actually works with and exclude the stale bare 0.1.2. T01.l's tightening of ng-e2e-helpers to >=0.1.2-alpha.13 <0.1.2 is the shape that was measured to work - decide whether the same bound is right here, given the polyfill is built against orm alpha.21 rather than web alpha.14.

VERIFY BY RESOLUTION, NOT BY READING. This is the whole lesson of T01.l: the range it was sent to fix had a real defect, but the stated failure mode was wrong, and only a resolution test showed which part was true. Query the registry, compute what the range admits before and after, and paste both counts. A range that looks right and resolves wrong is the entire failure mode here.

Check peerDependenciesMeta at the same time. All four are declared optional; confirm that is still the intent for each, since T01.l MEASURED that a consumer receives none of them under pnpm while this checkout gets the ORM through a devDependency.

2. The example has no typecheck script

examples/notebook typechecks correctly when invoked directly, but carries no typecheck script, so nothing in the repo runs it and its green state depends on someone remembering the command. Add the script. Do not build tooling around it.

Verification

Hard gate: bun test -> 0 fail (baseline 449 pass / 0 fail, measured); pnpm exec tsc --noEmit -p packages/polyfill/tsconfig.json -> exit 0; pnpm exec tsc --noEmit -p packages/polyfill/e2e/tsconfig.json -> exit 0; the example's typecheck via its new script -> exit 0; python3 ~/.claude/skills/concept/lint.py -> 0 ERROR.

A fresh rm -rf node_modules && CI=true pnpm install --no-frozen-lockfile must end with ONE copy of each @ng-org package - verify what each resolves to rather than trusting a silent install. Two copies of a package holding module-level state means two registries and two identities, which is this package's own named hazard.

Anti-cheat: no widening a range to silence a warning, and no any, @ts-ignore, deleted or skipped test.

Every quantitative claim carries the number that supports it in the same sentence.

Progress

Result

Status: done Commits: 3aa3fb2 (item 1, peer ranges), f417841 (item 2, example typecheck script).

1. The four peer ranges - VERIFIED BY RESOLUTION, per-package floor

Method: registry version lists pulled from registry.npmjs.org (public npm, confirmed as the active registry via pnpm config get registry), admitted-set and maxSatisfying computed with the real node-semver engine (pnpm dlx semver -r '<range>' <versions>), not by reading the range.

package published versions BEFORE "*" admits BEFORE maxSatisfying AFTER range AFTER admits AFTER maxSatisfying
@ng-org/web 16 1 (0.1.2) 0.1.2 >=0.1.2-alpha.14 <0.1.2 2 (alpha.14, alpha.15) 0.1.2-alpha.15
@ng-org/orm 22 0 (no bare 0.1.2 exists) none >=0.1.2-alpha.21 <0.1.2 2 (alpha.21, alpha.22) 0.1.2-alpha.22
@ng-org/shex-orm 11 1 (0.1.2) 0.1.2 >=0.1.2-alpha.9 <0.1.2 2 (alpha.9, alpha.10) 0.1.2-alpha.10
@ng-org/alien-deepsignals 15 1 (0.1.2) 0.1.2 >=0.1.2-alpha.13 <0.1.2 2 (alpha.13, alpha.14) 0.1.2-alpha.14

VERIFIED: orm's BEFORE case is worse than the other three - "*" was not "wrongly satisfied", it was unsatisfiable (0 of 22 versions admitted), because orm has never published a bare 0.1.2 at all - every one of its 22 releases is a prerelease.

Floor choice, per package, not copied from ng-e2e-helpers. ng-e2e-helpers's floor (alpha.13 on web) predates its own current devDependency pin (alpha.14) - it is a historical artifact, not a re-derivable rule. Instead the floor used here is each package's own current devDependencies pin in packages/polyfill/package.json (web alpha.14, orm alpha.21, shex-orm alpha.9, alien-deepsignals alpha.13) - the one version each package is actually built and tested against today, VERIFIED against the manifest (not trusted from the task prompt). Upper bound <0.1.2 applied uniformly, including to orm, as a precaution against a future stable release repeating the same-shape inversion the other three already exhibit.

2. peerDependenciesMeta - optional:true is correct for all four, VERIFIED by source inspection

grep of packages/polyfill/src shows every @ng-org/* reference is import type only (index.ts:143,145,150,156,158; model/types.ts:8,12,13; surface/orm.ts:73-74; surface/use-shape-query.ts:185-186; surface/ng-proxy.ts:7) - zero runtime imports. The real functions (ng, getObjects, insertObject, RdfOrmSubscription.getOrCreate, initNg) are injected by the consuming app via bootstrap.ts, not imported by the polyfill. The polyfill's own runtime never needs these packages present; only its published .d.ts needs their types at the consumer's compile time - exactly what an optional peer expresses. examples/notebook/package.json confirms the pattern in practice: it declares @ng-org/orm and @ng-org/web itself, and the polyfill supplies none of them (T01.l's own measurement, unchanged here).

3. Example's typecheck script

examples/notebook/package.json scripts: "typecheck": "pnpm exec tsc --noEmit -p tsconfig.json" (mirrors packages/ng-e2e-helpers's script). No tooling built around it, as instructed.

4. Fresh-install duplication check - ONE copy of each, VERIFIED

rm -rf node_modules packages/*/node_modules examples/*/node_modules && CI=true pnpm install --no-frozen-lockfile -> "Lockfile is up to date, resolution step is skipped", "Scope: all 4 workspace projects", Packages: +113.

node_modules/.pnpm holds exactly one store entry per package: @ng-org+web@0.1.2-alpha.14, @ng-org+orm@0.1.2-alpha.21, @ng-org+shex-orm@0.1.2-alpha.9_typescript@5.9.3, @ng-org+alien-deepsignals@0.1.2-alpha.13. Resolving @ng-org/* by readlink -f from all three consuming projects (packages/polyfill, packages/ng-e2e-helpers, examples/notebook) lands on the exact same realpath per package - confirmed for all combinations present (web from all three, orm from polyfill and the example). No second copy anywhere.

Hard gate, verbatim, measured after the fresh install above

  • bun test -> 462 pass, 0 fail, 1313 expect() calls, Ran 462 tests across 40 files.
  • pnpm exec tsc --noEmit -p packages/polyfill/tsconfig.json -> exit 0
  • pnpm exec tsc --noEmit -p packages/polyfill/e2e/tsconfig.json -> exit 0
  • cd examples/notebook && pnpm run typecheck -> exit 0
  • python3 ~/.claude/skills/concept/lint.py -> 0 ERROR (4 pre-existing WARNING groups: 3 oversized leaves, 2 open _debt.md, 1 unlisted usage_, 5 banned-alias hits - none introduced by this task)

Surprises

  • VERIFIED, contradicts this task file's own Description: the Description above states baseline 449 pass / 0 fail, but the orchestrator's live instruction and my own measurement (both before and after the change, on this checkout) show 462 pass / 0 fail. The file's own text is stale relative to the branch's current state - flagging rather than silently using either number without support.
  • VERIFIED: @ng-org/orm's "*" was not merely "admits the wrong one" like the other three - it admitted zero versions, a strictly worse defect than the one the task description generalizes from.
  • INFERRED, not re-verified in this task: ng-e2e-helpers's own floor (alpha.13 vs its devDependency pin alpha.14) looks like the same kind of staleness this task fixed for the polyfill. Left untouched - it belongs to a package this task was not asked to touch, and re-opening it was not requested.
  • pnpm-workspace.yaml now lists examples/* (fresh install reports "all 4 workspace projects"), where T01.h/T01.l had reported examples/notebook outside pnpm's scope. Already fixed by an earlier task; not something this task touched.

Found broken, left alone (out of scope)

  • Concept lint's 4 pre-existing WARNING groups (see gate line above) - unrelated to this task's files.
  • Doc-debt auto-log .project/concepts/app-contract/_debt.md gained one entry from a repo hook on editing examples/notebook/package.json; recorded automatically, not authored content, left as the hook produced it.

Not touched: ng-helpers (not read, only its published contract/usage), docs/briefs/2026-08-10-consumer-harness-identity-switching.md, T01.k, T01.g.