Uh oh!
There was an error while loading. Please reload this page.
fix(scaffold): state the measured pnpm build-approval boundary, and gate the two scaffold paths against each other - #11090
Conversation
… approvals (#10499) Two producers render a `pnpm-workspace.yaml` into a new user's project — `renderPnpmWorkspaceYaml()` in packages/cli and create-objectstack's literal blank template — and both ratchets are package-local, so neither can fail for the other file's regression. That is how one scaffold path went on shipping the pre-`allowBuilds` shape for months, and how the two currently ship contradictory pnpm boundaries for the same key. The gate compares the RENDERED outputs of both producers: the packages each key actually grants a build to, and the pnpm versions each file actually names for each key. Neither file's expected content is restated in the test — every expected value comes from the other producer. Verified RED against the live divergence on main before the comment fix: `objectstack init names [10.26] and npx create-objectstack names [10.31]`. The template read escapes packages/cli, so it is declared in check-cross-package-test-inputs.mjs and in turbo.json's `@objectstack/cli#test` inputs — without that, a template-only diff would replay a cached green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r
…ilds (#10498) The blank template's `pnpm-workspace.yaml` is copied verbatim into every scaffolded project, and its comment told the reader `allowBuilds` needs pnpm >= 10.31 while `onlyBuiltDependencies` covers 10.0-10.30. Measured with one clean install per pnpm version, each with its own store, the floor is 10.26.0: 10.25.0 ignores `allowBuilds`, 10.26.0 honours it. So a user on pnpm 10.28 was told by the file inside their own project that their pnpm cannot read the key it is in fact reading. Both load-bearing claims in that comment were and remain correct — both keys are needed, and pnpm 11 reads only `allowBuilds`. Only the boundary moves. The sibling scaffold path (`renderPnpmWorkspaceYaml` in packages/cli) already carried the measured numbers, so this is what closes the divergence the new consistency gate catches. Comment-only: no assertion, no behaviour and no rendered setting changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r
…eset Three repairs the gates themselves found, all on the new consistency test: * `check:cross-package-test-inputs` rejected the declared template glob as held by nothing — the read was spelled `resolve(\n HERE,\n '…')`, and the detector reconstructs that expression only on one line. Put back on one line, with a comment saying why it must stay there. The reverse-staleness limb catching this is the gate working: an unrecognised read means no declaration, silently. * The same gate then demanded a declaration for `scripts/check-cross-package-test-inputs.mjs` itself, which the test's header quotes while explaining where its read is declared. Declared, following this package's own `check-nul-bytes.mjs` precedent: the literal collector takes quoted paths without parsing, and declaring a rarely-touched file is the trade that entry already settles. * The relative import was extensionless. `packages/cli` is `moduleResolution: NodeNext` and `packages/cli/test` is a hidden typecheck layer (tsconfig `include` is `src` only) held by a shrink-only ledger, so an extensionless import adds a TS2835 plus its TS7006 cascade and reddens check:type-check-debt for everyone. Now `../src/commands/init.js`; measured at 0 errors over `src` + this file. Changeset is a `create-objectstack` patch: the corrected comment ships inside every scaffolded project, while nothing executable moves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 1 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32589379845 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#10499
Fixes#10498
Two scaffold paths render a
pnpm-workspace.yamlinto a new user's project, andon
mainthey ship contradictory prose about the same rule. This PR closesthe instance and the class in one change: the template moves to the measured
pnpm boundary, and a cross-file gate now fails when the two producers disagree.
The divergence, measured at head
03bdd148eeallowBuildsflooronlyBuiltDependenciesbandpackages/create-objectstack/src/templates/blank/pnpm-workspace.yaml:15-17pnpm >= 10.31❌10.0–10.30❌packages/cli/src/commands/init.ts:244-248pnpm >= 10.26✅10.0–10.25✅#10498 measured the true floor at 10.26.0 with per-version clean installs on
isolated stores. #10405 corrected the CLI renderer; the template was never
updated. A user on pnpm 10.28 was told by the file inside their own project that
their pnpm cannot read the key it is in fact reading — while the sibling
scaffold path told them the opposite.
⛔ Repaired by moving the template to the measured numbers.
packages/cli/src/commands/init.tsis read as evidence and is not modified bythis PR (verified: it does not appear in
git diff --name-only origin/main...HEAD).The gate — and why it is not vacuous
packages/cli/test/scaffold-workspace-consistency.test.tscompares therendered outputs of both producers:
renderPnpmWorkspaceYaml()is calledfor the CLI path, and the template file is read for the other. Neither file's
expected content is restated in the test — every expected value comes from the
other producer, so the test measures the two against each other rather than
against a transcription.
Two limbs:
producers, with a non-empty guard on each side (an empty grant would compare
equal while approving nothing).
with a non-empty guard (prose naming no version would compare equal while
telling the reader nothing). Dotted versions only:
10.26and10.0areboundary claims, while the bare majors both files use in passing ("pnpm 11
reads ONLY this one") are prose, and so is the
1in "exits 1".Wording is deliberately not compared — the two files explain the rule in
their own words and are meant to.
Landed RED first, against the live defect
The gate was committed and run before the comment fix, on the divergence
sitting on
main:Limb 1 passed there (both already granted
better-sqlite3,esbuild), limb 2failed — the boundary limb is the one carrying the invariant. After the comment
fix:
Test Files 1 passed (1) · Tests 2 passed (2).Reverse verification
Fix committed first, so both legs restore to a byte-identical tree.
10.31/10.0–10.30in the templateallowBuildslimbobjectstack init names [10.26] and npx create-objectstack names [10.31],1 failed | 1 passedcreate-objectstack's own ratchets30 passed (30)git checkout HEAD --the template path)2 passed (2),git diff HEADemptyThe second row is the thesis of #10499 stated as a measurement: the existing
ratchet stays green through the exact divergence this PR's gate catches.
No rebuild between legs, and none was needed — both sides resolve to
source:
renderPnpmWorkspaceYamlis imported relatively from../src/commands/init.js(no alias redirects it todist/), and the templateis read from
src/templates/. Proof rather than assertion: the verdict flippedRED → GREEN across a source-only edit with no build in between.
Declared repairs beyond the two named files
Both are the same defect class as #10498, mechanically pinned by the measured
table, in files already on the claimed surface:
template-consistency.test.tstest title and failure message. Beyond theheader comment [finding] The blank template's pnpm-workspace.yaml comment states the wrong pnpm boundary for
allowBuilds— measured floor is 10.26.0, not 10.31 #10498 names, the same wrong boundary sat init('… for pnpm 10.0–10.30')and inpnpm < 10.31 does not understand allowBuilds. Correcting the header while leaving those two would have leftthe wrong numbers in the file being corrected. No assertion semantics change
(a title and an
expectmessage), and nothing references either string —checked repo-wide before editing.
the third commit: the cross-package read had to go on one line (the detector
reconstructs
resolve(HERE, …)only unsplit — it flagged my declared glob asheld by nothing); the gate script's own path had to be declared because the
test's header quotes it (this package's
check-nul-bytes.mjsentry settlesthat trade); and the relative import needed its
.jsextension, becausepackages/cli/testis a hidden typecheck layer held by a shrink-only ledgerwhere an extensionless NodeNext import adds a TS2835 plus its TS7006 cascade.
⛔
peerDependencyRulesis untouched — #10931 owns that skew and is still openon this same file. The gate deliberately carries no peer limb, so it neither
duplicates nor pre-empts that card.
Verification, at head
69c17a2347Gate set derived with
node scripts/pm/dispatch-gates.mjsand no patharguments, re-derived after the final commit (same 20 families). All green;
each gate's own verdict line:
plus
check:entry-guard,check:parse-guard,check:slot-lookup,check:template-version-sync,check:type-source-resolution,check:changeset-gate-self-tests,check:objectui-changeset,check:query-options-erasure,check:engine-double-contract,check-adr-0087-registration,check-changeset-no-major,check-plugin-teardown-shape,docs-audit/check-affected-docs— allEXIT=0,captured before any pipe.
Suites:
@objectstack/cli— the new gate plustest/init.test.ts, the siblingratchet on the same renderer:
2 passed (2) files · 51 passed (51).create-objectstack— full suite:13 passed (13) files · 140 passed (140).Two declared narrowings, both because CI runs the farm regardless:
check:type-check-debt --re-measurewas not run whole-workspace (it needsthe full
./packages/*build and re-runs tsc for every ledger entry). Itsquestion for this diff is narrower and was answered directly: the only way
this change can move that ratchet is the new file in
packages/cli/test,which is inside
TEST_DEBT['@objectstack/cli'](146, shrink-only). Measuredwith a temp project over
packages/cli/src+ this one test file, the sameshape
measureTestDebt()builds: tsc exit 0, zero errors, so the countcannot rise. Nothing else in the diff is TypeScript that any ledger entry
reads.
@objectstack/cli's full 137-file suite was not run locally (~500s, and 56%of it is subprocess spawns unrelated to this diff, which is additive there).
Clause-② path limb
git diff --name-only origin/main...HEAD— no path underpackages/spec/src/, as expected:git diff --name-only origin/mainreturns 27 paths here, 21 of them sibling PRs that landed on
origin/mainafterthis branch's merge base (
03bdd148ee) — files this branch never touched. Noneof my six overlap anything that landed since, so there is no conflict risk.
Changeset
create-objectstack: patch. The corrected comment is user-visible — it isdelivered verbatim into every scaffolded project — while nothing executable
moves: the rendered
onlyBuiltDependencies/allowBuildsvalues arebyte-identical, and no assertion changed. The
packages/cliside of this PR isa new test plus input declarations, which ship nothing, so it takes no bump.
Left open
packages/create-objectstack/CHANGELOG.md(lines 643-644 and 743-744) repeatsthe wrong
10.31/10.0–10.30boundary in two historical release entries.Deliberately untouched — a changelog is an append-only record of what shipped,
and rewriting past entries falsifies it; this PR's own changeset carries the
corrected numbers forward. Recorded rather than filed: the GitHub API was rate
limited at report time, so the required search-before-filing pass could not run,
and filing blind risks a duplicate.
CI is not awaited — every conclusion above is local. The lint farm, the full
@objectstack/clisuite andcheck:type-check-debt --re-measureare still inflight on CI at report time.
Generated by Claude Code