Filed unassigned from the execution seat that implemented #10933 (Option A, the explicit empty packages: [] on both scaffold paths). It is not a defect in that change and does not block it — it is the question that change uncovered, and it needs a maintainer ruling because it is a support-contract statement, not an implementation detail.
What changed under the ruling's own premise
The #10933 ruling reads, verbatim:
Option A — the scaffolded pnpm-workspace.yaml declares the explicit empty packages: []. This makes the file's existing intent ("acts purely as a settings file", a workspace root with no member packages) explicit, and lets pnpm 10.0–10.4 — which parse the workspace file before reading engines and therefore can never be reached by any floor — install a scaffolded project normally.
The clause "can never be reached by any floor" was true of the keyless file. With packages: [] present, those versions get past the parse and reach the engines.pnpm check — where PR #10932's >=10.15 floor now refuses them. Measured on the shape that ships, one clean install per pnpm version, each with its own store:
| fixture | pnpm | result |
|---|
| keyless (before #10933) | 10.0.0 / 10.4.0 | exit 1, ERROR packages field missing or empty |
packages: [], floor >=10.15 (ships today) | 10.0.0 / 10.4.0 | exit 1, ERR_PNPM_UNSUPPORTED_ENGINE — "Your pnpm version is incompatible with PROJECT. Expected version: >=10.15. Got: 10.0.0" |
packages: [], floor >=10.0 | 10.0.0 | exit 0 — Done in 12.3s |
packages: [], floor >=10.0 | 10.4.0 | exit 0 — Done in 8.6s |
So the diagnosis half of the card is fully delivered: every unsupported pnpm now names a cause the user can act on. The "install normally" half is not, and one line decides which.
Why it was not taken unilaterally
Lowering the floor is not free, and the cost is measured rather than argued. On both 10.0.0 and 10.4.0 the install succeeds and silently skips the scaffold's build approvals — those versions do not read the settings out of pnpm-workspace.yaml at all:
The following dependencies have build scripts that were ignored: better-sqlite3, esbuild
To allow the execution of build scripts for these packages, add their names to
"pnpm.onlyBuiltDependencies" in your "package.json", then run "pnpm rebuild"
The peer rules are ignored on the same versions (both declared skews are still reported as unmet peers). On 10.15.0 the allowlist is honoured — better-sqlite3 runs node-gyp rebuild during the install.
A scaffold installed on 10.0–10.4 is therefore a project whose native driver was never built. That is the failure the allowlist exists to prevent, so admitting those versions trades a clear refusal for a quiet degradation.
The options
Not recommending one: axis ① (real business need) turns on a reading nobody has — the share of new users on pnpm 10.0–10.4, a band released Jan–Feb 2025. The #10933 triage flagged the same gap ("我们没有任何用户环境的 pnpm 版本分布读数"). What this measurement adds is that option B is no longer free, which is the part that was not known when the original ruling was written.
Scope
Filed unassigned from the execution seat that implemented #10933 (Option A, the explicit empty
packages: []on both scaffold paths). It is not a defect in that change and does not block it — it is the question that change uncovered, and it needs a maintainer ruling because it is a support-contract statement, not an implementation detail.What changed under the ruling's own premise
The #10933 ruling reads, verbatim:
The clause "can never be reached by any floor" was true of the keyless file. With
packages: []present, those versions get past the parse and reach theengines.pnpmcheck — where PR #10932's>=10.15floor now refuses them. Measured on the shape that ships, one clean install per pnpm version, each with its own store:ERROR packages field missing or emptypackages: [], floor>=10.15(ships today)ERR_PNPM_UNSUPPORTED_ENGINE— "Your pnpm version is incompatible with PROJECT. Expected version: >=10.15. Got: 10.0.0"packages: [], floor>=10.0Done in 12.3spackages: [], floor>=10.0Done in 8.6sSo the diagnosis half of the card is fully delivered: every unsupported pnpm now names a cause the user can act on. The "install normally" half is not, and one line decides which.
Why it was not taken unilaterally
Lowering the floor is not free, and the cost is measured rather than argued. On both 10.0.0 and 10.4.0 the install succeeds and silently skips the scaffold's build approvals — those versions do not read the settings out of
pnpm-workspace.yamlat all:The peer rules are ignored on the same versions (both declared skews are still reported as unmet peers). On 10.15.0 the allowlist is honoured — better-sqlite3 runs
node-gyp rebuildduring the install.A scaffold installed on 10.0–10.4 is therefore a project whose native driver was never built. That is the failure the allowlist exists to prevent, so admitting those versions trades a clear refusal for a quiet degradation.
The options
engines.pnpmat>=10.15(status quo after [Decision] What should the scaffoldedpnpm-workspace.yamldeclare underpackages:? Measured: noenginesfloor can reach pnpm 10.0–10.4, which parse the file before reading engines #10933). pnpm 9.x through 10.14 get one clear refusal naming the range; nobody lands on a half-built scaffold. Cost: 10.0–10.4 cannot install a scaffolded project at all, which is what [finding] The scaffolded pnpm-workspace.yaml has nopackages:key, so pnpm 10.0.0 refuses the install outright — "ERROR packages field missing or empty" #10497 was filed about. The residue is no longer undiagnosable, which was that card's actual complaint.>=10.0. 10.0–10.4 install, matching the ruling's stated aim. Cost: on those versions the build allowlist and the peer rules are dead letters, and the first thing the new user sees is two unmet-peer warnings plus an unbuilt better-sqlite3.package.jsonunder thepnpmfield, which 10.0–10.4 do read. Cost: it reverses a decision currently pinned by a test (does NOT put the allowlist in package.json), and it adds a third copy of a rule that already ships twice (see [finding] Two scaffold paths render the same pnpm-workspace.yaml rule independently, and the drift between them is only ever noticed one incident at a time #10499).Not recommending one: axis ① (real business need) turns on a reading nobody has — the share of new users on pnpm 10.0–10.4, a band released Jan–Feb 2025. The #10933 triage flagged the same gap ("我们没有任何用户环境的 pnpm 版本分布读数"). What this measurement adds is that option B is no longer free, which is the part that was not known when the original ruling was written.
Scope
pnpm-workspace.yamldeclare underpackages:? Measured: noenginesfloor can reach pnpm 10.0–10.4, which parse the file before reading engines #10933's PR, which ships the decidedpackages: []on both paths and leavesengines.pnpmuntouched.packages:key, so pnpm 10.0.0 refuses the install outright — "ERROR packages field missing or empty" #10497 is the card this feeds: its complaint is a first-command failure with no diagnostic, and after [Decision] What should the scaffoldedpnpm-workspace.yamldeclare underpackages:? Measured: noenginesfloor can reach pnpm 10.0–10.4, which parse the file before reading engines #10933 the failure has a diagnostic. Whether that closes it is a call for whoever grades [finding] The scaffolded pnpm-workspace.yaml has nopackages:key, so pnpm 10.0.0 refuses the install outright — "ERROR packages field missing or empty" #10497, and this card is the input.SCAFFOLD_PNPM_RANGEinpackages/cli/src/commands/init.ts, the floor block inpackages/create-objectstack/src/template-consistency.test.ts) already carry this measurement and say the floor is not to be moved as a side effect.