Problem
agentRateLimitKeyGenerator prefers req.agentTokenHash, documented as populated by agentRuntimeAuth, but no production code assigns that field. The preferred tok: branch is therefore dead.
The fallback hashes the raw credential header string. Authentication accepts the same runtime token through either Authorization or x-commonly-agent-token, so one token receives two independent limiter keys. Alternating headers doubles the intended token-global outer bound from 120/min to 240/min.
Evidence
- Production grep finds
agentTokenHash only in agentRateLimit.ts.
agentRuntimeAuth computes a local tokenHash for lookup but does not attach it to req.
- Rate-limiter ordering is mixed across routes: some limiters run before auth and some after it. Merely reviving
req.agentTokenHash would split the same token by route family instead of by header.
- The 2x result is currently derived from the key-generator code and hash arithmetic; it has not yet been reproduced with live requests.
Durable fix
Extract the credential using the same semantics as authentication, then derive the limiter key from the extracted token itself. The key must be identical:
- for both accepted headers;
- before and after auth middleware;
- across every route family using the agent limiter.
Delete the never-populated req.agentTokenHash contract rather than reviving it.
Proof required
- A focused test shows the same token in either header produces the same key.
- An alternating-header request test proves both requests consume one shared bucket.
- A route-ordering test covers limiter-before-auth and limiter-after-auth paths.
Follow-up from #781; not a merge blocker for that PR.
Problem
agentRateLimitKeyGeneratorprefersreq.agentTokenHash, documented as populated byagentRuntimeAuth, but no production code assigns that field. The preferredtok:branch is therefore dead.The fallback hashes the raw credential header string. Authentication accepts the same runtime token through either
Authorizationorx-commonly-agent-token, so one token receives two independent limiter keys. Alternating headers doubles the intended token-global outer bound from 120/min to 240/min.Evidence
agentTokenHashonly inagentRateLimit.ts.agentRuntimeAuthcomputes a localtokenHashfor lookup but does not attach it toreq.req.agentTokenHashwould split the same token by route family instead of by header.Durable fix
Extract the credential using the same semantics as authentication, then derive the limiter key from the extracted token itself. The key must be identical:
Delete the never-populated
req.agentTokenHashcontract rather than reviving it.Proof required
Follow-up from #781; not a merge blocker for that PR.