Repository navigation
Commit 03966ce
fix(plugin-auth)!: lift the better-auth family from 1.7.3 to 1.7.12 (#25109)
Fixes #25096
Clause-②: no (narrowing)
Metadata-protocol: none
## What changed
- **The lift, one commit (`75aaf74a1d`).** The 11 better-auth family
overrides in `pnpm-workspace.yaml` and the 5 exact ranges in
`packages/plugins/plugin-auth/package.json` move from `1.7.3` to
`1.7.12`, still exact. The selectors keep their bound at the 2.0.0 major
boundary; the header's selector rule is untouched. The lockfile is
regenerated by `pnpm install` (under the verify lock), never by hand.
- **`pnpm-workspace.yaml` family note** states the new target, why, and
what moved with it.
- **`auth-route-ledger.ts`**: one new row, `POST
/api/v1/auth/oauth2/client/rotate-keys`. `@better-auth/oauth-provider`
1.7.12 registers it, so the catch-all publishes it. It is refused `403
access_denied` because `auth-manager.ts` does not set
`allowClientKeyRotation` (measured below). This is the one test the lift
turned red (`auth-route-ledger.conformance.test.ts`, the mounted-surface
equality).
- **Two new pin files** for vendor changes plugin-auth callers now
depend on, each with one ablation leg (below):
- `session-read-failure-answer.test.ts`: a session lookup the store
cannot answer is a failure, never a signed-out caller.
- `verification-reservation-single-use.test.ts`: the ObjectQL adapter
keeps the primary key better-auth forces on a single-use reservation, so
a replay is refused.
- **Version attestations**: the 32 lines under
`packages/plugins/plugin-auth/src` that named `1.7.3` were each
re-measured on 1.7.12 (table below). 19 restamped with the date and the
card, 12 left as written (they are facts about the 1.7.3 release and
still hold), and 1 not restamped but flagged and reported (its claim is
false).
- **`.changeset/25096-better-auth-1-7-12.md`**:
`@objectstack/plugin-auth` `minor`, BREAKING, with the `Clause-②` line,
the ADR-0087 disposition `not-required (no-migration-prescription)`,
FROM / TO per measured change, Unchanged, and the operator notes.
No behaviour of plugin-auth changes beyond the vendor's. No other
dependency was moved on purpose; `packages/spec/**` and
`packages/objectql/**` are untouched.
## Lockfile: what moved
Resolved package set, old vs new (`packages:` keys of `pnpm-lock.yaml`):
- The family: all eleven `1.7.3` to `1.7.12`.
- Declared by 1.7.12 itself: `better-call` 1.4.0 to 1.4.4,
`@better-auth/utils` 0.4.2 removed (0.5.0 was already resolved and is
now the only copy; 1.7.12 peers `^0.4.2 || ^0.5.0`),
`@better-fetch/fetch` 1.3.1 to 1.3.2.
- Gone because 1.7.12 no longer asks for them: the auto-installed
`better-sqlite3@12.11.1` copy (better-auth dropped its optional
`better-sqlite3 ^12` peer) and the 20 packages only its native build
used (`prebuild-install`, `node-abi`, `tar-fs`, `bindings` and the
rest); `@cloudflare/workers-types` (core dropped the peer);
`@opentelemetry/semantic-conventions` (core dropped the dependency);
`@noble/ciphers@2.3.0` and `tldts`/`tldts-core@7.4.9` (deduplicated onto
the 2.4.0 and 7.4.16 copies already in the tree).
- Nothing added outside the family. One cosmetic swap: the `vitest`
snapshot lines of the `packages/apps/account` and `packages/apps/setup`
importers exchanged which of the two existing `vite@8.3.4` peer variants
(`esbuild@0.28.1` / `0.28.2`) they name. No version entered or left.
## Measured on 1.7.12, item by item (the card's list)
Real stack throughout: `ObjectQL` over `@objectstack/driver-sql`
(better-sqlite3 `:memory:`), the objects from plugin-auth's manifest, a
real `AuthManager`, requests through `AuthManager.handleRequest`. Where
a reading comes from a one-shot probe it is marked **probe**: a
throwaway vitest file in the package, run once at `347772618d`, not
committed.
| Card item | Reading on 1.7.12 | How |
|---|---|---|
| Export surface | `check:vendor-export-contract` PASS, 3 edges
(`@better-auth/core/context`, `@better-auth/core/utils/ip`,
`better-auth/adapters`); `check:override-consistency` PASS; plugin-auth
`build` (DTS) and `typecheck` green | gates |
| 1.7.7 better-auth/better-auth#11494 identifier prefixes vs
`implicit-account-linking.ts` | A Magic Link row is stored as
`magic-link:TOKEN` with value `{"type":"magic-link",...}`; an OAuth
state row as `auth-state:STATE`. The unlink tombstone is
`account-unlinked:USER:PROVIDER`; its exact read and its user-prefix
read each return the tombstone alone, and the user sweep left both
vendor rows in place. No collision, and plugin-auth reads neither
prefix. `implicit-account-linking.test.ts` green | probe + suite |
| 1.7.8 better-auth/better-auth#11391 `customSession` now throws | Over
HTTP a store failure on `GET /get-session` answers `500
FAILED_TO_GET_SESSION` and keeps the session cookie; in process
`api.getSession` rejects. Before (vendor ablation restoring the 1.7.7
catch): `401 UNAUTHENTICATED` "Sign in first" and `null`. Right answer:
yes, see below | new pin + ablation |
| better-auth/better-auth#11540 / better-auth/better-auth#10591 /
better-auth/better-auth#11718 cookies and session storage, with
`secondaryStorage` | **Fork, below.** Cookies: `HttpOnly; SameSite=Lax;
Path=/`, no `Secure` on plain HTTP, the same with or without a host
`secondaryStorage`, so the RFC 6265bis forcing (`SameSite=None` and
`Partitioned` imply `Secure`, in `better-call` 1.4.4) never applies to
plugin-auth's cookies. better-auth/better-auth#10591: a stale session
cookie on `/get-session` is now cleared (`Max-Age=0` on `session_token`,
`session_data`, `dont_remember`) alongside the same `401`.
better-auth/better-auth#11718: not armed here | probe |
| 1.7.7 better-auth/better-auth#11375 active organization refresh vs the
`session.create.before` stamp | Client-only: it widens the organization
client's `$activeOrgSignal` matcher to the session signals. No server
path changed. The stamp's suites (`first-session-membership-ordering`,
`session-positions-security-axis`, `session-grants-resolved-once`,
`principal-session-mint`) green. The client that would pick it up is
objectui's `@object-ui/auth`, which declares `better-auth ^1.7.2` on its
own lockfile; nothing here moves it | dist + suite |
| oauth-provider 1.7.9 better-auth/better-auth#10799 DPoP `htu` |
Authorization-code exchange with a DPoP proof: `htu` = the public base
URL is accepted (`token_type: DPoP`) even when the request reaches the
server under another host (`127.0.0.1:3000`); `htu` = that request URL
is refused `400 invalid_dpop_proof` "DPoP proof htu does not match the
request URL". 1.7.3 compared against the request URL. **Widening for
host-rewriting proxies, in open questions** | probe |
| oauth-provider 1.7.10 better-auth/better-auth#11724 PKCE 401 to 400 |
Wrong `code_verifier`: `400 invalid_grant` "code verification failed";
control with the right verifier: `200`. **No pin of the old 401 exists**
(repo-wide grep for PKCE / `code_verifier` in tests: the success-path
uses in `auth-manager.mcp-oauth-resource.test.ts` and
`auth-manager.oauth-consent-organization.test.ts`, no status pin on a
mismatch), so none was updated | probe + grep |
| 1.7.8 better-auth/better-auth#11625 replay protection; which ids the
adapter generates | plugin-auth sets no `generateId`: user, session,
account and verification rows carry better-auth's own 32-character
base62 ids, kept as given. A reservation is stored under the forced
base64url SHA-256 id, and its replay is refused. The `uuid` path the fix
is about is not armed here | new pin + ablation + probe |
| Version attestations | 32 lines, table below | dist re-reads, suites,
probes |
| GHSA-965c-763c-88jm precondition set | With Magic Link on (plain token
storage, the default), a social provider configured and database-backed
OAuth state, a value minted by the OAuth-state flow presented at
`/magic-link/verify` answers `302` to `?error=INVALID_TOKEN`, sets no
session cookie, and leaves the state row intact. Control: the real link
answers `302` to the callback with a session cookie. The precondition
set no longer yields the exposure | probe |
**Is the new `customSession` answer right?** Yes. A store outage is not
a signed-out caller. Under 1.7.3 the browser was told "Sign in first"
while its session still existed; now it is told the read failed and
keeps its cookie. That follows AGENTS.md "Absence must be loud" and the
degradation rule (a failure handed to the caller is not a silent
degradation). The in-process callers that want "anonymous" on a failed
read keep it on purpose: `resolveRequestExecutionContext` (core) and
`resolveSessionData` (runtime) catch the throw themselves. One
in-process path gets stricter: core's auth-gate re-read
(`decideAuthGate`) already maps a throw to `AuthzStoreUnavailableError`;
under 1.7.3 the swallowed failure reached it as `null` and the gate read
as not held. The raw `/admin/*` routes that call `api.getSession` answer
through their own `catch`.
Also measured, not on the card's list (both in the changeset): an
over-long password at `/sign-in/email` now answers `400
PASSWORD_TOO_LONG` before any lookup, and still counts as a failed
attempt for the lockout (`failed_login_count` 0 to 1, then 2 after a
wrong short password); and the new `rotate-keys` route answers `403
access_denied` "Client key rotation is disabled".
## Forks from the card
1. **"plugin-auth sets session `storeInDatabase` whenever a host
supplies `secondaryStorage`."** Measured: it sets
`verification.storeInDatabase: true`, not
`session.storeSessionInDatabase`. With a host `secondaryStorage` the
session of record lives in the cache only (0 `sys_session` rows; the
cache holds the token and `active-sessions-USER`), and `/list-sessions`
answers from that list. better-auth/better-auth#11718's database
fallback (`databaseSessionFallbackEnabled`) requires
`storeSessionInDatabase === true`, so it is never armed on this
platform.
2. **"Any test that pins the old [PKCE] status needs updating."** None
exists; nothing to update.
3. **Changeset level.** The card asks `patch`; this ships `minor`,
BREAKING, per the claim's `Clause-②: no (narrowing)`.
## Attestations: the 32 lines
R = restamped to 1.7.12 with the date and #25096 after the re-measure; K
= kept, a fact about the 1.7.3 release that still holds on 1.7.12; F =
flagged, not restamped.
| Line at base | Claim | 1.7.12 | |
|---|---|---|---|
| `account-identity-preflight.ts:11` | 1.7.3 removed the issuer-scoped
account identity | account key still `(providerId, accountId)`, no
`issuer` in core's account table | K |
| `account-invitation-marker.ts:14` | `requestPasswordReset` answers `{
status, message }`; only `sendResetPassword` gets the link |
`password.mjs` request leg unchanged | R |
| `account-invitation-marker.ts:68` | `runInBackgroundOrAwait` catches
the send; answer stays `{ status: true }` | `create-context.mjs`
unchanged there | R |
| `admin-import-users-invite-delivery-failure.test.ts:9` | same | same;
suite green | R |
| `admin-user-endpoints.ts:69` | `providerId` + `accountId` is the whole
identity since 1.7.3 | holds | K |
| `auth-email-locale.test.ts:871` | `/sign-in/magic-link` does no user
lookup; `/magic-link/verify` creates a user unless `disableSignUp` |
holds (1.7.12 adds a form-CSRF middleware and a record-type check, no
lookup) | R |
| `auth-email-locale.test.ts:1006` | body schema has no case transform;
`findUserByEmail` lowercases | holds | R |
| `auth-manager.test.ts:318` | 1.7.3 rolled the issuer key back | holds
| K |
| `auth-manager.ts:1802` | `appName` read once; two otpauth readers; no
cookie name derives from it | same three sites | R |
| `auth-manager.ts:2062` | the reset token lives
`resetPasswordTokenExpiresIn` seconds, or 3600 when that is falsy |
`password.mjs:73` | R |
| `auth-manager.ts:2084` | a server-side reset reaches the callback with
no request | `to-auth-endpoints.mjs` byte-identical;
`sendResetPassword(..., ctx.request)` unchanged | R (extended) |
| `auth-manager.ts:4727` | no `database` builds a store keyed by schema
KEY, read by `modelName` | probe: `Model sys_user not found` | R |
| `auth-manager.ts:9701` | `/sign-in/email` asks
`findUserByEmail(email.toLowerCase())` | holds, now after the new length
check | R |
| `auth-schema-config.ts:104` | 1.7.3 removed the issuer model | holds |
K |
| `auth-schema-config.ts:956` | scim exposes no `schema` option; six
`SCIMOptions` members | holds | R |
| `auth-schema-config.ts:961` | the re-read history | 1.7.12 appended |
R (extended) |
| `implicit-account-linking.ts:45` | the `handleOAuthUserInfo` gate,
then `assertValidUserInfo` with `link-account` | holds; the explicit
link now runs through `linkOAuthAccount`, same check, noted | R |
| `in-process-redispatch.ts:30` | `disableRefresh` is read from the
query on both re-dispatches | `in-process-session-renewal.pin.test.ts`
green | R |
| `internal-field-readback.ts:197` | the read-back census, including
"`identifier`: no flow reads it back off a row" | **false, on 1.7.3 and
1.7.12 alike**: `@better-auth/sso`'s `/sso/verify-domain` reads it back
(reported below) | F |
| `invite-role-not-found-code.ts:16` | invite throws an uncoded
`ROLE_NOT_FOUND`; update-member-role a coded one | `crud-invites.mjs`
byte-identical; `crud-members.mjs` still coded | R |
| `list-user-invitations-verification.ts:11` | `listUserInvitations`
never asks the verification rule | `crud-invites.mjs` byte-identical | R
|
| `objectql-adapter.test.ts:95` | 1.7.3 removed the `issuer` column |
holds | K |
| `objectql-adapter.ts:1051` | identity is `(provider_id, account_id)`
since 1.7.3 | holds | K |
| `organization-delete.ts:10` | what `POST /organization/delete` does
and leaves | `crud-org.mjs` and the organization adapter byte-identical
| R |
| `session-envelope-completion.ts:21` | `createSession` awaits the
write; line references | holds; lines now `259-332` and `333-370` | R |
| `two-factor-reenrollment-verified-reset.test.ts:27, 29, 340, 345, 354,
461` (6 lines) | 1.7.3 added the `TOTP_ALREADY_ENABLED` gate |
`plugins/two-factor/index.mjs` byte-identical 1.7.3 to 1.7.12 | K |
| `two-factor-totp-issuer.test.ts:11` | what better-auth does with
`appName` | same three sites | R |
`node scripts/check-vendor-version-stamps.mjs` is green on every
plugin-auth line. **It stays red on two sites outside this card's file
surface**, which the lift makes false and which I did not touch (claim:
stop on breach):
- `packages/spec/src/identity/organization.zod.ts:95`: "Both halves
measured against the installed better-auth 1.7.3, so fallback A
applies". `packages/spec/**` is a hard stop, and the line is TSDoc on a
schema property. Re-measured on 1.7.12: the organization plugin's
`schema.mjs` is byte-identical and the adapter factory's
`transformOutput` still iterates the declared fields only, so the claim
holds and a restamp is honest.
- `packages/cli/src/commands/migrate/account-issuer.ts:71`: the command
description "...is ONE account under the key better-auth 1.7.3
restored". It is operator-facing text. The claim holds on 1.7.12.
Both need the seat's word on the file surface before this lands; the
report proposes the text.
## Ablations
Both on committed code, each leg proven on disk, each restore proven by
hash.
1. **Reservation pin** (`aa3112430a`). `scripts/ablation-replace.mjs`
(WRAP) replaced the adapter's `dataEngine.insert(objectName, row)` with
an insert that drops `id` (an adapter that mints its own key): anchor 1
to 0, replacement 0 to 1, blob `5ed0db896088` to `cbd1309c37a7`. The
test reaches the adapter through relative `src` imports, so no build
sits between. Result: `Tests 2 failed | 1 passed (3)`: "the engine kept
the forced primary key: expected '3hj6lgd1y2K1GdHC' to be 'RhMSgVct...'"
and "expected true to be false" (the replay won); the control stayed
green. Restore: blob `5ed0db896088` equals HEAD, `git diff HEAD` empty,
`git status --porcelain` empty.
2. **Session-read-failure pin** (`aa3112430a`). The behaviour is the
vendor's, so the mutation is in the installed `better-auth` 1.7.12
`dist/plugins/custom-session/index.mjs`: the 1.7.7 `.catch(...)` put
back around the inner session read. That file is a hard link into the
shared pnpm store, so the link was broken first (inode `4096254` to
`1565215`, 1 link) and the store copy was never written. On disk: anchor
1 to 0, injected 0 to 1, sha256 `b2e60e53...` to `25e2b179...`. Result:
`Tests 2 failed | 2 passed (4)`: over HTTP "expected 401 to be 500" with
body `UNAUTHENTICATED` "Sign in first"; in process "promise resolved
null instead of rejecting"; both controls green. Restore under a trap:
sha256 back to `b2e60e53...`, and the store inode still hashes
`b2e60e53...`.
## Tests
- plugin-auth, full suite on the lift alone (`75aaf74a1d`): `Test Files
1 failed | 176 passed (177)`, `Tests 1 failed | 3375 passed | 10
skipped`. The one red was the route ledger (`rotate-keys`), fixed by
`9ffd7eb619`.
- New pins: `session-read-failure-answer.test.ts` `Tests 4 passed (4)`;
`verification-reservation-single-use.test.ts` `Tests 3 passed (3)`.
- **Final head `89b9affe00`** (this branch with `origin/main`
`2e242bb0a9` merged in; every reading below was taken after that merge):
- plugin-auth `vitest run`: `Test Files 179 passed (179)`, `Tests 3383
passed | 10 skipped (3393)`.
- plugin-auth `typecheck`: exit 0, with `check:test-typecheck: OK` and
the debt ledger unchanged (88 errors, 23 pinned signatures).
- `pnpm check:vendor-export-contract`: `VERDICT: PASS`, 3 edges. `pnpm
check:override-consistency`: all 9 published-manifest declarations
resolve to their override targets.
- `node scripts/check-vendor-version-stamps.mjs`: exit 1, red only on
the two out-of-surface sites above.
- `node scripts/pm/dispatch-gates.mjs --commands`, every family run and
reconciled with `--ran`: 86 derived, 86 run, 0 NOT-MEASURED, every exit
0. On the first run, at `becfb99a89`, `check:dual-build-cjs-loads`
exited 3 (no full build yet); after the dogfood closure build it was
measured green.
- **Full dogfood battery** (`pnpm --filter @objectstack/dogfood test`,
no shard, no path, under the lock, after `pnpm --filter
'@objectstack/dogfood^...' build`): `Test Files 286 passed | 3 skipped
(289)`, `Tests 2387 passed | 18 skipped (2405)`, lock verdict
command-exit 0. The auth suites run in it.
- CI check-runs: CI owns them; they had not finished when this PR was
opened.
## Acceptance notes
- **Reported, out of scope: SSO domain verification cannot succeed with
the record plugin-auth tells the operator to publish.** `POST
/api/v1/auth/admin/sso/request-domain-verification` answers
`dnsRecordValue` as `_better-auth-token-PROVIDER=TOKEN`.
`@better-auth/sso`'s `/sso/verify-domain` accepts a TXT record equal to
`IDENTIFIER=VALUE`, building `IDENTIFIER` from the verification row it
read, or equal to the bare `VALUE`. On this store
`sys_verification.identifier` is `internal` and the read hands
better-auth `undefined` there, so it expects `undefined=TOKEN`. Probe,
vendor door, DNS answered by a double: the record as instructed answers
`502 DOMAIN_VERIFICATION_FAILED`; the bare token answers `204`. Same
vendor code on 1.7.3. Not changed here. The report asks the seat to file
it.
- **Reported, out of scope: the Magic Link mail states a lifetime the
link does not have.** `sendMagicLink` passes `expiresInMinutes: 10` to
`auth.magic_link`, whose copy says "This link expires in 10 minutes";
`magicLink()` is mounted without `expiresIn`, so better-auth stores the
row with a 300-second lifetime (probe: `lifetimeSec: 300`). Unchanged by
the lift.
- Pre-existing, loud, unchanged: a host `secondaryStorage` together with
the embedded OAuth provider (on by default with the MCP surface) makes
the auth instance throw at build ("OAuth Provider requires
`session.storeSessionInDatabase: true` when using secondaryStorage"), on
1.7.3 and 1.7.12 alike. The existing `secondaryStorage` suites set
`oidcProvider: false`.
- Not measured: better-auth/better-auth#11626 /
better-auth/better-auth#11646 say a password reset consumes its token,
revokes sessions and writes the password in one transaction.
plugin-auth's adapter opens a real transaction only inside a SCIM
request and runs other flows sequentially (`objectql-adapter.ts`, the
#3653 scoping note), so on this platform those three writes are
sequential, in the vendor's order: consume, revoke, write. A refusal
before the write (bad token, password length, unknown user) no longer
spends the token.
- Accidental push, repaired: the throwaway probe file rode one commit
for about a minute. I removed it by amending and a `--force-with-lease`
push pinned to that commit, with all five AGENTS.md §3 conditions
holding (a `claude/issue-*` branch this worktree created, one author, no
PR yet, the lease on the sha I last pushed). It holds no secret.
## Patch round 1 (seat rulings `6315255713`, claim amendment
`6315268175`)
- **`packages/spec/src/identity/organization.zod.ts`**: the `updatedAt`
TSDoc keeps its 1.7.3 reading and appends the re-measurement:
"(re-measured on 1.7.12 for #25096: the organization plugin schema is
byte-identical and `transformOutput` still projects declared fields
only)". Nothing else in `packages/spec` moves. `pnpm --filter
@objectstack/spec check:generated` after a fresh spec build: all 14
generated artifacts up to date.
- **`packages/cli/src/commands/migrate/account-issuer.ts`**: the
`description` now reads "...is ONE account under the (provider_id,
account_id) key better-auth restored...", with no version, so a later
lift cannot falsify it. No test pins the sentence. cli `unit` layer:
`Test Files 321 passed (321)`, `Tests 4746 passed (4746)`; cli
`typecheck` exit 0.
- **Changeset**: `@objectstack/spec` and `@objectstack/cli` ride as
`patch`, text only and not breaking. plugin-auth stays the BREAKING
`minor`, and the DPoP `htu` FROM / TO still names both halves (ruling
Q2).
- With this round, the two out-of-surface stamp reds named under
**Attestations** are resolved: `node
scripts/check-vendor-version-stamps.mjs` exits 0
(`check:vendor-version-stamps: OK — 10187 file(s) scanned`).
- `origin/main` was merged at `ba244f1b48` before the edits (merge
`28476848b5`). Final head: `8c4bf6489b`.
- **Final head readings**: `pnpm check:vendor-export-contract` PASS (3
edges); `pnpm check:override-consistency` (9 declarations resolve to
their targets); plugin-auth `Test Files 180 passed (180)`, `Tests 3422
passed | 10 skipped (3432)`, `typecheck` exit 0; `dispatch-gates.mjs
--commands` 108 derived, 108 run, 0 NOT-MEASURED, every exit 0
(`--ran`); full dogfood battery (no shard, no path) `Test Files 286
passed | 3 skipped (289)`, `Tests 2387 passed | 18 skipped (2405)`, lock
verdict command-exit 0.
## Patch rounds 2 and 3: the Test Core 4/6 red (job `119207996576`) and
its fix
- **The failing test**:
`packages/services/service-datasource/src/__tests__/sqlite-driver-fallback-file-open-failure.test.ts`,
"an addon that was never built (no code) steps down to wasm SQLite",
`Error: Cannot find module 'bindings'`. It reproduced at `8c4bf6489b`
(`Tests 1 failed | 929 passed (930)`) and was green on `origin/main`
`ae58b26f9c` (`Tests 930 passed (930)`).
- **Root cause**: the fixture required `bindings` relative to
`better-sqlite3` 13.0.3, which does not depend on it: its only
dependency is `node-addon-api`, and it loads its addon with a plain
`require`. On `main`, `bindings@1.5.0` existed only under
`better-sqlite3@12.11.1`, the optional peer copy auto-installed for
better-auth 1.7.3, and the test reached it through pnpm's hidden hoist.
1.7.12 dropped that peer (see **Lockfile: what moved**), so the phantom
left. The producer was never affected: `resolveSqliteDriver` classifies
by error code, not message.
- **Fix (round 3, seat ruling A1, claim amendment `6316873193`)**:
`realNotBuiltFailure()` now produces better-sqlite3 13's own never-built
error: a `require()` of `build/Release/better_sqlite3.node`, made from
the installed package, against a module root that was never built, which
Node answers `MODULE_NOT_FOUND`. No phantom dependency. The case is
renamed "an addon that was never built (MODULE_NOT_FOUND) steps down to
wasm SQLite" and asserts that code, still driving the producer with a
real load error. The two `sqlite-driver-fallback.ts` docblock sentences
that named `bindings`' "Could not locate the bindings file" now describe
the 13.x error; no code moved. `@objectstack/service-datasource` rides
the changeset as `patch`, text only (the docblock ships in
`dist/index.d.ts`).
- **Ablation** (on `c428137808`, `scripts/ablation-replace.mjs` WRAP,
relative `src` import, no build between). A first leg at
`isSqliteFileOpenFailure` was a no-op for this case: the classifier sees
the driver's `DATABASE_ERROR` wrapper, not the load error's code.
Re-anchored at the step-down decision (`if
(isSqliteFileOpenFailure(err)) throw err;` also re-throwing on a
`MODULE_NOT_FOUND` code or cause): `Tests 1 failed | 8 passed (9)`, the
renamed case red and the `ERR_DLOPEN_FAILED` case green. Restore: blob
`cd3fd64524ff` equals HEAD and `git diff HEAD` is empty.
- **Final head `1a28ccb438`** (`origin/main` `ae58b26f9c` merged, merge
`9dcf97cae7`): service-datasource `Test Files 53 passed (53)`, `Tests
930 passed (930)`; plugin-auth `Test Files 180 passed (180)`, `Tests
3422 passed | 10 skipped (3432)`, `typecheck` exit 0;
`check-vendor-version-stamps` OK; `check:vendor-export-contract` PASS;
`check:override-consistency` green; `dispatch-gates.mjs --commands` 108
derived, 108 run, 0 NOT-MEASURED, every exit 0; full dogfood battery
`Test Files 286 passed | 3 skipped (289)`, `Tests 2387 passed | 18
skipped (2405)`.
- **Level (seat ruling A, `6317990662`, under the maintainer's ruling A
on #25105)**: this lift changes nothing a metadata author can write, so
it declares `Metadata-protocol: none` and ships
`@objectstack/plugin-auth` as a BREAKING-bannered `patch`, with its
ADR-0087 disposition kept.
- **Patch round 4 (ruling A, `6317990662`)**: `ea86e48563` regrades
`@objectstack/plugin-auth` from `minor` to `patch` under the
maintainer's ruling A (a non-protocol breaking change ships `patch` and
keeps its BREAKING banner and ADR-0087 disposition) and adds
`Metadata-protocol: none` under the changeset's `Clause-②` line; spec,
cli and service-datasource stay `patch`, and nothing outside
`.changeset/` moved. With origin/main's scripts against this body:
`check-changeset-no-major.mjs` exit 0 (level axis: `none` at `patch`)
and `check-adr-0087-registration.mjs` exit 0;
`check-vendor-version-stamps.mjs` exit 0 on the head.
---
_Generated by [Claude
Code](https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 386f60f commit 03966ce
24 files changed
Lines changed: 552 additions & 434 deletions
File tree
- .changeset
- packages
- cli/src/commands/migrate
- plugins/plugin-auth
- src
- services/service-datasource/src
- __tests__
- spec/src/identity
| 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 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
| 71 | + | |
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
| 45 | + | |
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
| 14 | + | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
65 | 66 | | |
66 | 67 | | |
67 | 68 | | |
68 | | - | |
69 | | - | |
| 69 | + | |
| 70 | + | |
70 | 71 | | |
71 | 72 | | |
72 | 73 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
867 | 867 | | |
868 | 868 | | |
869 | 869 | | |
870 | | - | |
871 | | - | |
| 870 | + | |
| 871 | + | |
872 | 872 | | |
873 | 873 | | |
874 | 874 | | |
| |||
1003 | 1003 | | |
1004 | 1004 | | |
1005 | 1005 | | |
1006 | | - | |
1007 | | - | |
| 1006 | + | |
| 1007 | + | |
1008 | 1008 | | |
1009 | 1009 | | |
1010 | 1010 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1799 | 1799 | | |
1800 | 1800 | | |
1801 | 1801 | | |
1802 | | - | |
1803 | | - | |
| 1802 | + | |
| 1803 | + | |
| 1804 | + | |
1804 | 1805 | | |
1805 | 1806 | | |
1806 | 1807 | | |
| |||
2058 | 2059 | | |
2059 | 2060 | | |
2060 | 2061 | | |
2061 | | - | |
2062 | | - | |
| 2062 | + | |
| 2063 | + | |
2063 | 2064 | | |
2064 | 2065 | | |
2065 | 2066 | | |
| |||
2081 | 2082 | | |
2082 | 2083 | | |
2083 | 2084 | | |
2084 | | - | |
| 2085 | + | |
| 2086 | + | |
2085 | 2087 | | |
2086 | 2088 | | |
2087 | 2089 | | |
| |||
4723 | 4725 | | |
4724 | 4726 | | |
4725 | 4727 | | |
4726 | | - | |
4727 | | - | |
| 4728 | + | |
| 4729 | + | |
4728 | 4730 | | |
4729 | 4731 | | |
4730 | 4732 | | |
| |||
9698 | 9700 | | |
9699 | 9701 | | |
9700 | 9702 | | |
9701 | | - | |
| 9703 | + | |
| 9704 | + | |
9702 | 9705 | | |
9703 | 9706 | | |
9704 | 9707 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
382 | 382 | | |
383 | 383 | | |
384 | 384 | | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
385 | 392 | | |
386 | 393 | | |
387 | 394 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
953 | 953 | | |
954 | 954 | | |
955 | 955 | | |
956 | | - | |
957 | | - | |
| 956 | + | |
| 957 | + | |
958 | 958 | | |
959 | 959 | | |
960 | 960 | | |
961 | | - | |
| 961 | + | |
962 | 962 | | |
963 | 963 | | |
964 | 964 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
| 45 | + | |
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| |||
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
66 | | - | |
| 66 | + | |
| 67 | + | |
67 | 68 | | |
68 | 69 | | |
69 | 70 | | |
| |||
0 commit comments