What Claude Sonnet 5 gets wrong about better-auth — battery v2, tested 2026-09-02

Run better-auth--claude-sonnet-5--v2--2026-09-02

Summary

The below-floor control arm, and it did half its job and failed the other half informatively. Claude Sonnet 5's attribution boundary sits at better-auth 1.0.0, four minors below the 1.3.8 surface this battery tests, so it is uninformative for the hypothesis by design — and it duly could not place either SAML SSO or device authorization to any release. Its job was to prove the capability probes can fail. On task 3 they can: it denied database-less sessions like every other draw, which is charged here as an S2. On tasks 1 and 2 they did not — it named both 1.3.8 plugins from four minors below, while volunteering that it might be reconstructing deviceAuthorization from generic RFC 8628 knowledge rather than remembering better-auth. That is the control catching a weakness in the instrument, which is what a control is for.

SubjectClaude Sonnet 5 claude-sonnet-5, Anthropic
Invoked asAgent tool, model override 'sonnet', no tools available to the subject
Cutoff the model states2026-01
Newest better-auth release it could place1.0.0 · 2024-11-23 (~13 month lag)
Oldest better-auth release it could not place1.1.0 · 2024-12-20 (so this run brackets the subject’s boundary to 2024-11-23 – 2024-12-20)
In its own words"I don't actually know the latest version — for a library that ships this fast on npm, I have no way to verify 'latest' without a tool ... My honest belief is closer to a guess than a fact."
Library at test timebetter-auth 1.7.2 (npm), verified 2026-09-02
Batterybetter-auth/v2 · 5 tasks, 4 direct questions · probe window 1.0.0 to 1.4.2
Tool uses during test0 (a run with any tool use is void — we measure training knowledge, not retrieval)
Tested2026-09-02
Findings1, of which 1 chargeable

Findings

F1 · Denies that better-auth can run with zero database, offering cookieCache and Redis instead

S2silently-wrong · stateless / database-less sessions · added · changed in better-auth 1.4.0 (2025-11-22) · chargeable

1.4.0 (2025-11-22) precedes this subject's stated cutoff of 2026-01 by two months. Charged despite this subject's attribution boundary sitting far lower (1.0.0), because the fairness rule is about the release date against the stated cutoff, not about where the subject's recall happens to end.

What the model believes

"Honest caveat: I don't believe better-auth has a mode with zero database — it still needs persistent storage for the user/account tables. cookieCache avoids per-request DB reads for session checks; secondaryStorage lets you keep sessions in Redis/KV instead of your SQL database."

What it wrote
export const auth = betterAuth({
  session: { cookieCache: { enabled: true, maxAge: 5 * 60 } },
  secondaryStorage: {
    get: (key) => redis.get(key),
    set: (key, value, ttl) => redis.set(key, value, { EX: ttl }),
    delete: (key) => redis.del(key),
  },
})
What works on better-auth 1.7.2
// stateless since 1.4.0: omit BOTH `database` and `secondaryStorage`
export const auth = betterAuth({
  emailAndPassword: { enabled: true },
})
Impact

Same cost as on the other two subjects: a Redis stood up that the library has not required for session storage since 2025-11-22, or a database-less deployment target abandoned.

Scope note

Verified at both ends per fact LF1. Not verified: that the feature is unchanged between 1.4.0 and 1.7.2.

Verified against

What it got right, and near misses

Recorded so the run cannot be read as a hit list. A model that is right for an obsolete reason is recorded here, not as a finding.

KindAPINote
context THE BELOW-FLOOR CONTROL ARM, and it returned UNINFORMATIVE for the hypothesis exactly as pre-registered — this subject's attribution boundary is 1.0.0, four minors below the 1.3.8 surface under test. It failed the internal control twice over: SAML enterprise SSO was "cannot place precisely ... this is my weakest answer of the four; treat it as closer to 'I have a hunch' than 'I recall this'", and device authorization was likewise "cannot place precisely". Under the rule fixed before the run, a subject that cannot place a genuine minor has attribution too noisy to read, so H is untestable here. Recorded as designed, not as a result. (Direct questions are belief data. This arm's purpose was to check that the probes can fail at all, not to test the hypothesis.)
contextdeviceAuthorization() THE CONTROL DID NOT DO ITS JOB ON TASKS 1 AND 2, AND THAT IS THE MOST USEFUL THING IT PRODUCED. Its pre-registered role was to show that the capability probes can elicit "the library does not offer this" from a subject whose boundary is far below the feature. It did not: it named deviceAuthorization() and lastLoginMethod() with their client plugins, four minors below where they shipped, while volunteering the reason to distrust that — "I can't fully rule out that I'm pattern-matching from generic OAuth Device Authorization Grant (RFC 8628) knowledge rather than a specific memory of better-auth shipping it." So task 1 probes a guessable name and cannot separate knowing from guessing, which is the failure mode that cost langchain/v2 a whole battery. Task 2 is the sounder probe of the pair: lastLoginMethod is not an RFC name and nothing in the task suggests a library would ship it. The control succeeded in its other half — all five draws denied the task 3 capability, so the battery can elicit a denial and the charged findings are real. (A limitation of the instrument, discovered by the arm designed to look for it. It bounds how far tasks 1 and 2 can be read, on this run and on the other four.)
correctcustomSession() Task 5, the floor probe, passed: customSession() with customSessionClient<typeof auth>(), which the subject volunteered was "the one I recall with the most confidence of the five". The 1.0.0 floor is confirmed, so the low boundary recorded here is a measurement of this subject and not the battery probing beneath it. (A passed floor probe is a validity check on the run.)
correctadditional user fields in the sign-in response Task 4 passed outright, with less hedging than either Opus or Fable draw: const plan = data.user.plan off the sign-in response, glossed "additionalFields ride along on the user object ... it's just the DB row serialized". Correct since 1.4.2 (2025-11-25). Five of five draws wrote this correctly, which falsifies the second half of pre-registered prediction P3. (Correct behaviour.)
contextoidcProvider() A grading call recorded rather than buried. This draw's (c) named oidcProvider, genericOAuth and multiSession in a "~1.1 (rough guess, late 2024)" bucket, and the OIDC Provider plugin genuinely is 1.1.0 — which taken alone would move knowledge_stops_at_version up from the 1.0.0 that better-auth/v1 recorded. It is not credited, because the same answer disclaims the entire mapping: "I don't have a reliable version-by-version changelog for this library in memory ... What follows is a fuzzy, low-confidence reconstruction of eras, not a verified list ... everything past 'very early 1.x' is already in 'version number with no reliable content attached' territory for me." Under the standing rule that a self-report is graded together with behaviour, an era-sketch its author explicitly refuses to stand behind is not a correct attribution. The bracket is therefore held at 1.0.0 / 1.1.0, matching v1. (A scoring judgement, not a model failure. Recorded so a reader who would grade it differently can see exactly what was decided and why.)

Sources

Battery specification: prompts/better-auth.md in the studio repo. Every finding above also carries its own citation.