Repository navigation
[finding] root engines.node ">=22.11" admits Node versions that pnpm install refuses under engine-strict (jsdom@30.0.1 needs ^22.22.2) #11366
Description
Activity
objectstack-fleet commented
on Oct 1, 2026 ContributorAuthorMore actionsTriage: first grade —
bug·priority:p3·domain:tooling·area:devpath·pm:queue. The declared floor follows what the install requiresTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-01T09:03Z. ⛔ Not a claim, ⛔ not a dispatch.Why p3. A contributor on a Node version the root
enginesadmits cannot install. The published packages are not affected.Direction. The root
engines.nodefloor, and the contributor docs that restate it, move up to what the locked dependencies require (^22.22.2on the 22 line). ⛔ jsdom is not held back to fit an old floor. Check:pnpm install --frozen-lockfileunder the new floor's lowest version succeeds.
Generated by Claude Code
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingSomething isn't workingand removed
on Oct 1, 2026 objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsMaintainer position on the fix direction: the install floor should not be forced up to Node 22.22.2. Make the toolchain honour the declared
engines.node(>=22.11); do not raiseenginesto match jsdom 30.Measured facts, at objectui
main=89cad75d5570:.npmrcsetsengine-strict=true, and the rootpackage.jsondeclares"node": ">=22.11".- The root
devDependenciespin"jsdom": "^30.0.1". jsdom 30.x declaresengines.node^22.22.2 || ^24.15.0 || >=26.0.0(npm view jsdom@30 engines). jsdom 29.1.x declares^20.19.0 || ^22.13.0 || >=24.0.0. - objectui's own test suites do not run on jsdom:
vitest.config.mtsuseshappy-domandnode, and no source file selects a jsdom environment. The rootjsdomentry exists as the version anchor forpackages/create-plugin/src/templates.ts'DEV_DEPENDENCIES(the table at templates.ts:77-86), whose generated plugin test usesenvironment: 'jsdom'.
So a test-only anchor for a scaffold is what raises the effective floor of every
pnpm installabove the declared one.Downstream cost: objectstack's
scripts/build-console.shrunspnpm install --frozen-lockfilein an objectui checkout at the pin. On Node 22.22.0, the version in the objectstack cloud containers, that install is refused. The last two Console pin bumps (objectstack#21149, objectstack#21380) and the 17.6.0 release verification (objectstack#21330) each had to put a separately downloaded Node in front ofPATHjust to build the Console.Possible directions, in the order I would take them:
- Pin the root
jsdomto^29.1.1, and move the create-plugin anchor with it. That keeps one jsdom across repo and scaffold, and the floor becomes 22.13, within reach of the 22.x lines in use. - Keep jsdom 30 for the scaffold only. Anchor its range somewhere that is not installed at the repo root, so the root install no longer carries jsdom.
Either one keeps
engine-strict=truetruthful without raisingengines.nodeto>=22.22.2.
Generated by Claude Code
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 (priority insert by the maintainer)
Session:session_01YLg8XqWGJ785fwQ5v4pH37
Account:os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-11366-jsdom-29-node-floor
Worktree:objectui-issue-11366
Domain:domain:tooling
Seat:domain:ui#1, taking adomain:toolingcard on the maintainer's direct instruction.
Provenance: the maintainer, in this PM session, at 2026-10-02T21:13Z, verbatim: 「11366 插队,回退相关依赖,不应该强制要求 22.22.2」 (this card jumps the queue; roll back the related dependencies; do not force Node 22.22.2). It matches the maintainer position comment5961542604on this card, and it overrules triage's direction in5928234946(raise the floor, do not hold jsdom back). The lane rule (an execution seat claims in its own lane) yields to the maintainer's words.domain:toolingis unchanged.
Direction (the maintainer's option 1): pin the rootjsdomto the 29.1 line and move the@object-ui/create-pluginscaffold anchor with it. ⛔engines.nodeis not raised to 22.22.2. The declared floor becomes exactly what the regenerated lockfile enforces. Measured by the seat at objectuimainfcdc8ec91:jsdom@30.0.1is the only locked package that rejects Node 22.22.0, andundici@8.9.0/whatwg-url@17.1.0, the two that reject 22.13, are pulled only byjsdom@30.0.1.
File surface:- root
package.json: thejsdomdevDependency andengines.node; pnpm-lock.yaml, regenerated bypnpm install, ⛔ never edited by hand;packages/create-plugin/src/templates.ts: thejsdomentry ofDEV_DEPENDENCIESand its anchor table row;- the
packages/create-plugintests that pin that anchor; CONTRIBUTING.md,QUICK_REFERENCE.md, and the.npmrccomment, where they state the Node floor;- one
@object-ui/create-pluginchangeset.
The dev stops on a breach and explains it in the report.
Container & model:S,mode:subagent,model: opus(default judgment tier; no path-derived mandate for these paths)
Clause-②: no
Why no: no public schema, API or validator accept set moves. The root package is private; the published change is the scaffold's generatedjsdomdevDependency range, a test-toolchain anchor, declared in apatchchangeset.
Thread-read: 5961542604
Serial constraints cleared: read 2026-10-02T21:16Z at objectuimainfcdc8ec91(via the API).- This seat's in flight: objectui#11500 (
packages/cli,cli.mdx, the CLI README); PR objectui#11502 (in the merge queue; nopackage.jsonor lockfile). Disjoint. - Draft PR objectui#11069 (
validate/check) and the release PR objectui#5400: no overlap with thejsdomlines, the rootenginesortemplates.ts.
Scope: the PR says
Fixes #11366.
Generated by Claude Code
- root
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11366,
"status": "done",
"branch": "claude/issue-11366-jsdom-29-node-floor",
"pr": "#11509",
"session": "session_01YLg8XqWGJ785fwQ5v4pH37 (subagent run; the parent PM session id, which is also the container's CLAUDE_CODE_REMOTE_SESSION_ID)",
"premise_still_valid": true,
"summary": "Implemented the maintainer's option 1 (5961542604): the root jsdom devDependency and the create-plugin DEV_DEPENDENCIES entry plus its anchor-table row go from ^30.0.1 to ^29.1.1, the newest 29.1.x (engines ^20.19.0 || ^22.13.0 || >=24.0.0). pnpm-lock.yaml was regenerated by pnpm install under engine-strict with no hand edits, and jsdom@30.0.1, undici@8.9.0 and whatwg-url@17.1.0 are all gone from it. Root engines.node goes from >=22.11 to >=22.13, measured as the highest 22-line lower bound among the 767 installed linux-x64 packages that declare engines (eslint 10, @inquirer/, @pnpm/deps.graph-sequencer and jsdom 29 all sit at 22.13; nothing is higher). So the old 22.11 floor was also already wrong for eslint 10, not only for jsdom 30. CONTRIBUTING.md and QUICK_REFERENCE.md now say 22.13, the .npmrc comment stops restating the number, and a create-plugin patch changeset is added. Measured on this container's Node v22.22.0 with engine-strict on and no override: a fresh frozen install on BASE fcdc8ec exits 1 with ERR_PNPM_UNSUPPORTED_ENGINE naming jsdom@30.0.1, and on HEAD e5eee15 it exits 0. HEAD also installs on a downloaded Node v22.13.0 (exit 0) and is refused on v22.12.0 by the root >=22.13. Draft PR 11509 is open. CI was in_progress when I read it once (22 success, 3 skipped, 19 in_progress), and I did not wait.",
"tests": "All on e5eee15, from the worktree root, through os-verify-lock where heavy. (1) pnpm exec vitest run packages/create-plugin/src/tests/ plus scripts/tests/{check-changeset-presence,check-phantom-dependencies,doc-version-claims,quick-reference-current-release-4143,sync-quick-reference-release,check-doc-links,ci-cd-pipeline-doc,quick-reference-commands-4149}.test.ts. These are every scripts/tests file that git grep finds reading engines, CONTRIBUTING or QUICK_REFERENCE; no test reads .npmrc. Result: 'Test Files 11 passed (11)', 'Tests 408 passed (408)', VERDICT command-exit 0. (2) pnpm --filter @object-ui/create-plugin build and type-check: 'ESM Build success', 'DTS Build success', VERDICT command-exit 0. (3) Install proofs with engine-strict=true, every node_modules removed, pnpm install --frozen-lockfile: BASE fcdc8ec on v22.22.0 gives exit 1 'Your Node version is incompatible with "jsdom@30.0.1(@noble/hashes@2.3.0)" Expected version: ^22.22.2 || ^24.15.0 || >=26.0.0'. HEAD on v22.22.0 gives exit 0. HEAD on v22.13.0 (nodejs.org tarball, sha256 OK against SHASUMS256.txt) gives exit 0. HEAD on v22.12.0 gives exit 1 'Expected version: >=22.13' from the root manifest. (4) Floor computation: a scratch script parsed the lockfile with yaml and semver.Range (which handles spaced ranges like '>= 20.12.0'). It excluded entries whose os/cpu/libc fields do not admit linux/x64/glibc, plus anything in node_modules/.modules.yaml 'skipped' after a fresh install (188 skipped; the platform filter alone catches 186, and the 2 extra are @img/sharp-wasm32 and @emnapi/runtime). That leaves 767 packages that declare engines.node: 0 admit no 22.x, and the floor is 22.13.0. (5) Scaffold on jsdom 29: I wrote the buildPluginFiles output into an untracked dir two levels below the worktree root (so the generated tsconfig's ../../tsconfig.json resolves) and ran the generated example test with the generated test block copied verbatim into a scratch vitest config. Result: 'Test Files 1 passed (1)'. A probe asserting navigator.userAgent contains 'jsdom/29.1.1' also passed. The dir was deleted afterwards. (6) Targeted eslint --format json on packages/create-plugin/src/templates.ts: 1 file, 0 errors, 0 warnings. This is NOT a repo-wide lint claim; pnpm lint belongs to CI. No ablation applies: the reverse verification is the BASE-refused / HEAD-accepted install pair on the same Node.",
"mcp_calls": "0 — no MCP GitHub tool was called, read or write",
"api_writes": "3 REST writes, each sent as one fleet-write relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches, which the board runs as objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/objectui/pulls, draft forced, which created PR 11509; read-back 8512 bytes sent and 8512 stored, identical. (2) label-write --assign os-elon-musk, POST /repos//issues/11509/assignees; read-back matched, zero label calls. (3) this os-dev-report comment, POST /repos//issues/11366/comments, via post-stamped.mjs. git push ran twice (the empty-branch probe and the commit); it is not REST.",
"gates": [
"pnpm check:unused-deps -> exit 0 · 'Every gated declaration has a consumer in the package that declares it.'",
"pnpm check:phantom-deps -> exit 0 · 'Every in-scope import is declared by the package that publishes it.'",
"pnpm docs:check-links -> exit 0 · 'Links are valid across 17 scan roots.'",
"pnpm check:control-bytes -> exit 0 · 'check-control-bytes: OK (scanned 10101 tracked text file(s); skipped 85 binary).'",
"pnpm check:new-line-citations -> exit 0 · 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'",
"node scripts/check-changeset-presence.mjs -> exit 0 · '1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/11366-create-plugin-jsdom-29.md.'",
"pnpm changeset:check -> exit 0 · 'All workspace packages are in the changeset fixed group.' · 'No changeset declares a major bump.'",
"pnpm check:changeset-claims -> exit 0 (report-only) · self-contradiction reading clean. It named 3 pending changesets mentioning pnpm-lock.yaml (5793, 6361, 7122). I re-read them: they are about @objectstack/ resolutions, and this diff moves 0 @objectstack lockfile lines.",
"pnpm check:doc-version-claims -> no such script in objectui. The doc-version-claims.test.ts suite ran in the vitest set instead (green).",
"pnpm quick-reference:check -> exit 0 · 'QUICK_REFERENCE.md's "Current Release" block already states every anchor.'",
"pnpm check:lockfile-integrity (added; the lockfile moved) -> exit 0 · 'VERDICT clean — no @objectstack/* identity moved backward and no package gained a copy.'",
"pnpm check:lockfile-dedupe (added; bare, hard mode) -> exit 0 · 'VERDICT deduped — pnpm dedupe would collapse nothing in this lockfile.'",
"node scripts/check-governed-queue-guard.mjs --test (all 7 paths) -> 'NOT GOVERNED — 7 path(s) checked against 5 governed surface(s); none matched.'",
"CI on PR 11509 head e5eee15 -> in_progress at a single read (44 check runs: 22 success, 3 skipped, 19 in_progress). Convergence is the PM's to watch."
],
"line_budget": "n/a — no skills/** file touched",
"deviations": [
"Lockfile regeneration took two pnpm install passes with a TEMPORARY root pnpm.overrides entry "jsdom": "^29.1.1", which was removed before the commit; there were no hand edits. A plain pnpm install after the manifest edit kept jsdom@30.0.1 (now optional) under the vitest snapshots of 17 workspace packages. pnpm 10.31.0 auto-installs vitest's optional jsdom peer from the highest version already in the lockfile (getHoistableOptionalPeers), so a stale version survives. pnpm dedupe, install --fix-lockfile and update -r --depth Infinity jsdom did not remove it. The committed lockfile is a fixed point: a third pnpm install leaves it byte-identical.",
"The lockfile also carries 12 'deprecated: yuku-analyzer runs on yuku-core since 0.14' lines on @yuku-analyzer/binding-* entries. pnpm wrote them from current registry metadata during the regeneration. They are unrelated to jsdom and declared in the PR body.",
"The .npmrc comment was rewritten to point at root engines WITHOUT restating the number, instead of bumping 22.11 to 22.13 (AGENTS.md #9). It also now says that a refusal of a Node version the floor admits is a repo defect.",
"scripts/check-lint-rule-coverage.mjs still carries the stale literal 'declares engines.node: ">=22.11"' in an error message. Zone 2 item 4 says to correct every non-governed 22.11 floor statement, but the claim's file surface does not include that file, and the brief says a breach means stop. I followed the claim and did not edit it; see open_questions.",
"The scaffold check ran vitest with its own scratch config on generated files in an untracked directory inside the worktree. That means the root vitest.config.mts and its invocation guard were not loaded. This was not a repo test run: repo tests all went through the root config from the worktree root. The directory was deleted.",
"engine-strict override: never used, including on BASE. The BASE leg is itself the strict refusal, so no scratch install with --config.engine-strict=false was needed."
],
"files_changed": [
"package.json",
"pnpm-lock.yaml",
"packages/create-plugin/src/templates.ts",
"CONTRIBUTING.md",
"QUICK_REFERENCE.md",
".npmrc",
".changeset/11366-create-plugin-jsdom-29.md"
],
"open_questions": [
{
"question": "Zone 2 item 4 (correct every non-governed 22.11 floor statement) conflicts with the claim's file surface for scripts/check-lint-rule-coverage.mjs. Its error message says package.json declares engines.node ">=22.11", which is stale after this PR (it fires only on Node below 22.5). How should it land?",
"options": [
"A: the seat extends the claim surface on the card, and a one-line literal-free fix lands on this branch (e.g. 'the root engines.node floor is above 22.5').",
"B: a separate small PR after this one merges."
],
"recommendation": "A. It is the same card and the same defect class (a restated floor drifting from the enforced one), it is a one-line text edit with no new verification surface, and it keeps the floor statement fixed in one place."
}
],
"out_of_scope_findings": [
"carrier: seat · scripts/check-lint-rule-coverage.mjs error text restates engines.node ">=22.11" (stale after this PR; reachable only on Node below 22.5). Noted in PR Acceptance notes, not filed (see open_questions).",
"carrier: 承接者:无 · noted, not filed (observation only): .github/dependabot.yml groups only minor/patch, and dependabot-auto-merge.yml only enqueues those, so a jsdom 30 major would arrive as its own human-gated Dependabot PR. Merging it would put the floor back at 22.22.2 with CI still green, because CI runs node-version 22.x. Recorded in PR Acceptance notes only."
]
}objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsClaim amendment (seat): the file surface gains one line of
scripts/check-lint-rule-coverage.mjs; the dev's open question in5961940627is ruled Adomain:uiseat 1 ·session_01YLg8XqWGJ785fwQ5v4pH37· 2026-10-02T21:43Z. Amends claim5961613739. Everything else in it stands.- Added to the file surface:
scripts/check-lint-rule-coverage.mjs, its one error message that restates the root floor as">=22.11". That statement is stale once the floor is>=22.13. - Ruling: A, on this branch. The fix is the error text only, made literal-free so it points at the root
engines.nodefloor without restating a number, as the.npmrccomment now does. ⛔ No change to the script's logic or its Node threshold. - Why A: the same card, and the same defect class: a restated floor drifting from the enforced one. It is a one-line text edit with no new verification surface. A separate PR would leave a known-stale statement on
mainafter this one lands. - Not carried: the dev's Dependabot observation, that a jsdom 30 major would arrive as its own human-gated PR and raise the floor again while CI on
22.xstays green. It stays in the PR's Acceptance notes. ⛔ No new gate.
Generated by Claude Code
- Added to the file surface:
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 11366,
"status": "done",
"round": "patch round 1 (ruling A, claim amendment 5961960157)",
"branch": "claude/issue-11366-jsdom-29-node-floor",
"head": "e0639b06f8ca546549326b9dab79c54fd33371c0",
"pr": "#11509",
"session": "session_01YLg8XqWGJ785fwQ5v4pH37 (subagent run; the parent PM session id, which is also the container's CLAUDE_CODE_REMOTE_SESSION_ID)",
"premise_still_valid": true,
"summary": "I recreated the worktree at the branch head e5eee15 and edited only the matchesGlob error string in scripts/check-lint-rule-coverage.mjs. It said package.json declares engines.node ">=22.11"; it now reads 'It arrived in Node 22.5 and the root package.jsonengines.nodefloor sits above that, so reaching this line means the floor moved or the runtime is not the declared one.' The check, the throw and the third string line are untouched (diff: 2 lines out, 2 in). This is commit e0639b0, pushed. Main moved from fcdc8ec to 9d9ed54 (one commit, #11502), and that commit touches no package.json, no pnpm-lock.yaml and not this script, so per the brief there was no merge. A fresh strict frozen install on v22.22.0 at e0639b0 still exits 0. The PR body was not edited.",
"tests": "All on e0639b0, from the worktree root. (1) Install: every node_modules was absent in the new worktree; pnpm install --frozen-lockfile on Node v22.22.0 with engine-strict=true gave exit 0, 'Lockfile is up to date, resolution step is skipped'. (2) git grep -l check-lint-rule-coverage in scripts/tests finds exactly one file, check-lint-rule-coverage.test.ts. Run through os-verify-lock with pnpm exec vitest run scripts/tests/check-lint-rule-coverage.test.ts: 'Test Files 1 passed (1)', 'Tests 35 passed (35)', VERDICT command-exit 0. No test pins the message text: git grep finds the message's phrases only in the script itself. (3) On disk: the edited file holds 0 occurrences of 22.11 and 1 of 'floor sits above that', and node --check parses it.",
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "1 REST write: this os-dev-report comment, POST /repos//issues/11366/comments, via post-stamped.mjs as one fleet-write relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches). git push ran once (e5eee15 to e0639b0); it is not REST. The PR body and labels were not touched.",
"gates": [
"pnpm exec vitest run scripts/tests/check-lint-rule-coverage.test.ts -> exit 0 · 'Test Files 1 passed (1)' · 'Tests 35 passed (35)' · 'os-verify-lock: VERDICT command-exit 0'",
"pnpm check:control-bytes -> exit 0 · 'check-control-bytes: OK (scanned 10101 tracked text file(s); skipped 85 binary).'",
"pnpm check:new-line-citations -> exit 0 · 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'",
"CI on e0639b0 -> in_progress at a single read (28 check runs so far: 21 success, 1 skipped, 6 in_progress); convergence is the PM's to watch."
],
"remaining_22_11_hits": [
"Pathspec: git grep -nE '22\.11' over the tree minus the governed surfaces (AGENTS.md, CLAUDE.md, .claude/, skills/, docs/adr/). The governed surfaces themselves return 0 hits; positive control: the same pathspec finds 'engines|Node' in AGENTS.md and skills/objectui/, so the zero is a reading.",
".changeset/6313-quick-reference-node-floor.md (2 hits) -> a pending changeset body describing objectui#6313's fix against the floor as it stood then ("Against root engines.node ... (objectui#5306 / PR #6311)"). It is a historical record of that change, not a current floor statement, and editing it would rewrite what that change measured.",
"pnpm-lock.yaml (15 hits, the @changesets/ 3.x/8.x family, e.g. '@changesets/cli@3.0.1') -> each package's own published engines.node '^22.11 || ^24 || >=26'. This is generated registry metadata and not a statement of this repo's floor; its 22-line lower bound (22.11) is below the 22.13 floor, so it does not set the floor.",
"scripts/tests/quick-reference-current-release-4143.test.ts (5 hits) -> docblock history ('has since moved again, to >=22.11 (objectui#5306 / PR #6311)') and worked examples of the old match(/(\d+)/) bug ('>=22.11 derived a floor of 22'). The test derives its expected floor from root engines.node at run time and is green on >=22.13. Not a floor statement.",
"scripts/setup.sh:52 -> a comment showing the prefix-strip transform (">=22.11" -> "22.11"); the script reads engines.node from package.json at run time. It is a worked example, not a floor statement.",
"scripts/sync-quick-reference-release.mjs:122 -> the docblock's worked example of the same old leading-digits bug ('>=22.11 produced a floor of 22'); the script reads the manifest at run time. Not a floor statement.",
"Conclusion: no remaining non-governed hit states the current install floor."
],
"line_budget": "n/a — no skills/ file touched",
"deviations": [],
"files_changed": [
"scripts/check-lint-rule-coverage.mjs (this round; the matchesGlob error string only)"
],
"open_questions": [],
"out_of_scope_findings": []
}objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actions✅ ACCEPT (seat review): PR objectui#11509 at
e0639b06f(Fixes #11366); jsdom goes back to the 29.1 line, andengines.nodebecomes the floor the lockfile enforces,>=22.13, not 22.22.2;Clause-②: no, so the seat lands itdomain:uiseat 1 ·session_01YLg8XqWGJ785fwQ5v4pH37· 2026-10-02T22:02Z. Read for this verdict: the dev reports5961940627and5961998344, the PR body, its 8-file list (+106 / −77), every hunk except the regenerated lockfile, the lockfile'sjsdom/undici/whatwg-urllines, and the check-runs on the head after every one completed: 45, 42success, 3skipped(dependabot,Test (coverage),Test (coverage shard)), 0 failure.Against the maintainer's direction
The maintainer, in the PM session: 「11366 插队,回退相关依赖,不应该强制要求 22.22.2」, and the position comment
5961542604, option 1.- "Pin the root
jsdomto^29.1.1, and move the create-plugin anchor with it": met. The root devDependency,DEV_DEPENDENCIES.jsdominpackages/create-plugin/src/templates.ts, and that file's anchor-table row all read^29.1.1, the newest 29.1.x (engines^20.19.0 || ^22.13.0 || >=24.0.0). - "Roll back the related dependencies": met. The regenerated lockfile no longer holds
jsdom@30.0.1,undici@8.9.0orwhatwg-url@17.1.0; the seat had measured the last two as pulled only by jsdom 30. The lockfile is a fixed point: a thirdpnpm installleaves it byte-identical. No hand edits; a temporarypnpm.overridesentry was used during regeneration and removed before the commit.check:lockfile-integrityandcheck:lockfile-dedupeare clean. - "Must not force 22.22.2": met.
engines.nodeis>=22.13, measured as the highest 22-line lower bound among the 767 packages actually installed on linux-x64 (eslint 10,@inquirer/*,@pnpm/deps.graph-sequencerand jsdom 29 all sit at 22.13). The old>=22.11was already untrue for eslint 10. - The proof, on this container's Node v22.22.0 with
engine-strict=trueand no override:- BASE
fcdc8ec91: a fresh frozen install exits 1 withERR_PNPM_UNSUPPORTED_ENGINE, namingjsdom@30.0.1. - HEAD: exits 0, and again after the patch round.
- On a downloaded Node v22.13.0, HEAD installs. On v22.12.0 it is refused by the root
>=22.13, so the floor is exact.
- BASE
- The scaffold on jsdom 29: the generated example test passed under jsdom 29.1.1 (a
navigator.userAgentprobe confirmed the version).
Patch round 1 (ruling A, claim amendment
5961960157)scripts/check-lint-rule-coverage.mjs'smatchesGloberror text stops restating">=22.11"and points at the rootengines.nodefloor. 2 lines out, 2 in, no logic change; its test file passed 35 of 35. The remaining non-governed22.11hits were each read: a pending changeset's history,@changesets/*'s own engines in the lockfile, and docblock worked examples. None states this repo's floor.Prose
@object-ui/create-pluginpatch: the generated plugin'sjsdomdevDependency is^29.1.1, with the reason. The root package is private, and the PR body says so.CONTRIBUTING.mdandQUICK_REFERENCE.mdsay 22.13. The.npmrccomment points at rootengineswithout restating a number, and says a refusal of a Node version the floor admits is a repo defect.Mechanics
- Body line 1 is
Fixes #11366; line 3 isClause-②: no, which holds: no public schema, API or validator accept set moves. - Model-free trailers.
- Not governed: 8 paths, 183 lines.
- PR assignee mirrors the card.
Out-of-scope findings
- The Dependabot observation (a jsdom 30 major would arrive as its own human-gated PR and raise the floor again, with CI on
22.xstill green) →Acceptance notes, surfaced to the maintainer. ⛔ No new gate.
Next: ready and into the merge queue.
Generated by Claude Code
- "Pin the root
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsLanded: PR objectui#11509 merged as
059bf1b59through the merge queue;pm:dispatchedand the assignee cleareddomain:uiseat 1 ·session_01YLg8XqWGJ785fwQ5v4pH37· 2026-10-02T22:20Z. Claim5961613739, amended by5961960157, is spent. The ACCEPT is the seat's comment on this card, on the landing heade0639b06f.Clause-②: no, so no contract record is owed.- Verified by content on
origin/main: the squash059bf1b59's own diff against its parent2d576e46eis 8 files, +106 / −77, exactly the PR's file set and counts. Rootpackage.jsonreads"node": ">=22.13"and"jsdom": "^29.1.1".pnpm-lock.yamlholds nojsdom@30,undici@8.9.0orwhatwg-url@17.1.0. The co-author trailer is model-free. - Closing keywords: the PR body names
#11366only. The card closedcompletedon the merge, and no other card was closed by it. - What it changes, as the maintainer directed (「回退相关依赖,不应该强制要求 22.22.2」):
- A contributor on any Node from 22.13 up installs with
engine-strict=true. That includes 22.22.0, the version in the objectstack cloud containers, whichmainrefused until now. - The floor is not raised to 22.22.2.
- objectstack's Console builds (
scripts/build-console.sh, the pin bumps and release verification named in5961542604) no longer need a separately downloaded Node, once their objectui pin moves past059bf1b59.
- A contributor on any Node from 22.13 up installs with
- Left in the PR's Acceptance notes: a future jsdom 30 major from Dependabot would raise the floor again with CI on
22.xstill green. ⛔ No gate added.
Generated by Claude Code
- Verified by content on
- added a commit that references this issue
on Oct 7, 2026
Filing-gate class: ① a defect with a named site and a measured reproduction (
finding, class (b): a declared contract the install path contradicts).Acting reader: objectui triage grades it. The fix lands at whichever end triage picks: the root
enginesfloor, or thejsdomresolution.Dedup: I listed objectui's issues over REST (all open, plus the 500 most recently updated closed) and grepped them for
ERR_PNPM_UNSUPPORTED_ENGINE,engine-strictand22.22.2. 0 hits. The control termenginesdoes return hits, so the corpus answers.Source: the out-of-scope finding in the os-dev report on #11356 (comment 5927721183), re-measured by the PM seat (
session_018gA1pE6eJtwHhqx72G8U9X) at objectuiorigin/main2124d04111.Measured
package.jsondeclares"engines": { "node": ">=22.11", "pnpm": ">=10" }..npmrcsetsengine-strict=true. Its comment says it enforces "the rootenginesrange at install time instead of documenting it".pnpm-lock.yamllocksjsdom@30.0.1, and its entry carriesengines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0}.npm view jsdom@30.0.1 enginesgives the same range.pnpm install --frozen-lockfileat2124d04111exits 1 withERR_PNPM_UNSUPPORTED_ENGINE"Your Node version is incompatible with jsdom@30.0.1 … Expected version: ^22.22.2 || ^24.15.0 || >=26.0.0". The os-dev measured this in its container.CONTRIBUTING.md("Node.js 22.11 or higher") and inQUICK_REFERENCE.md("≥ 22.11").So every Node from 22.11 up to 22.22.1 is advertised as supported and refused at install.
Direction (for triage, not a ruling)
Either raise the declared floor to what the lockfile actually enforces, with the two docs following it, or move the
jsdomresolution to a line that admits the declared floor. The.npmrccomment's own instruction, to upgrade node/pnpm to the declared floors, does not fix it, because the declared floor is the one that is too low.Generated by Claude Code