Commit fce7cd4
fix(cli): the scaffolded pnpm-workspace.yaml records the retired @better-auth/scim>better-call rule instead of advertising it (#17758)
Fixes #17093
`renderPnpmWorkspaceYaml()` wrote a paragraph into every project
`objectstack init`
scaffolds explaining an `@better-auth/scim>better-call` peer rule that
is not in the
map it annotates. The defect is in what ships, so every reading below is
taken from
the **rendered output**, not from the source.
Shipping proof, before the fix — the sentence is inside the published
tarball's own
`dist` (`@objectstack/cli` publishes `files:
["dist","README.md","CHANGELOG.md"]`):
```
$ grep -c "held at a release candidate deliberately" packages/cli/dist/commands/init.js
1
$ grep -c "Re-measured 2026-09-11 on" packages/cli/dist/commands/init.js # control, same file
1
```
## The three claims, re-measured on this tree
Re-measured here rather than carried from the card — the card's version
number was
already stale, and so was this file's own (see *The file disagreed with
itself*).
### 1. The entry it explains is absent from the rendered map
The rendered `peerDependencyRules.allowedVersions` block, verbatim:
```
'better-auth>better-sqlite3': '13'
'@better-auth/core>@better-auth/utils': '0.5.0'
'@better-auth/oauth-provider>@better-auth/utils': '0.5.0'
'@better-auth/scim>@better-auth/utils': '0.5.0'
'@better-auth/sso>@better-auth/utils': '0.5.0'
```
Zero, with two positive controls from the **same rendered artifact**
under the same
grep shape:
| reading | count |
|:---|:---|
| ZERO — `scim>better-call` | 0 |
| CONTROL — `scim>@better-auth/utils` (a scim-prefixed key that IS
there) | 1 |
| CONTROL — `better-auth>better-sqlite3` | 1 |
The card's cited absence pin is live and passing:
`test/init.test.ts` → *keeps the retired @better-auth/scim>better-call
suppression OUT (#3653)*.
### 2. `@better-auth/scim` is NOT "held at a release candidate
deliberately"
It is pinned at an exact **stable** version. `pnpm-workspace.yaml:239`:
```
'@better-auth/scim@<2.0.0': '1.7.3'
```
and the installed manifest agrees — version string `"1.7.3"`, no
prerelease tag
(`.includes('-')` is `false`). Exactly one copy resolves in the store.
### 3. Stable `@better-auth/scim@1.7.3` peers `better-call` at exactly
`1.4.0`, not `1.3.7`
Read off the installed package manifest, not off prose:
```
peerDependencies: {
"@better-auth/utils": "0.4.2",
"better-call": "1.4.0",
"@better-auth/core": "^1.7.3",
"better-auth": "^1.7.3"
}
```
`better-auth@1.7.3` itself declares `dependencies["better-call"] ===
"1.4.0"`, and the
store holds a single `better-call` copy (`better-call@1.4.0_zod@4.6.1`).
So the skew
the paragraph described does not exist: both sides want the same exact
version.
Note `better-call` appears **four** times in the rendered file and only
two of them are
this defect. The other two are in the `@better-auth/utils` paragraph,
where `better-call`
is the load-bearing reason those four entries exist (it is the package
that depends on
`^0.5.0`). That paragraph is correct and is untouched — a count would
have hidden this;
each hit was read in context.
## Rendered output, before and after
Driven through the card's own repro — `renderPnpmWorkspaceYaml()` out of
the built
`dist`, which is what a scaffolded user receives:
```diff
-# @better-auth/scim (held at a release candidate deliberately) peers an
-# exact better-call 1.3.7, while better-auth itself depends on 1.4.0. A
-# better-auth plugin has to share the host's better-call instance, so
-# the single 1.4.0 copy is the correct resolution.
+# (The '@better-auth/scim>better-call' entry that used to sit here is
+# retired. The rc-era scim pin peered an exact better-call 1.3.7 against
+# better-auth's own 1.4.0 and this map declared that skew away; the pin
+# is a stable release now, and @better-auth/scim 1.7.3 peers an exact
+# better-call 1.4.0 — the one copy better-auth depends on. Re-measured
+# 2026-09-12 off the installed manifest: the skew is gone.)
```
That is the whole rendered delta. **No declaration moves**:
comment-stripped and with
blank lines dropped, the rendered settings are byte-identical across the
change —
14 lines both sides, `sha256` prefix `9992ee6451e59720` before and
after. The
comparison is not vacuous: mutating one character of the map (`'13'` to
`'99'`) is
detected by it.
The shape mirrors the sibling producer, which already recorded the
retirement —
`packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml`.
That was the
asymmetry the card named: one path recorded the retirement while the
other still
advertised the rule.
## This was not an unmaintained block — its neighbour was maintained
past it
The paragraph immediately above, in the same rendered block, was
re-measured
recently. `init.ts:509`-`:510`:
```
'# nothing here goes down that path. Re-measured 2026-09-11 on',
'# better-auth 1.7.3: nothing in the published package references',
```
So someone re-measured better-auth 1.7.3 one day ago, wrote the date
into the
neighbouring paragraph, and left this one advertising an rc-era skew.
The corrected
paragraph therefore carries its own measurement date, in that
neighbour's style.
## The file disagreed with itself — and so did the sibling
A finding in its own right, and the reason none of the three numbers in
play was
taken on anyone's word. Before this PR `init.ts` gave two different
answers for the
same pin:
| site | said | status |
|:---|:---|:---|
| `init.ts:142`-`:143` | "Stable `@better-auth/scim@1.7.1` (the pin
**since #3653 landed**)" | stale — reads as the current pin |
| `init.ts:197` | "stable **1.7.1** peers better-call@1.4.0 exactly" |
stale |
| `init.ts:178` | "Stable `@better-auth/scim@1.7.3` ... re-read
(2026-09-11)" | matches the pin |
| the sibling template | "stable @better-auth/scim **1.7.1** peers
better-call 1.4.0" | stale |
`pnpm-workspace.yaml:239` settles it: the pin is `1.7.3`. The card's own
`1.7.2` was a
third answer, and stale too.
The two stale `init.ts` comments are the source prose for the very entry
this PR
corrects, so leaving them would have manufactured a fresh disagreement
with the
paragraph being fixed. Both now name the measured `1.7.3`, and so does
the sibling
template's note — otherwise the two scaffold paths would have gone on
telling a user
two different versions, which is the exact divergence
`scaffold-workspace-consistency.test.ts` exists to prevent. Each keeps
the `1.7.1`
reading as history, attributed to when it was measured, rather than
deleting it.
## What holds the corrected paragraph: nothing. Stated, not invented.
Per triage's binding boundary, no gate was widened to compare prose.
Measured rather
than assumed — `scaffold-workspace-consistency.test.ts` DOES have a
prose reader
(`keyProse()` / `versionsNamed()`), so "it only compares the map" needed
checking.
Replaying that reader verbatim over both rendered files:
```
keys the gate captures: [ 'allowBuilds', 'onlyBuiltDependencies' ]
allowBuilds -> versionsNamed = [10.26]
onlyBuiltDependencies -> versionsNamed = [10.0, 10.25]
ZERO : captured prose mentioning "better-call" -> 0
ZERO : captured prose mentioning "scim" -> 0
CONTROL: captured prose mentioning "10.26" -> 1
CONTROL: whole file mentioning "better-call" -> 5
CONTROL: whole file mentioning "scim" -> 5
```
Its reader only opens on a comment line whose first token is
`allowBuilds` or
`onlyBuiltDependencies`, and its accumulator resets before the peer
block is reached,
so peer-block prose never reaches it. Identical capture before and after
this change.
So the accounting is:
- the **key's absence** is pinned — `init.test.ts` (#3653), passing;
- the **build-approval prose's version claims** are cross-compared
between the two
scaffold paths — `scaffold-workspace-consistency.test.ts`, passing;
- the **peer-block prose** — this paragraph — is held by **nothing**,
deliberately.
That is a named, accepted gap, and the card's structural half already
rules that
closing it here would defeat a deliberate exemption.
One thing worth checking, since the corrected note now contains the
literal string
`'@better-auth/scim>better-call'` inside a comment while the absence pin
asserts that
string is absent: the pin reads comment-stripped text, so it still
measures the
declaration and not this prose.
```
raw rendered contains the key string: 1
comment-stripped (what the pin asserts on): 0
CONTROL — comment-stripped still contains '@better-auth/scim>@better-auth/utils': 1
```
## Changeset
Required, and present — `patch` for `@objectstack/cli` and
`create-objectstack`. Both
publish the changed bytes: `@objectstack/cli` compiles the rendered
string into
`dist/commands/init.js`, and `create-objectstack` ships
`dist/templates/blank/pnpm-workspace.yaml`; both list `dist` in
`files[]`. Not
`skip-changeset` — the file a user's project receives changes.
## Gates
`dispatch-gates.mjs` derived **58** families for the delivered change
set; all 58 ran
and are reconciled with recorded exit codes:
```
Run reconciliation — 58 derived, 58 run, 0 NOT-MEASURED, 0 UNRUN.
✓ dispatch-gates --ran: 58 derived famil(ies) accounted for — 58 run,
0 NOT-MEASURED (a DERIVED zero — all 58 recorded an exit code and none of them is 3).
```
Two of them first returned `exit 3` — `PREREQUISITE NOT MET`, an unbuilt
workspace,
which is "nothing was measured" and not a finding. Both were re-run
green after
building the prerequisites they named, rather than being recorded as
passes:
`check:i18n-coverage` → `OK (13 config(s), 621 baselined untranslated
string(s), none new)`,
`check:dual-build-cjs-loads` → `104 published require entry point(s)
across 67 package(s) load`.
Also run, all green, all exit codes captured before any pipe:
| run | result |
|:---|:---|
| `pnpm --filter @objectstack/cli exec vitest run --project unit` | 197
files / 2820 tests passed |
| `pnpm --filter create-objectstack test` | 16 files / 203 tests passed
|
| `pnpm --filter @objectstack/cli --filter create-objectstack typecheck`
| passed |
| `pnpm lint` (whole repo, `eslint . --no-inline-config`) | exit 0 —
full run, no narrowing |
| `pnpm check:nul-bytes` + a direct control-character sweep of both
files | clean |
`packages/cli` integration tier is declared to CI: the diff touches no
integration-tier
file, no `bin/` entry and no spawn helper. Heavy runs went through
`scripts/pm/os-verify-lock.sh`; every verdict above is that script's own
`VERDICT command-exit` line.
## Acceptance notes
- `pnpm-workspace.yaml:107`-`:109` carries the same staleness one layer
out: it says
"measured unchanged on 1.7.2, **the version this lockfile now holds**",
while line
`:239` pins `1.7.3` and the installed tree holds `1.7.3`. Out of scope
here (repo
infrastructure, not a scaffold artifact, and nothing a user receives)
and not a
defect class that takes a card — noted for whoever next re-measures the
better-auth
family pins, which is the traffic that reads those lines.
Clause-②: no
<sub>Line added by the dispatching `domain:cli` PM seat (#6024) after
the delivering agent finished — the machine-readable carrier only. ⛔ No
prose of the author's was altered, ⛔ the changeset was not dropped, ⛔
the package was not regraded, ⛔ nothing was pushed or re-run.</sub>
- `Clause-②` re-derived from the delivered diff and unchanged at **no**:
the rendered
declarations are byte-identical, no accept set moves and no published
surface shape
changes. Comments only.
---
_Generated by [Claude Code](https://claude.ai/code)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 0a88a80 commit fce7cd4
3 files changed
Lines changed: 44 additions & 11 deletions
File tree
- .changeset
- packages
- cli/src/commands
- create-objectstack/src/templates/blank
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
142 | | - | |
143 | | - | |
144 | | - | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
145 | 147 | | |
146 | 148 | | |
147 | 149 | | |
| |||
194 | 196 | | |
195 | 197 | | |
196 | 198 | | |
197 | | - | |
198 | | - | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
199 | 202 | | |
200 | 203 | | |
201 | 204 | | |
| |||
514 | 517 | | |
515 | 518 | | |
516 | 519 | | |
517 | | - | |
518 | | - | |
519 | | - | |
520 | | - | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
521 | 526 | | |
522 | 527 | | |
523 | 528 | | |
| |||
Lines changed: 4 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
53 | | - | |
54 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
55 | 57 | | |
56 | 58 | | |
57 | 59 | | |
| |||
0 commit comments