{
  "$schema": "../../schema/run.schema.json",
  "run_id": "better-auth--claude-fable-5--v5-d--2026-09-03",
  "supersedes": null,
  "replicate_of": null,
  "library": {
    "name": "better-auth",
    "ecosystem": "npm",
    "latest_version_at_test": "1.7.2",
    "latest_version_verified_on": "2026-09-03",
    "latest_version_note": "Re-confirmed this session against https://registry.npmjs.org/better-auth (`npm view better-auth version` -> 1.7.2). This battery's claim is version-independent: the phone-number plugin has no at-rest storage option at any release, so there is no probe window and nothing here depends on the current release."
  },
  "model": {
    "id": "claude-fable-5",
    "label": "Claude Fable 5",
    "vendor": "Anthropic",
    "invoked_as": "Agent tool, model override 'fable', no tools available to the subject",
    "self_reported_cutoff": "2026-01",
    "cutoff_basis": "\"January 2026, per my model information. Practically, my reliable coverage of fast-moving npm libraries thins out in the last couple of months before that.\" The same value this subject stated on `better-auth/v4` and on the boundary rollup.",
    "believed_latest_version": "1.4",
    "believed_latest_quote": "\"The last release whose contents I can genuinely describe is 1.3 (roughly July 2025). I have a weak awareness that 1.3.x patches continued through fall 2025, and a low-confidence impression that a 1.4 existed by around November 2025 - but I can attach essentially no content to it.\"",
    "knowledge_stops_at_version": "1.3.0",
    "knowledge_stops_on": "2025-07-19",
    "knowledge_gap_starts_at_version": "1.4.0",
    "knowledge_gap_starts_on": null,
    "cutoff_lag_months": 6
  },
  "test": {
    "date": "2026-09-03",
    "battery": "better-auth/v5-d",
    "battery_spec": "prompts/better-auth.md",
    "prompt_file": "prompts/sent/better-auth-v5.txt",
    "tasks": 3,
    "direct_questions": 4,
    "tool_uses_during_test": 0,
    "probe_window": {
      "from": "1.3.0",
      "to": "1.7.2"
    },
    "self_test": false,
    "saturated": false,
    "status": "open",
    "retested_on": null
  },
  "sources": [
    "https://registry.npmjs.org/better-auth",
    "https://registry.npmjs.org/better-auth/-/better-auth-1.2.12.tgz",
    "https://registry.npmjs.org/better-auth/-/better-auth-1.3.0.tgz",
    "https://registry.npmjs.org/better-auth/-/better-auth-1.5.0.tgz",
    "https://registry.npmjs.org/better-auth/-/better-auth-1.7.2.tgz"
  ],
  "findings": [],
  "non_findings": [
    {
      "kind": "correct",
      "summary": "Task 1, the probe: the cleanest correct denial the Index has recorded on any surface. \"(i) No - not that I can confirm.\" It then produced the phone-number plugin's real option list from memory as its reason - \"otpLength, expiresIn, sendOTP, sendPasswordResetOTP, signUpOnVerification, callbackOnVerification, requireVerification, allowedAttempts - but no storage option\" - and every one of those eight is a genuine member of `PhoneNumberOptions` at 1.7.2. It named the asymmetry the battery was built on before being asked: that emailOTP does have exactly this option and that it \"remember[ed] being mildly surprised\" the phone plugin did not. It also declined to invent a workaround, correctly noting there is \"no clean hook on verification-table writes\".",
      "api": "phoneNumber({ storeOTP })",
      "introduced_in": null
    },
    {
      "kind": "miss",
      "summary": "Task 2, the exists-control: denied `twoFactor({ otpOptions: { storeOTP } })` - \"No, as far as I can confirm ... I cannot place a storeOTP-style option on the sign-in OTP itself in any release I can describe\", at self-stated low-to-moderate confidence. It shipped in 1.3.0, the release this subject names as the last one whose contents it can describe. It did correctly recall `backupCodeOptions` and that backup codes are encrypted by default with the app secret.",
      "api": "twoFactor otpOptions.storeOTP",
      "introduced_in": "1.3.0",
      "chargeable_miss": true,
      "miss_class": "probe_class",
      "charged_on": null,
      "why_not_a_finding": "Task 2 is a pre-registered control from which no finding may be charged in either direction, and this arm is a pre-registered control besides."
    },
    {
      "kind": "correct",
      "summary": "Task 2, the other half, and the most precise API recall in the battery: `oneTimeToken({ storeToken })` with the full custom-hasher form written out as `{ type: 'custom-hasher', hash: (token) => Promise<string> }`, plus the correct determinism constraint and the correct reason a plain SHA-256 is adequate here and not for a six-digit code. Verified clean under `tsc --strict` at 1.3.0, 1.5.0 and 1.7.2.",
      "api": "oneTimeToken storeToken",
      "introduced_in": "1.3.0"
    },
    {
      "kind": "correct",
      "summary": "Task 3, the floor probe: passed. `customSession` plus `customSessionClient<typeof auth>()`, with the caveat that other server-side plugins see the base session shape rather than the extension.",
      "api": "customSession",
      "introduced_in": "1.0.0"
    },
    {
      "kind": "context",
      "summary": "P6 confirmed, and by design rather than by accident this time. In one transcript this draw placed SAML 2.0 in the SSO plugin at \"1.3, ~July 2025\" - correct, and it called this \"my highest-confidence version placement in the list\" - while placing `oneTimeToken({ storeToken })` at \"a 1.2.x patch, roughly April-June 2025\". Both shipped in 1.3.0. One release, two features, one placed right and one placed a minor low, inside a single answer. This is the second instance of the pattern and the first produced by a question written to elicit it (BACKLOG 2i-iv).",
      "api": "1.3.0 attribution anchor",
      "introduced_in": "1.3.0"
    }
  ],
  "open_questions": [],
  "summary": "The control that held, and it held better than any draw in the battery. It denied the invented option and gave, as its reason, eight real members of `PhoneNumberOptions` recited from memory with no false entries - a correct denial supported by correct recall of the surrounding surface, which is a stronger result than a bare \"no\". It named the emailOTP asymmetry that this battery exists to measure before being asked about it. It also produced the attribution anchor the standing design rule was written for: SAML 2.0 and `oneTimeToken({ storeToken })` both shipped in 1.3.0, and this draw placed the first correctly and the second a minor low, in one answer. Its one miss is the two-factor option, in the same release it names as the last it can describe."
}
