Skip to content

fix(cli): re-measure the better-auth better-sqlite3 peer record, correct what it credits, and pin the declaration it justifies - #17095

Merged
os-project-manager merged 3 commits into
mainfrom
claude/issue-16813-better-sqlite3-peer-range
Sep 9, 2026
Merged

fix(cli): re-measure the better-auth better-sqlite3 peer record, correct what it credits, and pin the declaration it justifies#17095
os-project-manager merged 3 commits into
mainfrom
claude/issue-16813-better-sqlite3-peer-range

Conversation

@claude

@claude claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #16813

Clause-②: no

The first step was a measurement, and it picked the branch

Triage was emphatic that nothing was decidable until the compatibility reading existed, and it was right. Here is that reading, taken rather than inherited — the card's core assertion was explicitly unverified by triage, so it is re-taken from source below.

The card's core assertion is TRUE, from two independent sources

Neither the card nor the triage comment was used as a source for this.

  • Registry manifest for the exact version: GET https://registry.npmjs.org/better-auth/1.7.2 reads peerDependencies["better-sqlite3"] = "^12.0.0".
  • The installed manifest in this tree: node_modules/.pnpm/better-auth@1.7.2_.../node_modules/better-auth/package.json reads the same.

Both also carry a detail the card and triage omit, and it is load-bearing: peerDependenciesMeta["better-sqlite3"] = {"optional": true}.

The two readings triage confirmed relocate cleanly, with one correction — the CLI's declaration is in optionalDependencies, not dependencies (packages/cli/package.json), and packages/plugins/plugin-auth/package.json pins "better-auth": "1.7.2" exactly.

Reproduced, including the trap

A clean install on a satisfied lockfile proves nothing, so the reproduction was run as a real resolve against the published package — a bare project depending on @objectstack/cli@17.3.0, pnpm install --lockfile-only:

 WARN  Issues with peer dependencies found
.
├─┬ better-auth 1.7.3
│ └── ✕ unmet peer better-sqlite3@^12.0.0: found 13.0.3
└─┬ @objectstack/cli 17.3.0
  └─┬ @objectstack/runtime 17.4.0
    └─┬ @objectstack/plugin-auth 17.4.0
      └─┬ better-auth 1.7.2
        └── ✕ unmet peer better-sqlite3@^12.0.0: found 13.0.3

The resolved lockfile names the binding copy exactly: the @objectstack/cli@17.3.0 snapshot carries optionalDependencies: better-sqlite3: 13.0.3.

The compatibility answer: compatible, and structurally so

Triage's re-grade trigger 1 asks whether better-auth's SQLite adapter touches an API that moved between better-sqlite3 12 and 13. Measured NOT met, and it cannot be met:

  • Of the 464 files in the published better-auth@1.7.2 tarball, exactly one names better-sqlite3 — package.json, i.e. the peer declaration itself. Zero code files reference it. Positive control on the same grep: kysely names 9 files.
  • better-auth never imports the package. It accepts a Database the caller constructs and hands it to Kysely; its own sqlite test path uses node's built-in node:sqlite DatabaseSync.
  • And we never supply one: AuthManager.createDatabaseConfig() (packages/plugins/plugin-auth/src/auth-manager.ts) returns createObjectQLAdapterFactory(...), or undefined for better-auth's in-memory adapter. Never a Database.

So the card stays p3. Per triage's own decision tree, "compatible" makes the correct action bookkeeping, not a choice — which is what this PR is.

Why no range moves

The card offered pulling the CLI back inside caret-12 as the other branch. Measured, it is not a neutral alternative. Three arms, same bare project, same pnpm:

arm peer warning better-sqlite3 copies resolved resolution
baseline (@objectstack/cli@17.3.0) reported one: 13.0.3
scoped override pulling only the CLI to caret-12.11.1 cleared two: 12.11.1 and 13.0.3 moves
allowedVersions widening (what the scaffold already ships) cleared one: 13.0.3 byte-identical, 0 lines of diff

The second copy is dead weight: this package loads better-sqlite3 itself (packages/cli/src/utils/sqlite-occupancy.ts) and knex resolves 13.x through @objectstack/driver-sql either way. Clearing a report by installing an unused native module is a worse tree than the report.

What actually changes here

Not a range — the record, which had two measured errors in it, plus the gate that was missing.

  1. Corrected attribution. The record credited @objectstack/driver-sql for the 13.x copy. On the chain that reports, the binding copy is the CLI's own optionalDependencies entry — pnpm names it in the warning text. Editing driver-sql alone would not move this line.
  2. Re-measured version. The reading was taken on better-auth 1.7.1 while the family has been pinned at 1.7.2 throughout; the empirical reading is now backed by the structural one above.
  3. New pinpackages/cli/test/better-sqlite3-peer-declaration.pin.test.ts. The scaffold widens better-auth's peer to a major, and the only reason that major is right is the CLI's declaration; held apart, either can move alone and stay green. The pin reads the major out of the manifest and compares, so neither moves without the other, and the naive "fix" this card invites fails loudly with the reason attached.

Both scaffold producers carry the corrected prose. No declaration, no widening entry and no resolution moves, so pnpm-lock.yaml is untouched — which also means this does not contend with the open PRs holding it.

