Uh oh!
There was an error while loading. Please reload this page.
fix(cli): declare a pnpm floor in the scaffolded package.json - #10932
Conversation
Both scaffold paths write a settings-only pnpm-workspace.yaml with no `packages:` key, which early pnpm 10 refuses outright — `pnpm install` exits 1 with "ERROR packages field missing or empty" before resolving a single dependency, so a brand-new project could not be installed at all. Declaring `engines.pnpm: ">=10.15"` makes pnpm report its own version instead. Measured, one clean install per pnpm version, each with its own store: 10.5.0-10.14.0 now refuse with ERR_PNPM_UNSUPPORTED_ENGINE naming the range; 10.0.0-10.4.0 parse the workspace file before reading engines so they are unchanged; >=10.15.0 installs as before. engines.pnpm rather than a packageManager stamp: npm, yarn and bun ignore it, so the scaffold keeps working for all four package managers the CLI hands off to. Part of #10497 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r
📓 Docs Drift CheckThis PR changes 2 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7e30277b5b5e7bd67d98580e397a243c0d7b4d4b && git checkout 7e30277b5b5e7bd67d98580e397a243c0d7b4d4b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 3d7deb70005ce2297b5b1a311b629106c3c39bb8 d346c399956268e94a698010dc1d2aefcb029363 && git checkout -B drift-repro 3d7deb70005ce2297b5b1a311b629106c3c39bb8 && git merge --no-ff d346c399956268e94a698010dc1d2aefcb029363
node scripts/docs-audit/affected-docs.mjs --json 3d7deb70005ce2297b5b1a311b629106c3c39bb8
|
Uh oh!
There was an error while loading. Please reload this page.
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32516136591 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Part of #10497
Both scaffold paths write a settings-only
pnpm-workspace.yamlwith nopackages:key. Early pnpm 10 refuses that file outright —pnpm installexits 1 withERROR packages field missing or emptybefore resolving a single dependency, so a brand-new project cannot be installed at all.Per the triage ruling on #10497, this takes the cheapest sound route: declare a
>=10.15floor so the failing band is refused by the package manager itself, without deciding thepackages: []vspackages: ['.']workspace-shape question. The renderedpnpm-workspace.yamlis untouched by this PR.Step 1 was a measurement
Neither scaffold path pinned a floor at head:
grepforpackageManageracrosspackages/cli/srcandpackages/create-objectstack/srcreturns nothing, and the onlyenginesin scaffolded output isengines.protocol(the ADR-0087 handshake inobjectstack.config.ts, not a package-manager range). The CLI rendered exactlyname, version, private, type, scripts, dependencies, devDependencies. So the floor route was live rather than already satisfied.Measured behaviour
The card's repro reproduced exactly before any edit (pnpm 10.0.0 exit 1, 10.15.0 exit 0). Then measured on a project scaffolded by the real CLI (
objectstack init my-app -t app --no-install), one clean install per pnpm version, each with its own store:packages field missing or emptypackages field missing or emptyERR_PNPM_UNSUPPORTED_ENGINE— "Your pnpm version is incompatible ... Expected version: >=10.15"The 10.0–10.4 boundary was bisected across every minor from 10.1.0 to 10.13.0, not assumed.
The residue is real, and it is the fenced decision
The floor is a diagnosis, not a repair. pnpm 10.0.0–10.4.0 parse
pnpm-workspace.yamlbefore they readengines, so they still print the raw workspace error — no floor value changes that, because those versions never reach theenginescheck on this path. Closing that remaining sliver requires deciding what a single-package scaffold should declare underpackages:, which triage routed to a decision card; #10498 and #10499 are queued against that same rendered file and are not touched here.Why
engines.pnpmand notpackageManagerMeasured both.
packageManager: "pnpm@10.15.0"auto-switches and makes 10.5–10.14 succeed rather than refuse, which looks stronger — but it buys nothing on 10.0–10.4 (same raw error), it would declare the project pnpm-only whenobjectstack initdeliberately hands off to npm, yarn or bun viadetectPackageManager, and it pins one exact version that goes stale on every pnpm release. npm, yarn and bun all ignoreengines.pnpm, so the floor costs them nothing — the same principle the workspace file already states about itself. A test pins the choice so a future edit does not quietly add the stamp.Tests
Reverse-verified from the committed state. Removing the floor from both paths turns the new assertions red — create-objectstack
1 failed | 101 passed, CLI init2 failed | 43 passed— and restoring returns102 passed/45 passed. Both suites resolve through source, notdist(the CLI test imports../src/commands/initrelatively; the consistency test reads the template withfs.readFileSync), so this ablation needs no rebuild and none was required for it to be valid.An existing test that re-declared init.ts's package.json inline "to mirror it" now calls the real renderer instead — the hand-copied mirror would have kept passing however far init.ts drifted from it.
Gates
Gate set re-derived from the actual changeset with
node scripts/pm/dispatch-gates.mjs(no hand-supplied paths) atd346c39with a clean tree; all 21 matched and convention-triggered families green, includingcheck-nul-bytes: OK,check-type-check-coverage --re-measure: OK — 33 ledger entr(ies) re-measured ... none above its recorded number(run after building the closure, as lint.yml does),check-engine-double-contract: OKandcheck:template-version-sync. No threshold moved and no baseline raised.Also filed while measuring, unrelated cause, not addressed here: #10931 (a scaffolded project still reports four unmet
@better-auth/utilspeers on first install).Generated by Claude Code