From 81706420f0a40508a03d1faca3ec8e3a05007dfe Mon Sep 17 00:00:00 2001 From: Jeremy Drouillard Date: Thu, 9 Apr 2026 10:07:21 -0700 Subject: [PATCH] Update THV-0057 key format to prevent cross-type collisions Per-user per-operation Redis keys now use distinct prefixes (user-tool:, user-prompt:, user-resource:) instead of nesting under user:{userId}:tool:... to prevent key collisions when a userId contains delimiter characters like ":tool:". The operation name precedes the userId so that the variable-length userId is always the terminal key component. Matches the implementation shipped in stacklok/toolhive#4692. Co-Authored-By: Claude Opus 4.6 (1M context) --- rfcs/THV-0057-rate-limiting.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rfcs/THV-0057-rate-limiting.md b/rfcs/THV-0057-rate-limiting.md index f7fadeb..7865201 100644 --- a/rfcs/THV-0057-rate-limiting.md +++ b/rfcs/THV-0057-rate-limiting.md @@ -181,9 +181,11 @@ Per-user limits work identically — each user gets their own bucket, keyed by i - Global per-prompt: `thv:rl:{namespace}:{server}:global:prompt:{promptName}` - Global per-resource: `thv:rl:{namespace}:{server}:global:resource:{resourceName}` - Per-user: `thv:rl:{namespace}:{server}:user:{userId}` -- Per-user per-tool: `thv:rl:{namespace}:{server}:user:{userId}:tool:{toolName}` -- Per-user per-prompt: `thv:rl:{namespace}:{server}:user:{userId}:prompt:{promptName}` -- Per-user per-resource: `thv:rl:{namespace}:{server}:user:{userId}:resource:{resourceName}` +- Per-user per-tool: `thv:rl:{namespace}:{server}:user-tool:{toolName}:{userId}` +- Per-user per-prompt: `thv:rl:{namespace}:{server}:user-prompt:{promptName}:{userId}` +- Per-user per-resource: `thv:rl:{namespace}:{server}:user-resource:{resourceName}:{userId}` + +Per-user per-operation keys use distinct prefixes (`user-tool:`, `user-prompt:`, `user-resource:`) rather than nesting under `user:{userId}:tool:...` to prevent key collisions when a `userId` contains delimiter characters (e.g., `:tool:`). The operation name precedes the userId so that the variable-length userId is always the terminal component. The `{namespace}` and `{server}` components are derived from the CRD metadata at middleware initialization time, never from per-request input.