This PR does not silence the warning for an existing consumer such as hotcrm, and is not meant to: it establishes that the warning is benign, corrects two errors in the record, and pins the declaration so the wrong remedy cannot land later. A consumer that wants the line gone adopts the same scoped allowedVersions entry the scaffold already emits (better-auth > better-sqlite3: 13) in its own pnpm-workspace.yaml — a downstream action, deliberately not implemented here, and one that suppresses the report without moving any resolution.

Ablation for the new pin

Committed first, then mutated, with the mutation proved on disk before the run:

  • anchor counts flipped 1 -> 0 and 0 -> 1; mutated blob f09c205c differs from the HEAD blob 5d84eb3e, so the edit landed and the reading is not a no-op
  • mutated leg RED: expected '13' to be '12' and expected '12' not to be '12' — 2 failed / 2 passed
  • restore leg: blob back to 5d84eb3e, git diff HEAD empty
  • restored leg GREEN: 4 passed

Direction observed: turned red, as predicted.

Verification

  • pnpm --filter @objectstack/cli exec vitest run --project unit190 files / 2628 tests passed (re-run on the merged head)
  • pnpm --filter create-objectstack test16 files / 203 tests passed
  • pnpm --filter @objectstack/cli --filter create-objectstack typecheck — exit 0. Note this package's tsconfig includes src only, so the test layer is the declared hidden layer held by the shrink-only ledger; check:type-check-coverage is what governs it, and it is green.
  • Gate families: scripts/pm/dispatch-gates.mjs derived 62, re-derived after merging origin/main (still 62, no new families), and --ran reconciles 62 run, 0 NOT-MEASURED, 0 UNRUN.
  • pnpm lint (the full repo union, eslint . --no-inline-config) — exit 0, measured at 6a9b7b4989.
  • Three families returned exit 3, which each gate defines as NOT MEASURED rather than a finding, all for whole-repo prerequisites unrelated to this diff: check:dual-build-cjs-loads and check:i18n-coverage ("PREREQUISITE NOT MET", packages with no dist/), and check:type-check-debt (OOM under container contention; its sibling check:type-check-coverage is green). Declared to CI.

Clause-② — re-derived from the delivered diff, and the answer changed shape

Dispatch declared no on the assumption the landing surface would be a range in packages/cli/package.json. It is not — the diff landed in packages/cli/src/commands/init.ts, the blank template's pnpm-workspace.yaml, two test files and a changeset. Re-derived against both limbs:

  • Declaration limb — no new exported symbol and no new key on a published payload. SCAFFOLD_ALLOWED_PEER_VERSIONS already existed and its value is unchanged; what changed is the prose beside it. Nothing an author or a caller writes against moves.
  • Path limb — nothing in packages/spec/src/**, no error-code ledger, no *.zod.ts contract schema.

Both limbs still miss, so the declaration stays no — but it is a different no than the one dispatch reasoned about, which is why it is re-derived here rather than carried forward.

验收备注


Generated by Claude Code


Generated by Claude Code

…record, and pin the declaration it justifies

better-auth peers `better-sqlite3@^12.0.0` while `@objectstack/cli` declares
`^13.0.3`, so every fresh resolve of a tree containing the CLI prints an unmet
peer. The reading that decides what to do about it existed only inside the
scaffold generator, was taken on better-auth 1.7.1, and credited the wrong
package for the 13.x copy.

Re-measured on the pinned 1.7.2 and on a bare project depending on
`@objectstack/cli@17.3.0`; the declaration is correct and stays. Corrects the
record in both scaffold producers and adds the gate that holds the declaration
to the reasoning behind it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QE8qk46e5CHJxyQEUjbf8
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, objectstack-blank, touching 2 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

5 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx (via os init (command, read off packages/cli/src/commands/init.ts))
  • content/docs/getting-started/examples.mdx (via os init (command, read off packages/cli/src/commands/init.ts))
  • content/docs/getting-started/your-first-project.mdx (via os init (command, read off packages/cli/src/commands/init.ts))
  • content/docs/plugins/index.mdx (via os init (command, read off packages/cli/src/commands/init.ts))
  • content/docs/protocol/kernel/index.mdx (via os init (command, read off packages/cli/src/commands/init.ts))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17.mdx (via os init (command, read off packages/cli/src/commands/init.ts))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml) — pages documenting those are invisible to this run
  • the SDK route bridge reached 60 of 216 client-bound route-ledger rows — the other 156 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 156: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json c43bac704819ecb4ae7ecc92b7b3fa2681befe6bpackageMentionDocs.

Which tree this was computed on

This run read content/docs from b523ae915a6da5ed37ef52342ad343cdb1536edc — the merge of head 6a9b7b4989119b0251b7042de31f8921dda22dbd into base c43bac704819ecb4ae7ecc92b7b3fa2681befe6b, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b523ae915a6da5ed37ef52342ad343cdb1536edc && git checkout b523ae915a6da5ed37ef52342ad343cdb1536edc
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c43bac704819ecb4ae7ecc92b7b3fa2681befe6b 6a9b7b4989119b0251b7042de31f8921dda22dbd && git checkout -B drift-repro c43bac704819ecb4ae7ecc92b7b3fa2681befe6b && git merge --no-ff 6a9b7b4989119b0251b7042de31f8921dda22dbd

node scripts/docs-audit/affected-docs.mjs --json c43bac704819ecb4ae7ecc92b7b3fa2681befe6b

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs c43bac704819ecb4ae7ecc92b7b3fa2681befe6b → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation domain:cli size/m tests tooling

Projects

None yet

2 participants