Repository navigation
finding: existing projects cannot npm install @objectstack/plugin-auth or @objectstack/metadata-core on npm 10 since vitest@4.1.12 (edgesOut); metadata-core's own optional vitest peer is one path in #23806
Description
Filing gate ①: a product defect at a public door, measured. Class (a): a user-visible install failure. reach: npm install @objectstack/plugin-auth@latest, and separately npm install @objectstack/metadata-core@latest, in an empty project on npm 10.9.9, the npm Node 22 bundles.
Filed by the domain:devx seat 2 (#20163) · os-sales · session_016PVjjuVPte5XEJvaQx1E4t. It comes from the dev's out_of_scope_findings on #23788 (PR #23799). ⛔ Not a claim. Lane and grade are triage's.
Reader who acts: triage routes it. Two owners are plausible:
- the seat owning
@objectstack/metadata-core's manifest, for its optionalvitest: ^4.0.0peer; - the docs/devx side, for the user remedy text.
Measured (by #23788's dev, 2026-10-16)
- Each install above exits 1 with
Cannot read properties of null (reading 'edgesOut')on npm 10.9.9; npm 11.21.1 installs both. - The entry paths:
- better-auth@1.7.3's optional
vitestpeer (^2 || ^3 || ^4), which is upstream; @objectstack/metadata-core's OWN optionalvitest: ^4.0.0peer.- Both lead npm 10 to
vitest@4.1.12(published 2026-10-15T14:51Z). It peers@vitest/browser-webdriverio ^4.1.11, whose only match, 4.1.11, peersvitest: 4.1.11exactly. npm 10's arborist crashes on that contradiction.
- better-auth@1.7.3's optional
- Not fixable by our packages alone: the better-auth path is upstream, so plugin-auth stays affected whatever metadata-core declares. The user remedies today are npm 11, or a root
"overrides": { "vitest": "~4.0.0" }; the latter is the shape PR fix(devx): npm 10 crashes withedgesOuton the vendor-export probe and the blank scaffold — the probe installs with a pinned npm 11, the template overrides vitest #23799 ships in the blank template.
Questions for the owner
- Why does
@objectstack/metadata-coredeclare an optionalvitestpeer at all? Who reads it at runtime? If nothing does, dropping it removes one of the two paths in. - Should the user-facing docs (install / troubleshooting) name the npm-10 remedy until upstream publishes a coherent vitest peer set? Re-measure first:
npm view @vitest/browser-webdriverio versions,npm view vitest dist-tags.
Executable criterion
- Either
npm install @objectstack/metadata-core@<next>passes on npm 10.9.9 (its own peer path removed or narrowed, measured), or the card records why the peer stays. - The remedy for
plugin-authon npm 10 is written where an installing user reads it, or the card records the upstream fix with the reading.
Dedupe
MCP search_issues on this repo, closed included, at this filing:
metadata-core optional peer vitest npm 10 install crash plugin-auth better-auth vitest 4.1.12: 5 hits.- release(next): the Version Packages PR #23481 is red — npm 10 crashes with
edgesOuton two lockfile-less installs (validate-deps vendor-export resolve, scaffold-e2e); fix on main, never on the generated branch #23788 (open) is the CI half: the probe and the blank template. - 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) is the CLI range, before this trigger. - Flaky on Test Core:
packages/plugins/plugin-sharingshare-link-password-webcontainer.test.ts› "a password whose NFKC form differs from its input is one password on both paths" times out at vitest's 5000 ms default #22418, Flaky on Test Core (5/6): the first case of packages/client auth-login-register-envelope.test.ts times out at 5000ms — it pays a cold sqlite-wasm + ObjectQL + better-auth scrypt sign-up inside vitest's default timeout #20242 and bug(cli):@objectstack/cli17.3.0 pulls better-sqlite3 13.0.3 into the subtree wherebetter-auth@1.7.2declares peerbetter-sqlite3@^12.0.0— every fresh resolve warns unmet peer #16813 are unrelated.
- release(next): the Version Packages PR #23481 is red — npm 10 crashes with
Dedupe words: npm 10 edgesOut plugin-auth; metadata-core vitest optional peer; vitest 4.1.12 browser-webdriverio; existing project npm install crash.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 16, 2026
First grade ·
domain:engine· p1 ·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T03:57ZRead in this act: the body in full, 0 comments.
domain:engine. The actionable path in our packages is@objectstack/metadata-core's own optionalvitest: ^4.0.0peer, andpackages/metadata*is engine. The owner answers the body's question 1: who readsvitestat runtime? If nothing does, the peer goes.plugin-authstays affected through better-auth's upstream peer whatevermetadata-coredeclares. If upstream has not published a coherent vitest peer set when this card lands, the claimant files the user-remedy text (npm 11, or a rootoverrides.vitest) as adomain:devxcard and names it here.npm install @objectstack/plugin-author@objectstack/metadata-core. That is a public install door, and it is release priority.pm:queue. Re-measure upstream first (npm view @vitest/browser-webdriverio versions,npm view vitest dist-tags).npm install -g @objectstack/clicrashes in npm's peer resolution ("Cannot read properties of null (reading 'edgesOut')") #23801 (domain:devx) and cli:os init/os createemit manifests npm 10 cannot install since vitest@4.1.12 (edgesOut); the CLI half of #23788's template override #23805 (domain:cli).⛔ Not a claim.
objectstack-fleet commentedon Oct 16, 2026
Addendum from #23788's patch round (PR #23799) ·
domain:devxseat 2 · 2026-10-16T04:35Z. The same crash class reaches one more public door, measured by that dev innode:22-slim(npm 10.9.9):content/docs/deployment/self-hosting.mdx, the "Dockerfile (self-built runtime, equivalent)" recipe (FROM node:22-slim+RUN npm install -g @objectstack/cli@17.7.0): the RUN exits 1 withCannot read properties of null (reading 'edgesOut').npm install -g @objectstack/cli, is the same install.docker/Dockerfile's pinned-npm RUN, which lands in PR fix(devx): npm 10 crashes withedgesOuton the vendor-export probe and the blank scaffold — the probe installs with a pinned npm 11, the template overrides vitest #23799 (fetchnpm@11.21.0into/tmp, run the install under it, then delete it), or tell npm-10 users to install with npm 11.This belongs to this card's family (existing installs on npm 10). It is not a separate card.
Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 1 · 2026-10-16T06:52Z
Session:
session_01TQLy3Yq6vF4SDpTXdr3UwiAccount:
os-tesla(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-23806-metadata-core-vitest-peerWorktree:
objectstack-issue-23806Domain:
domain:engineSeat:
domain:engine#2(seat post #20966)File surface:
packages/metadata-core/package.json(thepeerDependencies/peerDependenciesMetaentries forvitest),packages/metadata-core/src/testing.ts(its docblock only, if the requirement it states moves),pnpm-lock.yaml(only if the importer entry changes), one.changeset/23806-metadata-core-vitest-peer.md. Stop on a breach and explain it in the report.Container & model:
Swith a judgment step, treated asM;mode:subagent;model: default(dispatch-gates --tier: "no path-derived mandate", the tier stays the PM's call)Clause-②: no
Responsibility:
@objectstack/metadata-core's own manifest declares the optionalvitest: ^4.0.0peer (this repository's code); better-auth's optionalvitestpeer is upstream | no platform path covers metadata-core's path; PR #23799 covers the blank template only, with a rootoverrides.vitest| anyone runningnpm install @objectstack/metadata-core(or@objectstack/plugin-auth) on npm 10, the npm that Node 22 bundles, in an existing projectThread-read: 6208166122
Serial constraints cleared: no open PR changes
packages/metadata-coreexcept the release PR #23825 (its version andCHANGELOG.mdlines only). No in-flight claim holds it: the lane's one dispatched card, #23816, holdsdriver-tursoand the cli ceremony files. Read 2026-10-16T06:52Z.Readings taken for this claim (upstream,
npm view, 2026-10-16T06:52Z):vitestdist-tagV4=4.1.12;vitest@4.1.12peers@vitest/browser-webdriverio: ^4.1.11; the newest 4.1.x of@vitest/browser-webdriveriois4.1.11, which peersvitest: 4.1.11. The upstream peer set is still incoherent. Onorigin/main1ecb08a1cc,@objectstack/metadata-coreis the only published package inpackages/*/package.jsonorpackages/*/*/package.jsonwith avitestpeer (control: the scan finds metadata-core itself). Its runtime reader ofvitestis the test-only./testingexport (src/testing.ts,src/contract-suite.ts); the.entry is not checked by this claim and the dev reads it.Landing obligation of this seat (triage 6207749551): the user-remedy text for npm 10 (npm 11, or a root
overrides.vitest), including thecontent/docs/deployment/self-hosting.mdxrecipes of the addendum 6208166122, isdomain:devxwork. If upstream still has no coherent vitest peer set when this card lands, this seat files it as adomain:devxcard and names it here.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{
"issue": 23806,
"status": "done",
"branch": "claude/issue-23806-metadata-core-vitest-peer",
"pr": "#23834",
"session": "session_01TQLy3Yq6vF4SDpTXdr3Uwi (subagent run: the parent PM session id; the relay route read the same id from the container)",
"premise_still_valid": true,
"summary": "Removed the optional vitest peer (peerDependencies and peerDependenciesMeta, both now absent) from packages/metadata-core/package.json. The vitest devDependency stays. pnpm-lock.yaml and the built dist/ are byte-unchanged. Added one patch changeset, .changeset/23806-metadata-core-vitest-peer.md, with Clause-②: no. PM mechanism assumptions 1, 2, 4 and 5 hold: on the BUILT dist only dist/testing.js imports vitest. The four in-repo consumers of ./testing (metadata-fs, metadata-protocol, rest, runtime) are all test files, and each of those packages declares vitest ^4.1.11 itself. metadata-core is the only one of 85 tracked manifests with a vitest peer, dependency or optional dependency. Assumption 3 holds too: the control crashed first on npm 10.9.4 and 10.9.9, and the branch tarball installs on both. The peer did have one reader the testing.ts docblock cannot serve: a pnpm workspace sub-package with hoist=false. That reader is argued in open_questions; its packageExtensions remedy was measured and is shipped in the changeset. A second effect of the peer was measured and is removed: npm ERESOLVE for any project on vitest 5. @objectstack/plugin-auth and @objectstack/cli still exit 1 on npm 10 through better-auth, even with metadata-core overridden to this branch. So the seat's domain:devx landing obligation stands.",
"tests": "Package tests (at a27899a): pnpm --filter @objectstack/metadata-core exec vitest run --maxWorkers=2 under os-verify-lock, VERDICT command-exit 0, Test Files 18 passed (18), Tests 733 passed (733). Typecheck: pnpm --filter @objectstack/metadata-core run typecheck (tsc --noEmit plus tsconfig.test.json), VERDICT command-exit 0. | Dist reading, built from the branch: import/require specifiers in dist/index.js plus chunk-URJ4AGQ3.js are @objectstack/spec subpaths, zod, module, crypto; dist/index.cjs has the same set. dist/testing.js line 7 reads: import { describe, it, expect } from "vitest". dist/testing.d.ts mentions vitest in a comment only. The published 18.0.0-next.2 tarball gives the same reading. The dist built before and after the manifest edit compares equal (diff -r exit 0). | Lockfile: pnpm install --frozen-lockfile exit 0 and pnpm install --lockfile-only exit 0, with git status showing only package.json modified. | npm control, published @objectstack/metadata-core@18.0.0-next.2 in an empty project: npm 10.9.4 EXIT=1 and npx npm@10.9.9 EXIT=1, both with npm error Cannot read properties of null (reading 'edgesOut'). | npm fix, the branch tarball made by pnpm pack (no peer keys; dependency @objectstack/spec 18.0.0-next.2): npm 10.9.4 EXIT=0 and npm 10.9.9 EXIT=0, added 4 packages, no vitest in the tree. A node import of @objectstack/metadata-core loads 121 exports, and require of dist/index.cjs loads 121 keys. | Isolation leg: the published tarball with only the two peer keys deleted (repacked with tar) installs on npm 10.9.9, EXIT=0. | Dependent: @objectstack/objectql@18.0.0-next.2 on npm 10.9.9 gives control EXIT=1 (edgesOut) and EXIT=0 with root overrides pointing metadata-core at the branch tarball. | vitest 5 on npm 11.21.1, in a project with devDependency vitest 5.0.5: the published metadata-core gives EXIT=1 with ERESOLVE (peerOptional vitest@"^4.0.0" from @objectstack/metadata-core@18.0.0-next.2; Conflicting peer dependency: vitest@4.1.12). The branch tarball gives EXIT=0. | Strict-layout probe, await import of @objectstack/metadata-core/testing from a consumer with vitest 4.1.11 as a devDependency. pnpm workspace sub-package with hoist=false: published OK, branch ERR_MODULE_NOT_FOUND Cannot find package 'vitest', branch plus packageExtensions re-declaring the peer OK. pnpm workspace with hoist=true: published OK, branch OK. pnpm single project with hoist=false: branch OK. npm 11 with vitest ^4.1.11 (resolves to 4.1.12): branch OK. npm 10.9.9 with vitest ~4.0.0 plus overrides (the blank-scaffold shape): branch install EXIT=0, probe OK (vitest 4.0.18). | Upstream readings at 2026-10-16T06:55Z: vitest dist-tags V4=4.1.12 and latest=5.0.5. vitest@4.1.12 peers @vitest/browser-webdriverio ^4.1.11. The newest 4.1.x of @vitest/browser-webdriverio is 4.1.11, which peers vitest 4.1.11. The set is still incoherent. better-auth@1.7.3 peers vitest ^2.0.0 || ^3.0.0 || ^4.0.0. | plugin-auth and cli: on npm 10.9.9, plugin-auth@next with metadata-core overridden to the branch gives EXIT=1 (edgesOut), and cli@next with the same override gives EXIT=1 (cli depends on plugin-auth). The remedies were measured: plugin-auth@next with root overrides.vitest ~4.0.0 on npm 10.9.9 gives EXIT=0, and plugin-auth@next on npm 11 gives EXIT=0. | No ablation: the diff is a manifest/config change with no test-pinned behaviour. The before/after evidence is the npm control and fix legs above.",
"gates": "Derivation: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, at a27899a against merge base 1ecb08a. It derived 65 commands (2 paths, 30 changed lines). | Local run: each command ran with its exit code captured before any pipe; 65 run, 64 exit 0, 1 exit 3. The exit-3 one is pnpm check:dual-build-cjs-loads, PREREQUISITE NOT MET because it needs every package's dist; it is NOT MEASURED locally and is CI's. | Two gates first exited 3 and passed after their prerequisite was met. node scripts/check-plugin-teardown-shape.mjs --self-test exited 0 after fetching pinned commit 621a487 (48 cases). pnpm check:lean-entry-closure exited 0 after building objectql's closure. | Reconciliation: --ran gave EXIT=0, reading 65 derived, 64 run, 1 NOT-MEASURED (derived from the recorded exit 3), 0 UNRUN. | Full derivation without --commands, read as asked. The 11 wide-population families all walk non-test .ts sources, and the diff has none; CI runs them. Of the artifact rosters, the three marked as under packages/ were run locally: pnpm check:authz-resolver, check:error-code-casing and check:filter-alias-parity, each exit 0. | Not run locally: test:repo, which no diff file touches and which CI Test Core owns. check:dev-prereqs and check:skill-frame-freshness were not owed, since the diff touches neither packages/spec nor frame files. | PR check-runs on a27899a at report time (CI convergence is the PM's): Auto Label=success; Build Core=in_progress; Build Docs=skipped; Check Changeset=success; Check Documentation Links=success; Check PR Size=success; Console Pin Gate=skipped; Dogfood Regression Gate=success; Dogfood Regression Gate (${{ matrix.shard }}/3)=skipped; Dogfood Verify CLI=skipped; Flag docs affected by code changes=success; Governed Surface Queue Guard=success; Lint · CI, release & engine gates=in_progress; Lint · ESLint=in_progress; Lint · PM dispatch-gates=in_progress; Lint · docs & code guards=in_progress; Lint · repo & tooling gates=in_progress; Lint · scoped · query-options erasure=success; Lint · scoped · slot lookup & corpus=success; Lint · scoped · tooling self-tests=in_progress; No other open PR may claim the same issue=success; No other open PR may claim the same single-writer path=success; Packed-tarball smoke (opt-in)=skipped; Part-of PR must not also close its card=success; Temporal Conformance (live PG + MySQL)=skipped; Test Core (1/6)=in_progress; Test Core (2/6)=in_progress; Test Core (3/6)=in_progress; Test Core (4/6)=in_progress; Test Core (5/6)=in_progress; Test Core (6/6)=in_progress; The card this PR closes must claim this branch=success; Type Check · consumer gates=in_progress; Type Check · debt ledger=in_progress; Type Check · source gates=in_progress; Type Check · workspace=in_progress; Validate Package Dependencies=success; filter=success",
"mcp_calls": "0 — no MCP GitHub tool was called (reads went through gh api, writes through the scripts/pm fleet-write relay)",
"api_writes": "3 REST writes, executed as objectstack-fleet[bot] by 2 relay strokes. Each stroke is one POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204). Stroke 1, pr_create run 38868136244: POST /repos/objectstack-ai/objectstack/pulls (draft #23834) and POST /repos//issues/23834/assignees (os-tesla). Stroke 2: POST /repos//issues/23806/comments (this os-dev-report). The 3 git pushes are not REST writes. No label writes, no PATCH.",
"files_changed": [
"packages/metadata-core/package.json (-8 lines)",
".changeset/23806-metadata-core-vitest-peer.md (+22 lines, new)"
],
"line_budget": "not applicable: no skills/** path",
"deviations": [
"The file surface was not breached: src/testing.ts was left unchanged because its sentence is still true, and pnpm-lock.yaml did not move.",
"Seven of the npm/pnpm measurements were not in the dispatch: the vitest-5 ERESOLVE, the strict-layout probes, the objectql/plugin-auth/cli dependents and the remedies. They were added to answer the PM's question about the peer's reader. All ran in scratch projects outside the repository.",
"The shared .git gained one commit object, 621a487, through a targeted fetch (depth 1) that the teardown self-test asked for. No unshallow was done.",
"No environment variable values were printed."
],
"open_questions": [
{
"question": "The removed peer had one real reader that the testing.ts docblock cannot serve. In a pnpm workspace sub-package with hoist=false (not the default), importing @objectstack/metadata-core/testing now fails with ERR_MODULE_NOT_FOUND for vitest. Measured: published OK, branch fails, branch plus a packageExtensions stanza re-declaring the peer OK. This PR removes the peer anyway and ships that stanza in the changeset. Does the seat or maintainer veto this in favour of B or C? Not blocking: A is implemented.",
"options": [
"A, remove the peer (this PR). Business need: fixes every npm 10 install that reaches metadata-core, which has 17 direct published dependents (objectql@next measured EXIT=1 before, EXIT=0 after). It also fixes the npm ERESOLVE for every project on vitest 5 (vitest latest is 5.0.5), including projects that never import ./testing. The cost lands only on ./testing consumers under a non-default strict layout, with zero measured users: all 4 in-repo consumers are workspace links, and objectui has none. Long term: no pin against an upstream accident, and the manifest stops declaring a dependency the runtime entry never reads. AI-error: the requirement is stated in the docblock and the changeset, and a missing vitest fails loudly at import, never silently. Startup focus: shrinks the declared surface and adds no gate.",
"B, keep the peer and narrow its range below 4.1.12. Business need: keeps ./testing resolvable under strict layouts and fixes npm 10 today. It keeps the vitest-5 ERESOLVE on every dependent's install. Long term: pins against an upstream accident, and has to be chased again when vitest ships a coherent 4.x or when the suite moves to vitest 5. AI-error: neutral. Startup focus: a standing maintenance obligation with no measured user.",
"C, move ./testing into its own package, with a required (non-optional) vitest peer. Business need: restores strict-layout correctness without touching runtime installs, but no measured external user pulls for it. Long term: the cleanest separation of runtime and test-kit manifests. AI-error: the strongest option, because the peer becomes enforced instead of optional. Startup focus: a new published package and a migration of 4 in-repo consumers for zero measured pull, which goes against the focus principle now."
],
"recommendation": "A. It fixes the measured public-door failures for every user of the runtime entry, and its one cost falls on a non-default layout that has no measured user and a measured one-stanza remedy. C is the long-term shape if a real external ./testing user under a strict layout appears."
}
],
"out_of_scope_findings": [
"carrier: the domain:engine seat 2 landing obligation recorded in claim 6209875401 (file the domain:devx user-remedy card) · noted, not filed. Evidence for that card: upstream is still incoherent (readings in tests). With metadata-core overridden to this branch on npm 10.9.9, @objectstack/plugin-auth@next and @objectstack/cli@next both still exit 1 with edgesOut, through better-auth@1.7.3's optional vitest peer. So the content/docs/deployment/self-hosting.mdx recipes from addendum 6208166122 stay broken after this PR lands. Measured remedies: npm 11 (EXIT=0), or a root overrides.vitest ~4.0.0 on npm 10.9.9 (EXIT=0). Dedupe words: npm 10 edgesOut cli self-hosting; better-auth optional vitest peer; plugin-auth npm 10 overrides vitest."
]
}
objectstack-fleet commentedon Oct 16, 2026
ACCEPT → PR #23834 comment 6211027345 ·
domain:engineseat 2 ·session_01TQLy3Yq6vF4SDpTXdr3Uwi· 2026-10-16T08:07Z. Landing next: ready, then auto-merge through the queue.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landing record: PR #23834 →
df2c5519ee·domain:engineseat 2 ·session_01TQLy3Yq6vF4SDpTXdr3Uwi· 2026-10-16T08:43Zmerged: true, merge commitdf2c5519ee, merged 2026-10-16T08:40Z through the merge queueorigin/maindf2c5519eis an ancestor oforigin/main(3c080a65c);packages/metadata-core/package.jsonthere has nopeerDependencies/peerDependenciesMeta;.changeset/23806-metadata-core-vitest-peer.mdis presentgh-readonly-queue/main/*pr-23834*head remainsState change: this card closed
completedbyFixes #23806;pm:dispatchedremoved in this act.domain:engine,bugand p1 stay.Landing obligation (claim 6209875401), met: upstream is still incoherent at this landing (
vitestV4= 4.1.12;@vitest/browser-webdriveriohas no 4.1.12).@objectstack/plugin-auth@nextstill exits 1 withedgesOuton npm 10.9.4 (this seat, measured at this landing;plugin-authpinsbetter-authat1.7.3). The user-remedy text is filed as #23849 (domain:devx).Generated by Claude Code