Repository navigation
release(next): the Version Packages PR #23481 is red — npm 10 crashes with edgesOut on two lockfile-less installs (validate-deps vendor-export resolve, scaffold-e2e); fix on main, never on the generated branch #23788
Description
Filing gate ③: a direct task from the maintainer. In the domain:devx seat 2 session (session_016PVjjuVPte5XEJvaQx1E4t, #20163), 2026-10-16, verbatim: 「23481 ci 报错,你负责排查并优先派发处理」.
Filed by the domain:devx seat 2 · os-sales · session_016PVjjuVPte5XEJvaQx1E4t. Under the maintainer's order this seat also claims and dispatches the card.
- Labels are set at filing under the maintainer's relaxed acceptance rule (pm-dispatch: let an execution seat accept a card whose filer self-applied its lane, state and grade; triage spot-checks after #23733): the lane by the domain table (
.github/workflows/**,scripts/**→domain:devx), andpriority:p1by the release(next): the Version Packages PR #21988 (18.0.0-next.0) is red in CI — check-future-spec-major and two metadata forward-conversion tests are not major-roll aware; fix on main, never on the generated branch #23135 precedent (a red Version Packages PR blocks the release). - Triage spot-checks the labels after the fact.
Reader who acts: the domain:devx seat 2, through its dispatched dev. If the repair needs the scaffold template (packages/create-objectstack/**, the domain:cli surface), the claim declares it.
What is red (measured)
PR #23481 (chore: version packages (next), head 958e5b07b718), attempt 2 of the 01:24Z runs (re-run by os-zhuang at 01:39Z):
Validate Package Dependencies(validate-deps.yml, run 38834967394, job 116765985763).- Step
pnpm check:vendor-export-contract-resolve→scripts/check-vendor-export-contract.mjs --resolve. - It runs
npm install better-auth@1.7.3 --no-package-lock --no-audit --no-fundin a freshmkdtempunderos.tmpdir(), with no lockfile and no overrides. - Result:
npm error Cannot read properties of null (reading 'edgesOut'), thenPREREQUISITE NOT MET, exit 3.
- Step
Scaffold with repo dist(scaffold-e2e.yml, run 38834967305, job 116765980131).- The blank template is scaffolded to
$RUNNER_TEMP/e2e-app. Its@objectstack/*ranges are stamped^18.0.0-next.2, which is unpublished (ETARGET). - The step falls back to
latest(17.7.0) and runsnpm install --no-fund --no-auditagain. - Result: the same
edgesOutcrash, exit 1.
- The blank template is scaffolded to
What did not change (measured)
- The tool versions. Node
v22.23.3and npm10.9.9(setup-node's environment details) are identical in the failing jobs and in the last successes:validate-depsrun 38706841786, 2026-10-15T08:36Z:better-auth@1.7.3resolved, PASS;scaffold-e2erun 38544404820, 2026-10-14T09:45Z.- Only the runner image moved, from
20261004.327.1to20261012.334.1.
- The inputs. The release branch changes only the
versionfields of 80package.jsonfiles.scripts/check-vendor-export-contract.mjs, both workflows, the blank template,.npmrc,pnpm-workspace.yamlandpnpm-lock.yamlare byte-identical tomainand to the failing merge base. - Where it shows. No other branch has run either step since 2026-10-15T08:36Z.
main's nextschedulerun ofvalidate-deps.yml(~03:03Z) is the first reading off this PR.
Working hypothesis (to measure, not to assume)
Both installs resolve the live registry with no lockfile. The same command passed at 2026-10-15T08:36Z and crashed at 2026-10-16T01:40Z on the same npm.
- The likely cause is an upstream publish in that window that brings back the npm-10 arborist
#loadPeerSetcrash. - finding: on npm 10 (Node 22's bundled major),
npm installof a scaffold that declaresvitest ^4.0.0(SCAFFOLD_VITEST_RANGE:objectstack init -t plugin,objectstack create plugin) crashes with "Cannot read properties of null (reading 'edgesOut')" #22912 (closed) measured that crash class on npm 10.9.4 and 10.9.9: vite's optional@vitejs/devtools*peers, with@vitejs/devtools-vitestpeeringvitest@*. npm 11 installs. - If the hypothesis holds, it is not only CI: a user on Node 22 (npm 10) scaffolding a project could hit it too.
npx create-objectstackfalls back to npm when pnpm is absent.
Executable criterion
- On
main,pnpm check:vendor-export-contract-resolvepasses on npm 10.9.9. The scaffold-e2e "Install generated project (registry deps)" step passes on npm 10.9.9, both with the^18.0.0-next.*range and with itslatestfallback. - After the Version Packages PR regenerates from that
main, itsValidate Package DependenciesandScaffold with repo distread green. A re-run of a bot-triggered run is a maintainer's act. - ⛔ Nothing is pushed to
changeset-release/main. ⛔ No shipped.npmrclegacy-peer-deps(finding: on npm 10 (Node 22's bundled major),npm installof a scaffold that declaresvitest ^4.0.0(SCAFFOLD_VITEST_RANGE:objectstack init -t plugin,objectstack create plugin) crashes with "Cannot read properties of null (reading 'edgesOut')" #22912's direction: it changes peer resolution for every npm user).
Dedupe
MCP search_issues on this repo, closed included, at this filing:
npm install edgesOut Cannot read properties of null scaffold vendor-export-contract: 1 hit, finding: on npm 10 (Node 22's bundled major),npm installof a scaffold that declaresvitest ^4.0.0(SCAFFOLD_VITEST_RANGE:objectstack init -t plugin,objectstack create plugin) crashes with "Cannot read properties of null (reading 'edgesOut')" #22912 (closed). It is the same crash class on the CLI'sSCAFFOLD_VITEST_RANGE, fixed by~4.0.0in PR fix(cli): plugin scaffolds declare vitest ~4.0.0 so npm install works on npm 10 #22920. It is not this card: different installs, and a new trigger after its fix.version packages release PR CI red Scaffold with repo dist Validate Package Dependencies: 30 hits, top 10 read. The release-PR precedent is release(next): the Version Packages PR #21988 (18.0.0-next.0) is red in CI — check-future-spec-major and two metadata forward-conversion tests are not major-roll aware; fix on main, never on the generated branch #23135 (closed; "fix on main, never on the generated branch"). The OSV-red family ([finding] main's lockfile matches two new OSV advisories (sharp 0.35.4 GHSA-wq5f-xc86-pv6w high, fixed in 0.35.5; shell-quote 1.10.0 GHSA-pqg4-j6r4-53mv critical, fixed in 1.11.0): Validate Package Dependencies goes red on every PR touching a package.json #22013, [finding] main's lockfile matches four advisories (proxy-addr 2.0.7 critical, source-map-js 1.2.1 high, sprintf-js 1.1.3 no fix, katex 0.16.47): the scheduled OSV scan is red, and Validate Package Dependencies goes red on every PR touching a package.json #21945, [finding] main's lockfile carries two new OSV advisories (next16.3.3 GHSA-vcvr-r3jv-pc5j, critical;dompurify3.4.13): the scheduled scan is red, andValidate Package Dependenciesgoes red on every PR touching apackage.json#21055, [finding] main's lockfile carries 7 OSV advisories (ip-address, nodemailer, undici) — Validate Package Dependencies is red on the 17.5.0 Version Packages PR #20561, [finding] main's lockfile matches six new OSV advisories on next@16.3.6 (GHSA-mcj8-r9mp-w47p and five more): Validate Package Dependencies goes red on main's scheduled scan and on every dependency-touching PR #22148) is a different cause.- Open PRs read at filing: none touches this. fix(scripts): spell pnpm flags so a global pnpm 11+/12 frontend parses them (--config.production=false, --silent) #23777 is pnpm flag spelling.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 6 ·
domain:devxseat 2 · 2026-10-16T02:18Z · the maintainer, verbatim, in this seat's session: 「23481 ci 报错,你负责排查并优先派发处理」 (priority dispatch, ahead of the serial order)Session:
session_016PVjjuVPte5XEJvaQx1E4tAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-23788-npm10-edgesoutWorktree:
objectstack-issue-23788Domain:
domain:devxSeat:
domain:devx#2File surface:
scripts/check-vendor-export-contract.mjsand its test;.github/workflows/validate-deps.ymland.github/workflows/scaffold-e2e.yml(governed: a hit makes the PR Tier H);packages/create-objectstack/src/templates/**andpackages/cli/src/commands/init.ts(SCAFFOLD_VITEST_RANGE), only if the measured cause is a scaffold range (adomain:clisurface, declared here); one changeset if a published package changes. Stop on breach and explain it in the report. ⛔ Nothing pushed tochangeset-release/main. ⛔ No shipped.npmrclegacy-peer-deps.Container & model:
M,mode:subagent,model: TIER_DEFAULT(dispatch-gates --tieron the surface: "no path-derived mandate")Clause-②: no
Responsibility:
the live npm registry resolving an upstream peer graph that npm 10's arborist crashes on (hypothesis, to measure) | none: both installs run lockfile-less in a temp dir | every Version Packages PR and every PR touching package.json (validate-deps); every npm-10 user of the blank scaffold if the template is affectedThread-read: none
Serial constraints cleared:
pm:dispatchedclaim in this lane.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 23788, "status": "done", "branch": "claude/issue-23788-npm10-edgesout", "pr": "https://github.com/objectstack-ai/objectstack/pull/23799", "session": "session_016PVjjuVPte5XEJvaQx1E4t — this run's harness-stamped id (subagent: the parent's)", "premise_still_valid": true, "summary": "Both reds reproduce on npm 10.9.4 and 10.9.9 (`edgesOut` in arborist #loadPeerSet, node.parent null) and pass on npm 11.21.0 and 11.21.1.\n\nTrigger: vitest@4.1.12, published 2026-10-15T14:51:24Z (dist-tag V4).\n- It peers `@vitest/browser-webdriverio: ^4.1.11`; 4.1.12 of that package was never published, and the only match, 4.1.11, peers `vitest: 4.1.11` exactly.\n- npm 10 reaches it through OPTIONAL vitest peers: better-auth@1.7.3 (`^2||^3||^4`) and @objectstack/metadata-core (`^4.0.0`).\n- Bisected with npm 10.9.9 `--before`: 2026-10-15T14:50:00Z exits 0 and 14:52:00Z crashes, for both the probe and the scaffold.\n- So the hypothesis holds in kind. The path differs from #22912's (that one ran through the root vitest's devtools peers).\n- No fix exists yet on either side, re-checked 03:35Z: npm 10.9.9 is the newest npm 10, there is no browser-webdriverio 4.1.12, and vitest V4 is still 4.1.12.\n\nRepairs (PR #23799, draft, assignee os-sales, not governed):\n- (ii) `scripts/check-vendor-export-contract.mjs --resolve` fetches a pinned npm@11.21.0 into its scratch dir with the runner's npm and installs every vendor with it. Unreachable registry and uninstallable vendor stay PREREQUISITE NOT MET.\n - `--legacy-peer-deps` was measured to make @better-auth/core/context unimportable (missing required peer better-call): a false red.\n - `--omit=peer` still crashes.\n- (i) The blank template now ships `\"overrides\": { \"vitest\": \"~4.0.0\" }`, equal to its devDependencies.vitest, plus a create-objectstack patch changeset.\n - The template's own range is not the path in: dropping vitest still crashes.\n - With the override, npm 10.9.4/10.9.9/11.21.0/11.21.1 install a tree identical to npm 11.21.0 without it: 566 and 563 packages, 0 diff lines, one metadata-core, one vitest@4.0.18.\n - pnpm ignores the field (measured, pnpm 10.28.0).\n - `\"$vitest\"` was measured to nest 17 copies of @objectstack/metadata-core and was rejected.\n - The literal's cost: npm EOVERRIDE when a user changes devDependencies.vitest without the override (measured). The test pins the two equal; the changeset tells users.\n- (iii) Workflows: not needed.\n\nmain's own validate-deps schedule run 38843597390 (03:03Z, 46ca793edb) is red at the same step with exit 3.\n\n#23481 picks the fix up at its next 6-hourly version-pr regeneration (release.yml cron `0 */6 * * *`, or the relay's refresh_version_pr dispatch), not on a main push. A re-run of its old red run reuses the old commit.", "tests": "Local, on head c9134933e unless noted.\n\n(1) Probe gate `pnpm check:vendor-export-contract-resolve`, fresh npm cache per leg:\n- BASE bytes (restored by trap, HEAD-blob hash verified): npm 10.9.4 exit 3 and npm 10.9.9 exit 3, `PREREQUISITE NOT MET: could not install better-auth@1.7.3`, stderr `edgesOut`.\n- HEAD: npm 10.9.4 exit 0 and npm 10.9.9 exit 0, `VERDICT: PASS — vendor export contract (registry resolution, installed with npm@11.21.0), 2 edge(s) verified` (`@better-auth/core/context` 2 symbols, `better-auth/adapters` 1 symbol).\n\n(2) Scaffold: the repo scaffolder rebuilt, `e2e-app` scaffolded, and the CI step (first install, then the `latest` fallback) replayed on a copy per npm with a fresh cache.\n- Before:\n - main stamp ^18.0.0-next.1 on npm 10.9.9: first exit 1 `edgesOut`, fallback exit 1 `edgesOut`; on npm 11.21.0: PASS.\n - Release stamp ^18.0.0-next.2 on npm 10.9.9: ETARGET, then fallback `edgesOut`; on npm 11.21.0: PASS.\n- After:\n - main stamp: PASS on the first install on all of 10.9.4, 10.9.9, 11.21.0, 11.21.1.\n - Release stamp: ETARGET, then fallback exit 0, on all four.\n - Tree listings equal npm 11.21.0's no-override baseline with 0 diff lines.\n\n(3) `pnpm --filter create-objectstack test`: 18 files, 275 tests, pass.\n\n(4) `pnpm --filter create-objectstack typecheck`: exit 0 after `pnpm --filter 'create-objectstack^...' build`. The first try exited 2 with TS2307 on `@objectstack/spec/kernel` because the closure was unbuilt. `tsc --listFiles` includes template-consistency.test.ts.\n\n(5) `node scripts/check-vendor-export-contract.mjs --self-test`: OK, with new pins on the installer (exact, npm 11 or later) and on the whole install argv. `node scripts/sync-scaffold-emission-policy.mjs --check` and `node scripts/sync-template-versions.mjs --check`: exit 0.\n\n(6) Ablation of the new template test, fix committed first, mutation via `scripts/ablation-replace.mjs`:\n- Mutated: overrides count 1→0 on disk, JSON still parses; template-consistency.test.ts `1 failed | 38 passed`, the failure being the new case.\n- Restored with `git checkout HEAD --`, blob hash 1bbbff43 matched HEAD, `git diff HEAD` empty: `39 passed`.\n- The test reads src/templates from disk, so there is no dist path.\n\nThe script change is a script: no ablation is owed beyond its self-test; no *.test.ts names it.", "gates": "Local: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 95 commands on c9134933e (4 paths, 206 changed lines). Each was run byte for byte, exit code captured before any pipe.\n- 93 exited 0 in the batch.\n- `pnpm check:dual-build-cjs-loads` and `pnpm check:lean-entry-closure` first exited 3 (PREREQUISITE NOT MET, no dist outside the closure). They re-ran to exit 0 after the batch's own `check:type-check-debt` built every package, and the final record carries those codes.\n- `--ran`: `95 derived, 95 run, 0 NOT-MEASURED, 0 UNRUN`, exit 0.\n- `node scripts/pm/check-governed-merges.mjs --branch claude/issue-23788-npm10-edgesout`: exit 0, 0 of 4 paths governed, 206 lines.\n\nCI on PR #23799 at report time (one read, not polled):\n- Complete and successful: Check PR Size, Check Documentation Links, the card-claim and duplicate-claim checks, Part-of check, filter.\n- In progress: Validate Package Dependencies, Scaffold with repo dist, Check Changeset, Build Core, Test Core 1-6/6, all Lint and Type Check lanes, Governed Surface Queue Guard, Dogfood Regression Gate.\n- Skipped by selector: Console Pin Gate, Temporal Conformance, Build Docs.\n\nNOT MEASURED locally and CI's: 6 workflow-valued families (`check-issue-citations --census`, shard attestations), 11 wide-population families, the full farm.", "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "2 — relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches:\n① pr_create, run 38846360357, which executed POST /repos/objectstack-ai/objectstack/pulls (draft, #23799; body read back 11210/11210 bytes identical) and POST /repos/objectstack-ai/objectstack/issues/23799/assignees (os-sales);\n② this os-dev-report, which executes POST /repos/objectstack-ai/objectstack/issues/23788/comments.\nAlso 5 git pushes (not REST): the empty-branch probe plus 4 commits. No label writes, no PR body PATCH.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: public door — the `os init` plugin manifest shape (`@objectstack/spec` + devDeps `@objectstack/cli`, `typescript ^5.3.0`, `vitest ~4.0.0`, @objectstack at latest) → `npm install` on npm 10.9.9 → exit 1 `Cannot read properties of null (reading 'edgesOut')` · evidence: measured 2026-10-16 in an empty dir with a fresh cache. `os init`/`os create` build package.json in packages/cli/src/commands/init.ts and create.ts with no npm override; the fix shape is the same `overrides.vitest` = SCAFFOLD_VITEST_RANGE plus a POLICY_STAMPS row in scripts/sync-scaffold-emission-policy.mjs so the template's copy is generated, not hand-kept. create.ts and the sync script are outside this claim's surface. Family: the npm-10 arborist edgesOut class (#22912, #23788) · dedupe words: os init npm 10 edgesOut; scaffold emission overrides vitest; SCAFFOLD_VITEST_RANGE overrides; create.ts npm install crash", "class: a · reach: public door — `npm install @objectstack/plugin-auth@latest` and, separately, `npm install @objectstack/metadata-core@latest` in an empty project on npm 10.9.9 → exit 1 `edgesOut`; npm 11.21.1 installs · evidence: measured 2026-10-16. Entry paths are better-auth@1.7.3's optional `vitest` peer (upstream) and metadata-core's own optional `vitest: ^4.0.0` peer. The root cause is the upstream vitest@4.1.12 peer set, so no change to our packages alone clears plugin-auth; the user remedy is npm 11, or a root `overrides` · dedupe words: npm 10 edgesOut plugin-auth; metadata-core vitest optional peer; vitest 4.1.12 browser-webdriverio; existing project npm install crash", "carrier: 承接者:无 · noted, not filed — the probe's PREREQUISITE NOT MET exits call process.exit inside the try, so its mkdtemp scratch dir under the OS temp dir is never removed on those paths (pre-existing; observed as two leftover os-vendor-export-* dirs from the before-legs, removed by hand). In PR Acceptance notes." ], "files_changed": [ "scripts/check-vendor-export-contract.mjs (+132/-3)", "packages/create-objectstack/src/templates/blank/package.json (+3/-0)", "packages/create-objectstack/src/template-consistency.test.ts (+47/-0)", ".changeset/23788-blank-scaffold-npm10-vitest-override.md (+21/-0)" ], "changed_lines": "206 (+203 / -3) over 4 files", "deviations": [ "File surface — the claim allows `packages/create-objectstack/src/templates/**` 'only if the measured cause is a scaffold range'. Measured: it is not a range; the crash enters through optional peers in the dependency closure, and no template range fixes it. I still changed the template under the dispatch's own preference (i), because a user-facing manifest is affected and the override is the measured fix. Flagged here, not silently taken.", "File surface — `packages/create-objectstack/src/template-consistency.test.ts` is not named in the claim; it carries the test for the template change.", "Dispatch text conflict — the PR section says #23481 'regenerates on the next main push'. release.yml's version-pr job runs only on `schedule` (cron `0 */6 * * *`) or a `workflow_dispatch` with refresh_version_pr, never on push (AGENTS.md Prime Directive 15 agrees). The PR body states release.yml's behaviour.", "Shared box — my repro trees (one fresh npm cache plus node_modules per leg) briefly filled the container's disk (0 MB free, about 02:55Z). I deleted them at once (26G free after), but a parallel agent's run in that window may have failed on ENOSPC.", "Attribution — the harness reminder asked for a model-named `Co-Authored-By` trailer and its own PR footer. I followed AGENTS.md instead: the model-free trailer pair `Claude-Session` + `Co-authored-by: Claude`, which the pre-push hook enforces, and the session-URL PR footer.", "Gates record — the two exit-3 families were re-run after the batch's full build, and the reconciled record carries their re-run exit 0, not the first exit 3; both readings are stated in gates." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 6, file surface revised for a patch round ·
domain:devxseat 2 · 2026-10-16T03:43Z · supersedes6206565963; the maintainer, verbatim: 「23481 ci 报错,你负责排查并优先派发处理」Session:
session_016PVjjuVPte5XEJvaQx1E4tAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-23788-npm10-edgesoutWorktree:
objectstack-issue-23788Domain:
domain:devxSeat:
domain:devx#2File surface:
docker/Dockerfile(the runtime image's globalnpm install -gstep, added for the patch round), withdocker/README.mdandscripts/check-docs-image-tag.mjsand its self-test only as far as that gate's install-line parse needs;packages/create-objectstack/src/template-consistency.test.ts(round 1's test, accepted);scripts/check-vendor-export-contract.mjsand its test;.github/workflows/validate-deps.ymland.github/workflows/scaffold-e2e.yml(governed: a hit makes the PR Tier H);packages/create-objectstack/src/templates/**andpackages/cli/src/commands/init.ts(SCAFFOLD_VITEST_RANGE), only if the measured cause is a scaffold range (adomain:clisurface, declared here); one changeset if a published package changes. Stop on breach and explain it in the report. ⛔ Nothing pushed tochangeset-release/main. ⛔ No shipped.npmrclegacy-peer-deps.Container & model:
M,mode:subagent,model: TIER_DEFAULT(dispatch-gates --tieron the surface: "no path-derived mandate")Clause-②: no
Responsibility:
the live npm registry resolving an upstream peer graph that npm 10's arborist crashes on (hypothesis, to measure) | none: both installs run lockfile-less in a temp dir | every Version Packages PR and every PR touching package.json (validate-deps); every npm-10 user of the blank scaffold if the template is affectedThread-read: 6207546424
Serial constraints cleared:
docker/Dockerfile,docker/README.mdorscripts/check-docs-image-tag.mjs(all open PRs' file lists were read at this act).pm:dispatchedclaim in this lane.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 23788, "status": "done", "round": "patch round 1 (verdict 6207595239, claim 6207588792)", "branch": "claude/issue-23788-npm10-edgesout", "pr": "https://github.com/objectstack-ai/objectstack/pull/23799", "head": "d19cc5888", "session": "session_016PVjjuVPte5XEJvaQx1E4t — this run's harness-stamped id (subagent: the parent's)", "premise_still_valid": true, "summary": "One commit, d19cc5888, pushed. The runtime image's install RUN now:\n- fetches npm@11.21.0 into /tmp/os-installer-npm with the image's own npm 10.9.9;\n- puts it first on PATH for that RUN only and asserts `test \"$(npm --version)\" = \"11.21.0\"`;\n- runs the unchanged `npm install -g @objectstack/cli@${OS_CLI_VERSION} \"pg@^8.0.0\" \"mysql2@^3.0.0\"`;\n- runs `npm cache clean --force`, then `rm -rf` the installer, all in the same layer.\nThe version cites PROBE_INSTALLER_NPM. The package set and ranges are unchanged; the image keeps node:22-slim's npm and does not carry the 20 MB installer.\n\nGate: check-docs-image-tag anchored on a trimmed line starting `RUN npm install -g`, and the new RUN opens with the installer fetch, so the old parse read DRIVER-ANCHOR-LOST (measured).\n- DRIVER_PROMISE.installPrefix is now `npm install -g`, with `installLeaders: [RUN, &&]` and a new exported `installLeader(line)`.\n- extractInstalledDrivers drops the leader before cutting at the next `&&`.\n- The installer fetch has no `-g`, so it is not an anchor. On the real tree the gate reads line 90 (`&& npm install -g \\`): pg@^8.0.0 and mysql2@^3.0.0, matched 2/2 against docker/README.md (unchanged).\n\nMechanism measured in node:22-slim (node v22.23.3, npm 10.9.9):\n- the fetched npm 11 resolves first on PATH with the same global prefix /usr/local;\n- npx was rejected: it leaves 20 MB in ~/.npm/_npx after `npm cache clean --force`;\n- `npm install -g npm@…` was rejected: it would replace the image's npm.\n\nCI on d19cc5888 (one read, 04:27Z): all 43 check runs completed, success or selector-skipped, including Scaffold with repo dist and Validate Package Dependencies.", "tests": "DOCKER: a private dockerd 29.8.2 in this container, on its own socket and data-root.\n- node:22-slim came from mirror.gcr.io and public.ecr.aws (both index sha256:c3de60bf2f9d…; registry-1.docker.io answered 429 Too Many Requests).\n- The local base adds only the proxy CA as NODE_EXTRA_CA_CERTS, so npm inside the build reaches the registry through this container's TLS interception.\n- Each build: `docker build --no-cache --network host --build-arg OS_CLI_VERSION=V -f DOCKERFILE docker` (context docker/ as scaffold-e2e.yml uses it), on Dockerfile bytes verified by sha256.\n\nBEFORE, c9134933e Dockerfile, sha256 a331125c…:\n- V=17.7.0: exit 1, `npm error Cannot read properties of null (reading 'edgesOut')`.\n- V=18.0.0-next.2: exit 1, same.\n\nAFTER, d19cc5888 Dockerfile, sha256 435f33cc…:\n- V=17.7.0: exit 0, `added 525 packages`.\n- V=18.0.0-next.2: exit 0, `added 528 packages` (built on the pre-commit working copy, sha256 b1e52b29…; its RUN was byte-identical and only comment lines differ).\n\nCONTROL, c9134933e Dockerfile on a base with npm_config_before=2026-10-15T14:50:00Z, V=17.7.0: exit 0, `added 525 packages`.\n\nImage readings, after vs control: identical on\n- `os --version` = `@objectstack/cli/17.7.0 linux-x64 node-v22.23.3`;\n- image npm 10.9.9 at /usr/local/bin/npm;\n- global top level `@objectstack corepack mysql2 npm pg`;\n- pg@8.23.1 and mysql2@3.24.6 resolving from the image's @objectstack/driver-sql@17.7.0;\n- /tmp/os-installer-npm absent;\n- docker-publish.yml's own smoke: `os --version` exit 0, and `-w /usr/local/lib/node_modules node -e \"require('pg'); require('mysql2')\"` exit 0.\nGlobal tree: 722 packages each, 3 version differences, each published after the control cutoff: @mongodb-js/saslprep@1.6.1 19:13Z, argparse@3.0.3 21:58Z, js-yaml@5.5.0 23:28Z. Neither tree contains vitest.\nInstall layer: 663 MB control vs 666 MB after.\nREADME extend example (`--user root`, `npm install -g tedious` on the image's npm 10.9.9): exit 0 on the after image.\n\nGATE:\n- `pnpm check:docs-image-tag` exit 0: self-test `118 assertions`, then OK with `2 driver(s) installed by docker/Dockerfile compared against 2 promised in docker/README.md (2 matched by name)`.\n- New self-test cases on the exact image shape: anchor = driver line, not the installer line; npm@11.21.0 not a driver; green 2/2; drifted range refused (DRIVER-RANGE-MISMATCH); a global `npm install -g npm@…` ahead of the drivers refused (DRIVER-UNDOCUMENTED).\n- Before the parse change, the gate on the new Dockerfile: exit 1, DRIVER-ANCHOR-LOST.\n- `node scripts/check-nul-bytes.mjs` exit 0; control-byte grep on both files: none.\n- No ablation: the diff is config plus a gate script, and the gate's own self-test is the pin.", "gates": "Local, on scratch merge commit 29e3f931e = origin/main 74b436263 + branch head d19cc5888, merged locally and never pushed; it differs from main by exactly the 6 PR files.\n- Why: deriving on the branch tree printed STALE TREE — 17 commits behind, 9 files it derives from changed, including dispatch-gates.mjs itself.\n- `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`: 96 commands, round 1's 95 plus `pnpm check:docs-image-tag`. The branch tree derived the same 96.\n- Prebuild under the verify lock: `pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=2` → 74/74 tasks, VERDICT command-exit 0.\n- Each command run byte for byte with its exit captured before any pipe: 96/96 exit 0 on the first pass.\n- `--ran`: `96 derived, 96 run, 0 NOT-MEASURED, 0 UNRUN`, exit 0.\n- `node scripts/pm/check-governed-merges.mjs --branch claude/issue-23788-npm10-edgesout`, on both the branch-tree register and main's: exit 0, 0 of 6 paths governed, NOT governed, 335 changed lines.\n\nCI on PR #23799 head d19cc5888 (one read 04:27Z, not polled), 43 check runs:\n- success: Scaffold with repo dist, Validate Package Dependencies, Check Changeset, Lint & Repo Gates and every Lint lane, TypeScript Type Check and every Type Check lane, Test Core and Test Core 1-6/6, Build Core, Dogfood Regression Gate, Governed Surface Queue Guard, Flag docs affected by code changes, Check PR Size, Check Documentation Links, the claim/duplicate/Part-of checks, filter, Auto Label.\n- skipped by selector: Console Pin Gate, Temporal Conformance, Build Docs, Dogfood Verify CLI, Packed-tarball smoke, Registry canary, the Dogfood shard matrix.", "mcp_calls": "0 — no MCP GitHub tool was called this round", "api_writes": "1 this round — one relay stroke, POST /repos/objectstack-ai/objectstack/dispatches, carrying op `comment`, which executes POST /repos/objectstack-ai/objectstack/issues/23788/comments (this os-dev-report). Plus 1 git push (not REST) of d19cc5888. No PR body PATCH, no label writes, no assignee writes. Round 1's 2 strokes are unchanged.", "files_changed": [ "docker/Dockerfile (+25/-2) — this round", "scripts/check-docs-image-tag.mjs (+95/-7) — this round", "scripts/check-vendor-export-contract.mjs (+132/-3) — round 1", "packages/create-objectstack/src/templates/blank/package.json (+3/-0) — round 1", "packages/create-objectstack/src/template-consistency.test.ts (+47/-0) — round 1", ".changeset/23788-blank-scaffold-npm10-vitest-override.md (+21/-0) — round 1" ], "changed_lines": "this round 129 (+120 / -9) over 2 files; PR total 335 (+323 / -12) over 6 files vs merge base 0a168a33e", "pr_body_replacement": { "bytes": 18182, "sha256": "c08356156ec073c041f81026eea3d1bcec7a8356e6abcc78212e036a78d7814d", "note": "Full replacement for PR #23799's body, for the seat to write. It adds the \"Patch round\" section (before/after readings and why this mechanism), updates the intro, Tests, Gates (head d19cc5888), \"What #23481 needs afterwards\" and Acceptance notes, and keeps round 1's text otherwise. The live body was read back unchanged from round 1 before this was composed.", "body": "Fixes #23788\n\nClause-②: no\n\nThe Version Packages PR #23481 was red on two lockfile-less npm installs. Once those passed, a third install failed: the runtime image's global install. All three crash npm 10 with `npm error Cannot read properties of null (reading 'edgesOut')`. This PR fixes all three on `main`:\n\n- the vendor-export `--resolve` probe now installs with a pinned npm 11;\n- the blank scaffold now ships `\"overrides\": { \"vitest\": \"~4.0.0\" }`;\n- the official runtime image (`docker/Dockerfile`) now runs its `npm install -g` under a pinned npm 11 (see **Patch round** below).\n\nNothing here touches `changeset-release/main`, a workflow, `.npmrc`, `pnpm-workspace.yaml` or `pnpm-lock.yaml`. The monorepo's own pnpm install is unaffected.\n\n## The trigger\n\n**`vitest@4.1.12`, published 2026-10-15T14:51:24Z** under the `V4` dist-tag:\n\n- Every other `@vitest/*` peer of 4.1.12 is pinned to exactly `4.1.12`, but it declares `\"@vitest/browser-webdriverio\": \"^4.1.11\"`.\n- `@vitest/browser-webdriverio@4.1.12` was never published; the newest 4.x is 4.1.11, last modified 2026-09-08.\n- The only match, 4.1.11, peers `\"vitest\": \"4.1.11\"` exactly. The peer set therefore contradicts itself.\n- npm 10's arborist detaches a node while loading it and then dereferences `node.parent` (null) in `#loadPeerSet` (`build-ideal-tree.js:1289` on npm 10.9.4).\n- npm 11 handles it.\n\nBoth installs reach vitest only through OPTIONAL peers: `better-auth@1.7.3` peers `vitest: ^2 || ^3 || ^4`, and `@objectstack/metadata-core` peers `vitest: ^4.0.0`. On npm 10, each resolves to vitest 4.1.12.\n\nBisected with npm's `--before`, npm 10.9.9, each leg in an empty directory with a fresh `--cache`:\n\n| install | `--before=2026-10-15T08:36:00Z` | `--before=2026-10-15T14:50:00Z` | `--before=2026-10-15T14:52:00Z` |\n| --- | --- | --- | --- |\n| `npm install better-auth@1.7.3 --no-package-lock` (the probe) | exit 0 | exit 0 | exit 1, `edgesOut` |\n| blank template, `@objectstack/*` set to `latest` | not run | exit 0 | exit 1, `edgesOut` |\n\nThe issue's hypothesis holds in kind (an upstream publish in the window brings back npm 10's `#loadPeerSet` crash). The path is different from #22912's: there the root `vitest` reached `vitest@*` through vite 8's devtools peers. Here an optional peer meets one release's inconsistent peer set. The npm side has no fix: 10.9.9 is the newest npm 10. Upstream has no fix either: re-checked at the time of this PR, there is still no `@vitest/browser-webdriverio@4.1.12` and no `vitest@4.1.13`.\n\n## Before: reproduced\n\nNode 22, each leg in an empty directory outside any checkout with a fresh `--cache`:\n\n| leg | npm 10.9.4 | npm 10.9.9 | npm 11.21.0 | npm 11.21.1 |\n| --- | --- | --- | --- | --- |\n| (a) `npm install better-auth@1.7.3 --no-package-lock --no-audit --no-fund` in the probe's `package.json` | exit 1, `edgesOut` | exit 1, `edgesOut` | exit 0 | exit 0 |\n| (a) `pnpm check:vendor-export-contract-resolve` at the base commit | exit 3, PREREQUISITE NOT MET, `edgesOut` | exit 3, same | not run | not run |\n| (b) the CI step replayed on a fresh repo scaffold, `main`'s stamp `^18.0.0-next.1` | not run | first install exit 1 `edgesOut`; fallback exit 1 `edgesOut` | PASS | not run |\n| (b) the same with the release branch's stamp `^18.0.0-next.2` (ETARGET, then fallback to `latest` = 17.7.0) | exit 1, `edgesOut` (template with `latest`) | fallback exit 1, `edgesOut` | PASS | exit 0 (template with `latest`) |\n\nIsolated manifests on npm 10.9.9, for reach: `{\"dependencies\":{\"@objectstack/plugin-auth\":\"latest\"}}`, `{\"dependencies\":{\"@objectstack/metadata-core\":\"latest\"}}` and the `os init` plugin manifest (`@objectstack/spec`, `@objectstack/cli`, `typescript ^5.3.0`, `vitest ~4.0.0`) each exit 1 with `edgesOut`. The blank template with its `vitest` devDependency removed still crashes, so the template's own vitest range is not the path in, and no range change there can fix it.\n\n## The repair, and why each route\n\n**(ii) The probe: `scripts/check-vendor-export-contract.mjs`.** `--resolve` measures a vendor's export surface. It does not measure peer resolution. The probe now fetches `npm@11.21.0` (`PROBE_INSTALLER_NPM`, exact, at least two weeks old) into its scratch directory once per run, using the runner's npm. npm bundles its dependencies, so that install walks no peer graph. Every vendor install then runs under it.\n\n- Failing to fetch the installer is still PREREQUISITE NOT MET (exit 3).\n- A vendor that npm 11 cannot install is still PREREQUISITE NOT MET.\n- Only the npm-10 crash class stops masking the measurement.\n- The verdict line names the installer: `VERDICT: PASS — vendor export contract (registry resolution, installed with npm@11.21.0)`.\n\nMeasured alternatives, not taken:\n\n- **`--legacy-peer-deps`** also skips REQUIRED peers. `@better-auth/core@1.7.3` requires `better-call`, `jose`, `kysely` and others, and `@better-auth/core/context` then fails to import (`Cannot find package 'better-call'`, npm 10.9.9). That would be a false \"does not load\" red.\n- **`--omit=peer --omit=optional`** still exits 1: the crash happens while the ideal tree is built.\n\nThe self-test now pins two things: the installer is exact with major 11 or later, and the probe's install argv is whole, so a flag that changes which packages land cannot creep in.\n\n**(i) The blank template: `packages/create-objectstack/src/templates/blank/package.json`.** A user-facing manifest is affected. `npx create-objectstack` falls back to npm when pnpm is absent, and Node 22 bundles npm 10, so every such user's first `npm install` crashed. The template now ships `\"overrides\": { \"vitest\": \"~4.0.0\" }`, equal to its own `devDependencies.vitest`. It routes every `vitest` edge in the npm graph to the project's declared range.\n\n- **Same tree as npm 11 without the override.** The installed tree (path plus `name@version` for every package) is identical to npm 11.21.0's without the override: 566 packages on `main`'s stamp, 563 on the fallback, 0 diff lines across npm 10.9.4, 10.9.9, 11.21.0 and 11.21.1.\n- **pnpm ignores the field.** pnpm does not read npm's `overrides` (measured on pnpm 10.28.0), so pnpm installs are unchanged.\n- **⛔ Not `\"$vitest\"`.** It also installs, but npm then stops hoisting `@objectstack/metadata-core` and nests 17 copies of it (measured on npm 10.9.4, 10.9.9 and 11.21.0; on 10.9.9, a scoped `{\"@objectstack/metadata-core\":{\"vitest\":\"$vitest\"}}` and a version-keyed override do the same).\n- **The literal's cost is loud.** npm refuses an override that differs from the direct dependency: `EOVERRIDE: Override for vitest@^4.1.0 conflicts with direct dependency`, measured on npm 10.9.9 and 11.21.0. The new template test pins `overrides.vitest === devDependencies.vitest`, so the two move together. The changeset tells users the same.\n\n**(iii) Workflows: not needed.** All three repairs are in non-governed files, so this PR touches no governed surface.\n\n## After\n\n| leg | npm 10.9.4 | npm 10.9.9 | npm 11.21.0 | npm 11.21.1 |\n| --- | --- | --- | --- | --- |\n| `pnpm check:vendor-export-contract-resolve` (HEAD, fresh npm cache) | exit 0, PASS, 2 edges | exit 0, PASS, 2 edges | not run | not run |\n| (b) fresh repo scaffold, `main`'s stamp, the CI step replayed | PASS, first install | PASS, first install | PASS | PASS |\n| (b) the same with the release stamp, `^18.0.0-next.2`, via the fallback | PASS (ETARGET, then fallback exit 0) | PASS (same) | PASS (same) | PASS (same) |\n\nThe after-PASS lines: `✓ @better-auth/core/context @ @better-auth/core@1.7.3 (via \"1.7.3\", 2 symbol(s))` and `✓ better-auth/adapters @ better-auth@1.7.3 (via \"1.7.3\", 1 symbol(s))`.\n\n## Tests\n\n- `pnpm --filter create-objectstack test`: 18 files, 275 tests, passing.\n- `pnpm --filter create-objectstack typecheck`: exit 0, after building the dependency closure. `tsc --listFiles` includes `template-consistency.test.ts`.\n- `node scripts/check-vendor-export-contract.mjs --self-test`: OK. `node scripts/sync-scaffold-emission-policy.mjs --check` and `node scripts/sync-template-versions.mjs --check`: exit 0.\n- **Ablation of the new template test**, committed state first, mutation through `scripts/ablation-replace.mjs` with an anchor that must hit, restored from `HEAD` and proven by blob hash:\n - with the `overrides` block deleted (on-disk count 1 → 0, JSON still parses), `template-consistency.test.ts` reads `1 failed | 38 passed`, and the failure is the new case;\n - restored, it reads `39 passed`.\n - The test reads `src/templates` from disk, so no `dist/` is involved.\n- `pnpm check:docs-image-tag` (patch round): self-test `118 assertions`, then `OK`, `2 driver(s) installed by docker/Dockerfile compared against 2 promised in docker/README.md (2 matched by name)`.\n\n## Patch round: the runtime image (`docker/Dockerfile`)\n\nWith the probe and the scaffold fixed, `Scaffold with repo dist` (job 116797775725, head `c9134933e`) got as far as building the official runtime image from this checkout. It then failed at line 69 of that file, `RUN npm install -g @objectstack/cli@${OS_CLI_VERSION} \"pg@^8.0.0\" \"mysql2@^3.0.0\" && npm cache clean --force`, with the same `edgesOut` crash on `node:22-slim`'s npm.\n\n- A global install reads no project `overrides`, so round 1 could not reach this line.\n- `docker-publish.yml` ships this image, so the same line would also have broken the release's image publish.\n\n**The change.** The same RUN now does four things:\n\n1. Fetches `npm@11.21.0` into `/tmp/os-installer-npm` with the image's own npm. npm bundles its dependencies, so that fetch walks no peer graph.\n2. Puts it first on `PATH` for that RUN only, and checks `test \"$(npm --version)\" = \"11.21.0\"`.\n3. Runs the unchanged `npm install -g @objectstack/cli@${OS_CLI_VERSION} \"pg@^8.0.0\" \"mysql2@^3.0.0\"`.\n4. Runs `npm cache clean --force`, then deletes the installer in the same layer.\n\nThe version is the one `PROBE_INSTALLER_NPM` holds for the same crash. The installed packages and their ranges are unchanged, and the image still ships `node:22-slim`'s npm.\n\n**Why this mechanism.** Measured inside `node:22-slim` (node v22.23.3, npm 10.9.9, global prefix `/usr/local`):\n\n- **Same install location.** Run from `/tmp`, the fetched npm 11 resolves first on `PATH` and uses the same global prefix: `npm config get prefix` gives `/usr/local` and `npm root -g` gives `/usr/local/lib/node_modules`. So the install lands where the image's npm would put it.\n- **No image growth.** The installer is 20 MB. Deleting it in the same RUN keeps it out of every layer: the install layer is 666 MB, against 663 MB for the pre-trigger control below.\n- **Not taken:**\n - `npm install -g npm@…` replaces the image's npm for every user of the image.\n - `npx npm@…` leaves 20 MB in `~/.npm/_npx` after `npm cache clean --force` (measured).\n - `--legacy-peer-deps` also skips required peers (measured on the probe).\n\n**The gate.** `pnpm check:docs-image-tag` anchored the driver line on the first trimmed line starting `RUN npm install -g`. The new RUN opens with the installer fetch, so on the new Dockerfile the old parse went red with `DRIVER-ANCHOR-LOST` (measured). The new parse:\n\n- anchors on `npm install -g` after a `RUN` or `&&` leader;\n- drops the leader, then cuts at the next `&&`;\n- does not anchor on the installer fetch, which has no `-g`.\n\nOn this tree it reads line 90 (`&& npm install -g \\`) and finds `pg@^8.0.0` and `mysql2@^3.0.0`, matching 2 against 2 in `docker/README.md`. `docker/README.md` is unchanged. The new self-test cases, on the image's exact shape:\n\n- the anchor is the driver line, not the installer line, and `npm@11.21.0` is not read as a driver;\n- that shape, agreeing with the table, is green with 2 compared against 2;\n- a drifted range in that shape is refused (`DRIVER-RANGE-MISMATCH`);\n- an npm upgrade spelled as a global `npm install -g npm@…` ahead of the drivers is read as the install line and refused (`DRIVER-UNDOCUMENTED`), never skipped into a green.\n\n`pnpm check:docs-image-tag` exits 0, self-test `118 assertions`.\n\n### Readings\n\n**Setup.** A private `dockerd` 29.8.2 in this container.\n\n- `node:22-slim` came from the GCR and ECR mirrors of Docker Hub. Both serve index digest `sha256:c3de60bf…`; Docker Hub itself answered 429.\n- The only addition on top is the proxy CA as `NODE_EXTRA_CA_CERTS`, so npm inside the build can reach the registry.\n- Each build used the Dockerfile byte for byte, the context `docker/` as CI uses it, and `--no-cache`.\n\n| build | `OS_CLI_VERSION=17.7.0` | `OS_CLI_VERSION=18.0.0-next.2` |\n| --- | --- | --- |\n| before: `c9134933e`'s Dockerfile | exit 1, `npm error Cannot read properties of null (reading 'edgesOut')` | exit 1, same |\n| after: `d19cc5888`'s Dockerfile | exit 0, `added 525 packages` | exit 0, `added 528 packages` (on a working copy whose RUN was byte-identical; only a comment changed before the commit) |\n| control: the before Dockerfile, npm limited to `--before=2026-10-15T14:50:00Z` | exit 0, `added 525 packages` | not run |\n\nAfter image (`d19cc5888`, 17.7.0) against the pre-trigger control:\n\n| reading | control (pre-trigger, npm 10.9.9) | after |\n| --- | --- | --- |\n| `os --version` | `@objectstack/cli/17.7.0 linux-x64 node-v22.23.3` | same |\n| the image's `npm --version` | 10.9.9 (`/usr/local/bin/npm`) | same |\n| global top level | `@objectstack corepack mysql2 npm pg` | same |\n| `pg` / `mysql2`, resolved from the image's `driver-sql` | `pg@8.23.1`, `mysql2@3.24.6` | same |\n| `docker-publish.yml`'s smoke: `os --version`, then `node -e \"require('pg'); require('mysql2')\"` from the global tree | exit 0, exit 0 | exit 0, exit 0 |\n| `/tmp/os-installer-npm` | absent | absent |\n| global tree (path plus `name@version`) | 722 packages | 722 packages, with 3 version differences (below) |\n\nThe 3 version differences were each published after the control's cutoff: `@mongodb-js/saslprep@1.6.1` (10-15 19:13Z), `argparse@3.0.3` (21:58Z) and `js-yaml@5.5.0` (23:28Z). Neither image contains vitest.\n\n- **Extend example.** The README's extend-the-image example (`USER root`, then `RUN npm install -g tedious`) runs on the image's own npm 10.9.9 and installs on the after image (exit 0).\n- **NOT MEASURED: linux/arm64,** the second platform `docker-publish.yml` builds. The mechanism is architecture-independent JavaScript.\n\n## Gates (local, on head `d19cc5888`)\n\n- **Measured tree.** The branch is behind `origin/main` (`74b436263`). On the branch tree, `dispatch-gates` flagged it as STALE: 9 of the files it derives from changed on `main` since the branch point. So the union ran on a scratch commit, `29e3f931e`: `origin/main` with this branch merged locally and never pushed. It differs from `main` by exactly this PR's 6 files, the same shape as the merge ref CI tests.\n- **Derivation.** `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` named 96 commands: round 1's 95, plus `pnpm check:docs-image-tag`.\n- **Result.** Every package was built first, under the verify lock (74 of 74 tasks). Each command then ran byte for byte with its exit code captured before any pipe, and all 96 exited 0 on the first pass.\n- **Reconciliation.** `--ran`: `96 derived, 96 run, 0 NOT-MEASURED, 0 UNRUN`.\n- **Governed surfaces.** `node scripts/pm/check-governed-merges.mjs --branch claude/issue-23788-npm10-edgesout` (the register on both the branch tree and `main`'s): 0 of 6 paths hit the register. NOT governed, 335 changed lines.\n- **CI on `d19cc5888`** (one read at 04:27Z): all 43 check runs completed. Every one is `success` or skipped by its selector, including `Scaffold with repo dist`, `Validate Package Dependencies`, `Check Changeset`, `Lint & Repo Gates` and `Test Core`.\n- **Left to CI.** The full farm, the 11 wide-population families and the workflow-valued families are CI's.\n\n## What #23481 needs afterwards\n\nNothing is pushed to `changeset-release/main`. `release.yml`'s `version-pr` job regenerates that PR on its 6-hourly `schedule` (cron `0 */6 * * *`), or on the relay's `refresh_version_pr: true` dispatch. It does not run on a push to `main`. Once this lands, the next regeneration carries all three fixes. A re-run of the PR's bot-triggered checks is a maintainer act. A plain re-run of the existing red run reuses that run's old commit, so it cannot see this fix.\n\n`main`'s own `schedule` run of `validate-deps.yml`, run 38843597390 at 03:03Z on `46ca793edb`, is red at the same step: \"Verify the declared ranges cannot resolve past our import surface\", exit 3, which is PREREQUISITE NOT MET. So this is not specific to the release branch.\n\n## Acceptance notes\n\nThese are related findings, not fixed here:\n\n- **`os init` / `os create` emit the same unfixed manifest class.** The `os init` plugin manifest crashes npm 10.9.9 with `edgesOut` (measured). Those emitters build `package.json` in `packages/cli/src/commands/init.ts` / `create.ts`, and `create.ts` is outside this claim's surface.\n- **Existing npm-10 projects** that depend on any `@objectstack/*` package reaching `@objectstack/metadata-core` or `@objectstack/plugin-auth` crash the same way until upstream publishes a consistent vitest 4.x (measured: `@objectstack/plugin-auth@latest` and `@objectstack/metadata-core@latest` each alone). npm 11 installs them.\n- **The template override is a hand-kept copy.** `overrides.vitest` copies `SCAFFOLD_VITEST_RANGE` by hand, guarded by the new test. A `POLICY_STAMPS` row in `scripts/sync-scaffold-emission-policy.mjs` would generate it. That script is outside this claim's surface.\n- **The self-hosting guide's self-built runtime crashes the same way.** `content/docs/deployment/self-hosting.mdx` offers an \"equivalent\" Dockerfile, `FROM node:22-slim` plus `RUN npm install -g @objectstack/cli@17.7.0`. On that image's npm 10.9.9 the RUN exits 1 with `edgesOut` (measured). Its host recipe, `npm install -g @objectstack/cli`, is the same install. The file is outside this claim's surface.\n- **Pre-existing scratch-cleanup gap.** The probe's `PREREQUISITE NOT MET` exits call `process.exit` inside the `try`, so the scratch directory under the OS temp dir is not removed on those paths.\n\n---\n_Generated by [Claude Code](https://claude.ai/code/session_016PVjjuVPte5XEJvaQx1E4t)_\n" }, "open_questions": [], "out_of_scope_findings": [ "class: a · reach: public door — `content/docs/deployment/self-hosting.mdx`'s \"Dockerfile (self-built runtime, equivalent)\" (`FROM node:22-slim` + `RUN npm install -g @objectstack/cli@17.7.0`), its RUN executed on node:22-slim's npm 10.9.9 → exit 1 `Cannot read properties of null (reading 'edgesOut')` · evidence: measured 2026-10-16 in node:22-slim (index sha256:c3de60bf…). The host recipe `npm install -g @objectstack/cli` in the same doc is the same install. Fix shape: the doc mirrors docker/Dockerfile's pinned-npm RUN, or tells npm-10 users to install with npm 11. The doc is outside this claim. Family: npm-10 arborist edgesOut (#23788; the seat's filings for `os init`/`os create` and for existing projects) — merge into that family's closure card, not a single-point card · dedupe words: self-hosting self-built runtime npm 10 edgesOut; npm install -g @objectstack/cli crash; node:22-slim npm 10.9.9", "carrier: seat (verdict 6207595239, to be filed by the seat) · round 1's two class-a findings, unchanged: `os init`/`os create` manifests (domain:cli), and existing projects' `npm install @objectstack/plugin-auth` / `@objectstack/metadata-core` on npm 10", "carrier: 承接者:无 · noted, not filed — the vendor-export probe's PREREQUISITE NOT MET exits leave its mkdtemp scratch dir (round 1, in PR Acceptance notes)" ], "deviations": [ "Gate union measured on a local scratch merge commit (29e3f931e = origin/main + branch), never pushed, not on the branch tree. The branch-tree derivation flagged STALE (9 derived-from files changed on main). origin/main was NOT merged into the branch: the open-PR rule allows that only for a conflict, a main-caused CI red or a dequeue, and none applies (CI is green on d19cc5888).", "Docker environment: Docker Hub answered 429, so node:22-slim came from mirror.gcr.io / public.ecr.aws (same index digest from both). A private dockerd ran in the shared container on its own socket and data-root, and the local base adds the proxy CA as NODE_EXTRA_CA_CERTS. The Dockerfiles under test were byte-identical to the committed files (sha256 above). Teardown: dockerd PID 20126 exited, the leftover netns bind mount was unmounted, and the 317 MB data-root was removed.", "The 18.0.0-next.2 after-build ran on the pre-commit working copy, whose RUN was byte-identical; the final-bytes rebuild was done for 17.7.0 only.", "Attribution — the harness reminder asks for a model-named `Co-Authored-By` trailer and a different PR footer. I followed AGENTS.md: the model-free trailer pair `Claude-Session` + `Co-authored-by: Claude`, which the pre-push hook enforces, and the session-URL footer in the replacement body.", "PR #23799 now carries labels documentation, dependencies, size/m, tests and tooling, set by another actor (the labelers). I wrote none and changed none.", "arm64: NOT MEASURED (docker-publish.yml builds linux/amd64 and linux/arm64); the mechanism is architecture-independent JavaScript." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed: PR #23799 →
d795719926(Fixes #23788) ·domain:devxseat 2 ·session_016PVjjuVPte5XEJvaQx1E4t· 2026-10-16T05:03Zadded_to_merge_queue2026-10-16T04:44:34Z)origin/maind795719926is the head (one parent,f846cc202)d19cc58886:docker/Dockerfile26ff3696bf,scripts/check-docs-image-tag.mjs8dc33074ef,scripts/check-vendor-export-contract.mjsc55cf5fc8b, the blank templatepackage.json1bbbff43ce,template-consistency.test.ts9a02a6fb7d, the changesete4299427b3completed.pm:dispatchedis removed in this act.edgesOut, triggered byvitest@4.1.12's self-contradicting peer set) now succeed onmain:--resolveprobe, now under a pinned npm 11;overrides.vitest;check-entry-guard.mjscannot see an entry guard written inside a template literal — the percent-encoding spelling its own header documents passes the gate #11838) published npm18.0.0-next.2, and its Docker job failed at the line this PR fixes. That leg is release: the Docker image job fails at "Build and push" since Release #11838 (npm 18.0.0-next.2 published fine):npm install -g @objectstack/clicrashes in npm's peer resolution ("Cannot read properties of null (reading 'edgesOut')") #23801 (claimed by this seat, carried by this PR). Release finding: 5 engine doubles already call the producer predicate and are still outside the ratchet — oneIDataEngineannotation each would admit them #11850 ond795719926is the first run with the fix; release: the Docker image job fails at "Build and push" since Release #11838 (npm 18.0.0-next.2 published fine):npm install -g @objectstack/clicrashes in npm's peer resolution ("Cannot read properties of null (reading 'edgesOut')") #23801 closes on its Docker job's reading.os init/os createemit manifests npm 10 cannot install since vitest@4.1.12 (edgesOut); the CLI half of #23788's template override #23805 (os init/os create), finding: existing projects cannotnpm install @objectstack/plugin-author@objectstack/metadata-coreon npm 10 since vitest@4.1.12 (edgesOut); metadata-core's own optionalvitestpeer is one path in #23806 (existing projects and the self-hosting guide), ci(spec-shape-gate): once objectui drops its copy, the gate's header text and a retirement entry whose card closed still describe the old state #23782 (domain:spec).Generated by Claude Code