feat(rate_limit): Stage 1c — remaining/reset_at/limit fields and to_response_headers (Spec 6)

Summary

Implements Spec 6 (#28785) — adds rate limit state to Labkit::RateLimit::Result for RFC-compliant response headers.

  • Extends Result with three optional fields: remaining, reset_at, limit (all nil-defaulted; no existing callers broken)
  • Result#to_response_headers — emits RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset; returns {} when unmatched or errored
  • Evaluator#compute_reset_at — one redis.ttl call after incr; TTL ≥ 0 uses it directly, TTL < 0 falls back to rule period; no logging in success path
  • No per-request logging — MR !273 (merged) constraint preserved; TTL errors propagate to the existing StandardError rescue → log_error
  • FakeRedis#ttl — fixed to return -1 as default (matching real Redis for keys without expiry)

Test plan

  • bundle exec rspec spec/labkit/rate_limit/result_spec.rb spec/labkit/rate_limit/evaluator_spec.rb spec/labkit/rate_limit_spec.rb --format documentation — 80 examples, 0 failures
  • bundle exec rubocop lib/labkit/rate_limit/result.rb lib/labkit/rate_limit/evaluator.rb — no offenses

Closes #28785

🤖 Generated with Claude Code

Merge request reports

Loading
Loading