Skip to content

fix(plugin-auth): degraded rate-limit warning names the cache registration that boots - #25434

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-25329-rate-limit-cache-warning
Oct 23, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-25329-rate-limit-cache-warning

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread

Fixes #25329

Clause-②: no
Metadata-protocol: none

What changed

With no cache service registered, createLazyCounterStore (plugin-auth rate-limit-storage.ts) falls back to a per-process store and warns once. That warning told a multi-node deployment to use "Redis via @objectstack/service-cache". CacheServicePlugin.init throws when adapter: 'redis' is set ("Redis cache adapter is not yet implemented"), so an operator who followed the warning got a boot failure.

The warning now names the path that boots today, and promises no bundled adapter, so it cannot go stale when one ships:

a multi-node deployment needs a shared cache — an ICacheService backed by a store every node reaches, registered as the cache service (ctx.registerService('cache', impl)) — or each node enforces the limit independently (ADR-0069 D2)

The ADR-0069 D2 reference and the per-caller degradedImpact suffix are unchanged. This is fix option (a) of the card. Option (b), implementing the Redis adapter in service-cache, is not taken here.

Every caller of createLazyCounterStore prints this text: better-auth's rate limit, the per-number OTP send budget, the SMS quotas, and the runtime's inbound and endpoint limiters.

Files

  • packages/plugins/plugin-auth/src/rate-limit-storage.ts: the warning text.
  • packages/plugins/plugin-auth/src/rate-limit-storage.test.ts: new pin. The warning names the cache registration, does not name @objectstack/service-cache, does not say Redis, and keeps (ADR-0069 D2).
  • packages/runtime/src/security/inbound-rate-limit.test.ts: this pin quoted the old remedy (/Redis via @objectstack\/service-cache/). It is flipped to the new one plus a negative on @objectstack/service-cache.
  • packages/plugins/plugin-auth/src/otp-send-guard.ts: a doc comment that repeated the same Redis-via-service-cache claim.
  • .changeset/25329-rate-limit-cache-warning-remedy.md: @objectstack/plugin-auth patch.

Out-of-bounds files were not touched: auth-manager.ts and packages/spec. PR #25328 (docs for the same thread) is merged and edits only content/docs/api/wire-format.mdx, content/docs/deployment/production-readiness.mdx and docs/HARDENING.md, so it does not overlap.

Verification (head ff4e36d)

  • Built the closure @objectstack/runtime^... plus @objectstack/plugin-auth under the verify lock: VERDICT command-exit 0. dist/rate-limit-storage.js carries the new text, and no file in plugin-auth dist/ carries the old text.
  • pnpm --filter @objectstack/plugin-auth test: Test Files 189 passed (189), Tests 3580 passed, 10 skipped.
  • pnpm --filter @objectstack/plugin-auth typecheck: exit 0, check:test-typecheck OK.
  • pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/security/inbound-rate-limit.test.ts: 25/25 passed. Runtime reads plugin-auth through its exports, so this ran against the rebuilt dist.
  • pnpm --filter @objectstack/runtime typecheck: exit 0.
  • Ablation, one time, through scripts/ablation-replace.mjs: the src remedy was put back to "(Redis via @objectstack/service-cache)". The anchor went 1 to 0 and the blob changed. src/rate-limit-storage.test.ts went red, 1 failed / 19 passed, on the new toContain assertion. The file was then restored, blob equal to HEAD and git diff HEAD empty.

Acceptance notes

These are not filed here, because they are read-only text drift, not a reproduced defect at a public door:

  • README.md:415 lists @objectstack/service-cache as "Cache — in-memory and Redis".
  • content/docs/kernel/services-checklist.mdx:522 and :543 advertise a Redis adapter in the same package.
  • content/docs/kernel/services.mdx:130 and content/docs/kernel/cluster.mdx:720 already say that the Redis adapter is a skeleton.

🤖 Generated with Claude Code

https://claude.ai/code/session_016g7nYP9wdNx1GDa5XDr7Uy

…ation that boots

