docs(adr-0127): correct three measurably-false statements about the session-cache doors - #12835
Merged
os-zhuang merged 1 commit intoAug 28, 2026
Merged
Conversation
…ession-cache doors
Three statements of fact about the CURRENT plugin-auth implementation were
false against main. No ADR decision moves — D7's ruling is byte-identical.
1. Consequences said the `secondaryStorage` door is "boot-refused and pinned".
ObjectStack authors no such refusal; secondary-storage.ts:47-49 says the
opposite in terms. The default composition's boot throw is better-auth 1.7's,
conditional on the OIDC provider being on by default, and evaporates under
`plugins: { oidcProvider: false }`.
The likely origin of the error is named rather than silently fixed: the real
boot throw at secondary-storage.ts:87-89 is a `rateLimit.storage` requirement,
not a refusal of the session-cache door.
2. D7's closing sentence said `cookieCache` reaches the same architecture "with
the same result". Direction is right, magnitude is not: the session of record
stays in sys_session, the window is bounded at cookieCache.maxAge (300s), and
sensitive operations already bypass it. Corrected without overcorrecting into
"harmless".
3. Consequences said the `cookieCache` door is "unguarded (measured: zero
occurrences repo-wide)". Both halves are now false — PR #12735 landed a cost
note and an observation pin.
Every corrected claim cites the file+line it rests on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0194kbQJxUvv2yvsGRtuXpP5
os-zhuang
approved these changes
Aug 28, 2026
os-zhuang
marked this pull request as ready for review
August 28, 2026 08:02
os-zhuang
deleted the
claude/issue-12734-adr-0127-door-posture-corrections
branch
August 28, 2026 08:03
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #12734
⛔ Draft only —
docs/adr/**is governed surface. The maintainer's merge IS the review record. Not to be flipped ready, enqueued, or auto-merged, including by the dispatching seat.Three statements of fact about the current
plugin-authimplementation were false againstmain. ⭐ No ADR decision moves — see "D7 is byte-identical" below, which is asserted mechanically rather than promised.All measurements re-taken on the post-merge tree (
origin/mainatf75a38afa, after PR #12735), not from the card body — the card's own numbers predate that merge.Statement 1 —
:148"boot-refused and pinned"Old:
Why it is false: ObjectStack authors no such refusal, and the shipped module now says so in terms.
Evidence —
packages/plugins/plugin-auth/src/secondary-storage.ts:47-49:There is a boot throw in the default composition — but it is better-auth 1.7's, and it is conditional.
packages/plugins/plugin-auth/src/session-of-record.test.ts:528pins it and attributes it: better-auth hard-refusessecondaryStoragewithoutsession.storeSessionInDatabase, reachable only because the OIDC provider is on by default.session-of-record.test.ts:410reaches the cache-backed session store by passingplugins: { oidcProvider: false }and changing nothing else — so the throw is not a guard this repo owns.⭐ The likely origin of the error, written into the correction rather than fixed silently
packages/plugins/plugin-auth/src/secondary-storage.ts:87-89documents a real boot throw:That throw is real, and it contains the words "secondary storage" — but it is a rate-limit configuration requirement, not a refusal of the session-cache door. The correction names both throws and says which is which, so the next reader cannot re-derive the same wrong generalisation from the same evidence.
Statement 2 —
:113"with the same result"Old:
Why it is wrong: the direction is right; the magnitude is not. ⛔ Deliberately not overcorrected into "harmless" — the new text keeps the failure direction and ends "Smaller is not harmless — a bounded window in which a revoked session still authenticates is a tolerance D4 never granted, so D7's ruling covers this door too."
Evidence —
packages/plugins/plugin-auth/src/auth-manager.ts:1403-1421, the measured table PR #12735 landed. Each of its three claims was re-verified first-hand in this branch against the installed better-auth 1.7.1 (read out ofnode_modules, not off the^1.7.1range):better-auth/dist/cookies/index.mjs:50createCookie("session_data", { maxAge: options.session?.cookieCache?.maxAge || 300 })better-auth/dist/cookies/index.mjs:99symmetricEncodeJWT(..., options.maxAge || 300)databaseis configuredbetter-auth/dist/context/create-context.mjs:149-165if (isStateful && refreshCache) { logger.warn(...); return false; }better-auth/dist/api/routes/session.mjs:277-280getAuthoritativeSessionFromCtx:if (!isStateful(ctx)) return getSessionFromCtx(ctx); ... getSessionFromCtx(ctx, { disableCookieCache: true })Statement 3 —
:148"unguarded (measured: zero occurrences repo-wide)"Old:
Why both halves are false: this one did not exist when the card was written — PR #12735 created it.
"zero occurrences repo-wide" — re-measured.⚠️ Counted as lines, and every matched line was read before publishing the number (docblocks quote code, so a raw count is not a fact about occurrences):
23 matched lines across 5 files —
auth-manager.ts(6),session-of-record.test.ts(7),secondary-storage.ts(2),.changeset/plugin-auth-cookiecache-cost-disclosure.md(6), and ADR-0127 itself (2). Not zero."unconfigured rather than protected" — also false. The door now carries a measured cost note (
auth-manager.ts:1382-1438) and an end-of-chain observation pin (session-of-record.test.ts:479).session-of-record.test.ts:484-486is explicit that the pin is an observation, not a refusal, so the new text says "tripwire, not a rejection". It also records the sharper truth the old sentence inverted:cookieCacheis not reachable through ObjectStack config at all, by construction rather than refusal —AuthConfigSchema.session(packages/spec/src/system/auth-config.zod.ts) declaresexpiresIn/updateAgeonly.⭐ Net effect: the asymmetry in the old paragraph was backwards. It presented
secondaryStorageas the guarded door andcookieCacheas the open one. The measured truth is that neither is guarded, and the reachable, unbounded one issecondaryStorage.D7 is byte-identical — asserted, not promised
The card's fence is that no ADR decision may move. Checked mechanically rather than by eye:
The whole-file diff also contains no removed decision or ruling line — every difference in the decision/ruling extraction is an addition in Consequences. And the document's ruling marker count is unchanged (6 before, 6 after), so the two new Consequences bullets introduce no new ruling: the summary sentence deliberately starts "That is the ruled posture…" rather than carrying the arrow this document reserves for rulings.
An amendment line was added in the header, following the established convention in this directory (ADR-0059:7, ADR-0045:3):
**Amended 2026-08-28 (#12734), measurements only — no decision changes**.Verification
Gate union re-derived live on the actual changed set, not taken from the dispatch brief:
check:governed-proseand "the docs-audit families"; the derivation namedcheck:pm-governed-mergesand no docs-audit family. Both of the brief's families were run anyway — green — and are reported below marked as extras.All 7 run at commit
ad8b5a186on a clean tree, exit codes captured before any pipe, each quoted from the gate's own verdict line:check:adr-anchorscheck-adr-anchors: OK (52 anchored file(s), every governing ADR still referenced; 125 decision number(s) ...; 29690 citation(s) across 3748 file(s) resolve)check:doc-authoring✓ doc authoring guard: 391 files clean — no bare metadata literals.--filter @objectstack/lint check:doc-formula-expressions✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 424 files / 1453 TS blocks judged cleancheck:pm-governed-merges✓ check-governed-merges --self-test: 206 assertions ... live: the real generator declared 9 output(s) and certified this treescripts/check-adr-links.mjs✅ check-adr-links: 564 relative link destination(s) under docs/adr/ resolvecheck:pm-governed-prose(extra)✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces ... and claim no others.check:docs-audit-scope(extra)✓ docs-accuracy-audit scope is in sync with content/docs/: 189 hand-written doc(s).check:doc-formula-expressionsfirst returnedPREREQUISITE NOT METtwice (@objectstack/formula, then@objectstack/lintnot built). That is NOT MEASURED, neither pass nor fail — recorded rather than counted as green. Both prerequisites were built and the gate re-run to a real exit 0.Positive control — the gates actually read the edited paragraph
A green gate on a prose edit proves nothing unless the gate is shown to read the changed text. Mutation planted in the new paragraph, restore via an
EXIT INT TERMtrap on an absolute path:9549067a…→d3997abb…A decision record is only binding if the next reader can reach it.9549067acb623fcfce9dfd1a168498a078255cb5=HEADblob,git diff HEADemptyOther
check:nul-bytesexit 0 —check-nul-bytes: OK (scanned 7138 text file(s) ... no raw ASCII control bytes); plus a direct control-byte scan of the edited file, no matches.docs/adr/**alone, publishes nothing. The derivation's own line — "write one unless this card is docs-only".skip-changesetapplied accordingly.packages/specwas read for theAuthConfigSchema.sessioncitation and not edited. The diff is one file.Generated by Claude Code
Generated by Claude Code