Files
summercms/.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-07-SUMMARY.md
Jakub Zych bc43e9eabd docs(06-07): complete atomic limiter admission plan
Tasks completed: 1/1
- Make fixed-window admission atomic and inline keys server-controlled

SUMMARY: .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-07-SUMMARY.md
2026-09-20 17:10:43 +02:00

5.5 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
06-http-routing-auth-groups-and-rate-limiting 07 api-security
rate-limiting
concurrency
middleware
trusted-proxy
tdd
phase provides
06-http-routing-auth-groups-and-rate-limiting FixedWindowLimiter, MemoryStore, trusted-proxy ClientIP, named and inline throttle tests
atomic fixed-window admission under concurrent HTTP traffic
server-controlled domainless anonymous inline-throttle keys
coordinated race regressions for store and middleware Max=1 contention
phase-07-user-plugin
phase-08-oauth
public-routes
personal-token-routes
added patterns
Store.Attempt owns expiry, threshold comparison, admitted increment, and retry duration under one lock
anonymous inline throttles share inline:domainless|<trusted client IP> independently of Host and policy text
created modified
surf/limiter_store.go
surf/limiter.go
surf/limiter_test.go
surf/limiter_coverage_test.go
Replace the split Hit/TooManyAttempts/AvailableIn protocol with one atomic Store.Attempt operation
Use one inline:domainless namespace plus trusted-proxy ClientIP for every anonymous inline throttle
Rate-limit admission returns allowed, post-admission attempts, and remaining window from one store operation
Concurrency regressions coordinate 32 workers behind ready/start barriers and assert exact admissions
HTTP-04
12 min 2026-09-20

Phase 6 Plan 07: Atomic limiter admission and stable inline keys Summary

Atomic fixed-window admission now permits exactly one Max=1 contender while anonymous inline throttles share a server-controlled domainless/IP budget across Host and policy changes

Performance

  • Duration: 12 min
  • Started: 2026-09-20T14:57:45Z
  • Completed: 2026-09-20T15:10:02Z
  • Tasks: 1
  • Files modified: 4

Accomplishments

  • Replaced the raceable check-then-increment store protocol with Attempt, which performs lazy expiry, threshold comparison, admitted increment, and retry calculation within one mutex critical section.
  • Changed anonymous inline-throttle identity to inline:domainless|<ClientIP>, preventing Host rotation and inline parameter changes from creating fresh budgets while retaining per-principal u:<id> isolation.
  • Added coordinated 32-worker store and middleware regressions proving one Max=1 admission, one protected-handler invocation, and 31 exact 429 responses under the race detector.
  • Preserved first-hit-wins expiry, sweep cleanup, named-bucket stacking, headers, exact 429 body, and authenticated-user behavior.

TDD Cycle

  • RED: 5bcd7ba added the atomic Attempt contract, coordinated concurrency tests, Host-rotation regression, and cross-inline-policy regression; the targeted suite failed because MemoryStore.Attempt did not exist.
  • GREEN: 6852a8f implemented atomic admission, wired middleware to one Attempt call, established the domainless key, and adapted legacy window/sweep coverage; all targeted and package tests passed under -race.
  • REFACTOR: No separate refactor commit was needed; the GREEN implementation is the minimal store and middleware change required by the tests.

Task Commits

Each TDD gate was committed atomically:

  1. RED: Add failing atomic limiter regressions - 5bcd7ba (test)
  2. GREEN: Make limiter admission atomic - 6852a8f (fix)

Plan metadata: (this commit)

Files Created/Modified

  • surf/limiter_store.go - Defines and implements the atomic Store.Attempt admission contract.
  • surf/limiter.go - Uses one atomic admission result and domainless trusted-client inline keys.
  • surf/limiter_test.go - Covers concurrent admission, exact middleware outcomes, Host rotation, cross-policy sharing, headers, stacking, and principal isolation.
  • surf/limiter_coverage_test.go - Preserves sweep, retry-duration, and lazy-expiry coverage through the new API.

Decisions Made

  • The Store exposes only Attempt; no split check, increment, or availability operations remain available to production middleware.
  • Every anonymous inline throttle shares the router-controlled inline:domainless namespace for a client IP, while authenticated requests continue to use u:<principal id>.

Deviations from Plan

None - plan executed exactly as written.

Issues Encountered

  • The first repository-wide test run was sandbox-blocked from opening loopback listeners and reading VCS metadata in temporary build fixtures. The identical go test ./... -short command passed with the required sandbox permissions; targeted surf race tests were unaffected.

User Setup Required

None - no external service configuration required.

Next Phase Readiness

  • HTTP-04's concurrent-admission and attacker-controlled inline-key blockers are closed.
  • Plan 06-08 can proceed with the remaining SSRF transition-address gap.

Self-Check: PASSED

  • FOUND: surf/limiter_store.go, surf/limiter.go, surf/limiter_test.go, and surf/limiter_coverage_test.go
  • FOUND: RED commit 5bcd7ba and GREEN commit 6852a8f
  • PASS: targeted atomic/concurrent/inline/named limiter regressions under -race
  • PASS: go vet ./surf and complete go test ./surf -race -short
  • PASS: repository-wide go vet ./... and go test ./... -short
  • PASS: production limiter contains one Attempt(key, b.Max, b.Decay) call and no split admission path or request Host input

Phase: 06-http-routing-auth-groups-and-rate-limiting Completed: 2026-09-20