The per-process fallback warning prescribed "Redis via
@objectstack/service-cache", whose Redis adapter throws at init. It now
names the working path: a shared ICacheService registered as `cache`
(ctx.registerService('cache', impl)), and promises no bundled adapter.
ADR-0069 D2 reference and degradedImpact suffix kept. Pins flipped in
plugin-auth and runtime; otp-send-guard doc comment corrected.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016g7nYP9wdNx1GDa5XDr7Uy
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️ 1 changed file(s) yielded no anchor (packages/plugins/plugin-auth/src/otp-send-guard.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/plugins/plugin-auth/src/otp-send-guard.ts) — pages documenting those are invisible to this run
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 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.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 19 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 77392e901cce58316e803144971f2741ef049fc4 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from bac46b16f3663377813a58190d0151b9cbf46d53 — the merge of head ff4e36d9cceebd49d09077fb4c97e25c7a0092a2 into base 77392e901cce58316e803144971f2741ef049fc4, 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 bac46b16f3663377813a58190d0151b9cbf46d53 && git checkout bac46b16f3663377813a58190d0151b9cbf46d53
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 77392e901cce58316e803144971f2741ef049fc4 ff4e36d9cceebd49d09077fb4c97e25c7a0092a2 && git checkout -B drift-repro 77392e901cce58316e803144971f2741ef049fc4 && git merge --no-ff ff4e36d9cceebd49d09077fb4c97e25c7a0092a2

node scripts/docs-audit/affected-docs.mjs --json 77392e901cce58316e803144971f2741ef049fc4

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

@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tests tooling labels Oct 23, 2026
@objectstack-fleet
objectstack-fleet Bot requested a review from os-sales October 23, 2026 13:54
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · 2026-10-23T13:56Z

domain:services seat 1 (seat post #6021) · os-sales · session_016g7nYP9wdNx1GDa5XDr7Uy · card #25329, fix option (a) (S, in-seat subagent; os-dev-report on the card) · reviewed head ff4e36d9cc

  • Diff, read file by file against the claim's surface: 5 files, +27 / −4.
    • createLazyCounterStore's degraded warning (rate-limit-storage.ts) no longer prescribes "Redis via @objectstack/service-cache". On main, CacheServicePlugin.init still throws for adapter: 'redis'. The warning now names the working path: an ICacheService backed by a store every node reaches, registered as the cache service (ctx.registerService('cache', impl)).
    • The new wording promises no bundled adapter, so it cannot go stale. ADR-0069 D2 and the degradedImpact suffix stay.
    • The pins and docs that quoted the old remedy flip in the same PR: runtime/src/security/inbound-rate-limit.test.ts now asserts the new text plus a negative, the otp-send-guard.ts doc comment is updated, and a new plugin-auth pin is added.
    • The changeset is 25329-rate-limit-cache-warning-remedy.md.
    • auth-manager.ts and packages/spec are untouched. PR docs: describe the built-in inbound rate limiter, server.security.rateLimit and server.trustProxy #25328 (the docs side) has merged and does not overlap.
  • Pins (report): the ablation (old remedy restored) turns the new pin red, and the restore is byte-identical to HEAD.
    • plugin-auth: 189 files, 3580 passed and 10 skipped.
    • inbound-rate-limit.test.ts: 25/25, run against the rebuilt dist.
    • Both typechecks exit 0.
    • dispatch-gates --ran: 67 derived, 66 run, 1 unrun. The unrun one is check:dual-build-cjs-loads, which needs a full-workspace dist and is declared to CI.
  • CI on this head: 34 success and 7 expected skips, none failed. git merge-tree onto today's main is clean.
  • Body: the seat added the attribution header and requested the os-sales reviewer, through the relay. The closing footer is present.
  • Declarations: Clause-②: no, Metadata-protocol: none. Only a log line changes, so no contract-review record or dogfood battery is owed.
  • Out-of-scope finding, Acceptance notes: README.md:415 and content/docs/kernel/services-checklist.mdx:522/:543 still advertise a Redis cache adapter, while services.mdx and cluster.mdx already call it a skeleton. This is read-only doc drift with no public-door reproduction, and it is outside the three filing classes. It is left for the docs lane's next pass.
  • Commit trailers: model-free Co-authored-by: Claude + Claude-Session.
  • Landing: not governed (check-governed-merges --pr 25434: 31 lines). Ready + auto-merge through the relay. Fixes #25329 closes the card on merge.

Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rate-limit degraded warning prescribes "Redis via @objectstack/service-cache", but that adapter refuses to start

2 participants