Rate-limit rollout playbook
Companion to rate-limit-shadow-to-enforced.md, which handles the
actual shadow → enforced flip.
This document describes how the rate-limit subsystem ships initially
and how the 48-h soak is operated. Every release runs with
ratelimit.shadow_mode=true for the first 48 h on production; this
playbook makes that operable.
1. Ship configuration
The release pins:
| Setting | Value | Rationale |
|---|---|---|
ratelimit.enabled |
true |
Master switch on — the middleware records everything. |
ratelimit.shadow_mode |
true |
Log-only; no user is ever throttled during the soak. |
ratelimit.violation_retention_days |
30 |
Default retention window. |
The seed rows in rate_limit_groups come from
internal/ratelimit/seeds.go. Admin tier is action=allow (metered,
never denied); General and Anonymous are action=throttle (denied
when over budget, if shadow_mode=false).
During the soak, the yellow banner on
/admin/rate-limits/settings surfaces the shadow-mode state so any
operator hitting the page knows "nothing is actually being blocked".
2. Soak cadence
Fetch the following at T+0, T+24 h, T+48 h:
/admin/rate-limits— screenshot theThrottled (24 h)stat card and the 3×7 matrix. Note the action chip on every cell./admin/rate-limits/violations?action_taken=shadow— export CSV:curl -sS -H "Authorization: Bearer $ADMIN" \ "https://api.gitvetrix.com/api/v1/admin/rate-limits/violations.csv?limit=500" \ > soak-${TIMESTAMP}.csv/admin/health— capture theratelimit.enqueued/ratelimit.written/ratelimit.droppedcounters.
Archive all three snapshots together at each interval.
3. Soak report template
Compile the following as the final soak report at T+48 h.
# Rate-limit soak report — YYYY-MM-DD (T+48 h)
## Snapshots
- T+0 snapshot: _(paste link here)_
- T+24 h snapshot: _(paste link here)_
- T+48 h snapshot: _(paste link here)_
## Traffic summary
- Total `shadow_mode=true` violations recorded: **N**
- Unique users throttled: **M**
- Unique repos touched: **K**
## Top 10 throttled users
<paste from violations.csv, pivot by user_id>
## Top 10 throttled repos
<paste from violations.csv, pivot by repo_id>
## Budget safety check
For each scope, `(shadow_mode throttles over 48 h) / (expected budget
over 48 h)`. The threshold is **5×** — anything over gets a widened
seed before the shadow → enforced flip runs.
| Scope | Shadow throttles | Budget at 48 h | Ratio | Action |
|-------|------------------|----------------|-------|--------|
| api.read | | | | |
| api.write | | | | |
| api.expensive | | | | |
| git.read | | | | |
| git.write | | | | |
| registry | | | | |
| beacon | | | | |
## False-positive check
No user reports of false 429s during the soak (shadow mode cannot
actually throttle; confirm the support queue is clean).
## Recommendations
- [ ] Scope X widened from Y to Z (see link).
- [ ] OK to proceed with the shadow → enforced flip.
- [ ] (Or) Re-soak required.
4. Proceed conditions
Proceed to the shadow → enforced flip only when:
- All seven scopes' safety factor ≤ 5×.
- No support reports of false 429s.
ratelimit.droppedcounter is < 0.1 % ofratelimit.enqueued.- Redis connectivity green on
/admin/healththroughout the soak. - Any scope that exceeded the safety factor has had its seed row widened before the flip; re-soak a minimum of 24 h after widening.
Abort and re-soak if any condition fails.
5. Observability links
- Dashboard landing:
https://www.gitvetrix.com/admin/rate-limits - Violations feed:
https://www.gitvetrix.com/admin/rate-limits/violations - Live tail:
https://www.gitvetrix.com/admin/rate-limits/live - Settings page (shadow-mode banner):
https://www.gitvetrix.com/admin/rate-limits/settings - Per-user self-service:
https://www.gitvetrix.com/user/rate-limits - Per-user history:
https://www.gitvetrix.com/user/rate-limits/history