Public: anyone can read this; the crew can change it.

One ration at the door, and a 429 that tells the truth: src/ration.ts in src/server.ts #49

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The write door in `src/server.ts` now spends `take(key, now, PERSON_WRITES)` from `src/ration.ts`; `allow()`, `RATE` and `buckets` are deleted from `src/http.ts`. The key shape (`user:<id>`, `ip:<address>`) and the numbers (burst 20, 2/s) are untouched, so no policy changed — only who computes it, and now the answer includes the wait.

shipped production is serving it deploy 460b31c

opened this

The write door in src/server.ts now spends take(key, now, PERSON_WRITES) from src/ration.ts; allow(), RATE and buckets are deleted from src/http.ts. The key shape (user:<id>, ip:<address>) and the numbers (burst 20, 2/s) are untouched, so no policy changed — only who computes it, and now the answer includes the wait.

A refusal carries retry-after in whole seconds, rounded up from retryAfterMs with 1 as the floor on the wire. POST /api/* and POST /mcp answer {"error":"too_many_requests","message":…,"retry_after_ms":<exact>}; every other door keeps its plain-text sentence. Both carry the security floor — json() and text() in src/http.ts grew an optional headers argument, the way html() already had one.

Worth a look: serve takes an optional now() so src/server.test.ts can prove the wiring on a clock it controls — the 21st write in a burst is 429 with retry-after: 1, a request at retry_after_ms - 1 is still refused, and one at exactly retry_after_ms succeeds. Against a real server, a refusal 231ms from its token reports retry_after_ms: 231 and retry-after: 1.

One correction to the issue's survey: src/ration.test.ts also imported allow(), in the parity test written against the old door. That test now asserts PERSON_WRITES and the twenty-then-two behaviour directly — the test was right about the numbers and only wrong about where they live. APP_EVENTS is untouched and left entirely to #8, as is the app half of the swap. bun test: 82 pass.

🤖 Generated with Claude Code

Closes #40

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs