# Phase 6: HTTP routing, auth groups and rate limiting - Discussion Log > **Audit trail only.** Do not use as input to planning, research, or execution agents. > Decisions are captured in CONTEXT.md — this log preserves the alternatives considered. **Date:** 2026-09-19 **Phase:** 6-HTTP routing, auth groups and rate limiting **Areas discussed:** Bucket scope & limiter, Token guard depth, Outbound fetch guard, Route surface & OAuth exempt --- ## Bucket scope & limiter ### Which buckets does Phase 6 define and test? | Option | Description | Selected | |--------|-------------|----------| | Fonoteka 5 + mechanism | Five fonoteka named buckets plus inline throttle form; other plugins' buckets land with those plugins; roadmap "seven" corrected | ✓ | | All 11 now | Every named bucket of every ported plugin declared in Phase 6 | | | Fonoteka 5 + user 3 | Add the user stub's three buckets now | | ### Wire behavior | Option | Description | Selected | |--------|-------------|----------| | Exact Laravel parity | Fixed window, X-RateLimit-* headers, Retry-After/Reset on 429, same 429 body | ✓ | | Same limits, Go-native algorithm | Token bucket/sliding window, same headers, edge bursts may differ | | | You decide | Researcher picks cheapest faithful option | | ### Counter store | Option | Description | Selected | |--------|-------------|----------| | In-process, stdlib | Mutex map + sweep behind surf.Limiter, Store interface for later | ✓ | | In-process via otter (cooler) | Adds otter and the cooler package now | | | Postgres-backed | Survives restarts, DB write per limited request | | ### Client IP | Option | Description | Selected | |--------|-------------|----------| | Trusted-proxy config | XFF honored only from trusted CIDRs, rightmost untrusted hop | ✓ | | RemoteAddr only | Ignore forwarding headers | | | Always trust X-Forwarded-For | Spoofable if directly reachable | | **Notes:** Scouting found five named buckets in fonoteka/routes.php, not seven; eight more live in user, feedback, websockets and journal plugins. --- ## Token guard depth ### How real is the personal-token guard? | Option | Description | Selected | |--------|-------------|----------| | Real verifier, test-only minting | ApiToken lookup with PHP rules; tokens inserted by tests/seed hooks; Phase 7 adds CRUD | ✓ | | Interface + fake guard | Real lookup waits for AUTH-03 | | ### Where does inv.scope land? | Option | Description | Selected | |--------|-------------|----------| | Phase 6, in golem15.fonoteka | It is the token group's auth step; exact 401/403 bodies; parameterized names in surf | ✓ | | Phase 7 with AUTH-03 | Guard-only auth in Phase 6 | | ### Guard registry shape | Option | Description | Selected | |--------|-------------|----------| | Named guards in bouncer | Registry by name, Guard interface, single user accessor plus credential accessor, fail boot on duplicates | ✓ | | Just named middleware | Convention only | | | You decide | Planner picks | | ### OAuth bearer guard slot | Option | Description | Selected | |--------|-------------|----------| | Name reserved, no implementation | Registry proven with two real guards | ✓ | | Stub that always 401s | Mount /oauth/mcp behind a rejecting guard | | --- ## Outbound fetch guard ### Host policy | Option | Description | Selected | |--------|-------------|----------| | Per-caller policy, both modes | AllowHosts and/or PublicOnly; private-IP block always on | ✓ | | Allow-list only | Manual cover URL would need an allow-list (behavior change) | | ### DNS rebinding | Option | Description | Selected | |--------|-------------|----------| | Dial-time IP check | net.Dialer Control validates the connected IP | ✓ | | Match PHP: pre-resolve only | Keep the gap, note the risk | | ### Scope | Option | Description | Selected | |--------|-------------|----------| | Framework helper + tests only | Fetcher ports are Phase 12/14 | ✓ | | Helper + both fonoteka fetchers | Port ManualCoverUrlFetcher and CoverImporter now | | ### Limits source | Option | Description | Selected | |--------|-------------|----------| | Caller passes them; no framework default-open | Zero value fails construction | | | Framework defaults in config | http.fetch.* defaults, overridable per call | ✓ | **Notes:** User chose framework config defaults over the recommended caller-required values. Recorded with the constraint that an effective limit can never be unlimited. --- ## Route surface & OAuth exempt ### Route surface | Option | Description | Selected | |--------|-------------|----------| | Groups + proving routes only | All groups as builders; only real handlers mounted; genres under both prefixes; no 501 shells | ✓ | | All 154 as 501 shells | Whole surface registered now | | | Shells for auth-sensitive routes only | Public, token and OAuth groups fully registered | | ### OAuth exemption | Option | Description | Selected | |--------|-------------|----------| | Group flag + boot-time inspection | Raw group refuses house middleware, bare 500 on recover, route table + route:list | ✓ | | Separate mux mounted beside the pipeline | Own ServeMux and minimal chain | | | You decide | Planner picks | | ### Response conventions | Option | Description | Selected | |--------|-------------|----------| | Framework helpers + types, no envelope middleware | JSON writer, Carbon time, nullable bool, never-nil slice | ✓ | | Helpers live in fonoteka.go | Framework stays neutral | | ### CORS and body limits | Option | Description | Selected | |--------|-------------|----------| | Path-scoped CORS from config, exact parity | Reproduce cors.php, no CORS on /_fonoteka/api; body limits from real deployment values | ✓ | | CORS on everything | Header difference on the JWT group | | --- ## Claude's Discretion Package homes and names, sweep interval and Store shape, inline throttle key composition (must match Laravel), swag/openapi-typescript workflow and drift check, locale stage depth, how group mutual exclusivity is asserted, plan count and split. ## Deferred Ideas User/feedback/websockets buckets with their plugins; shared limiter store after v1; cooler/otter cache when needed; cover fetcher ports in Phase 12/14; OAuth guard and handlers in Phase 8; token CRUD in Phase 7.