Rate Limit Design Contract

Contract ID: CONTRACT-RATE-LIMIT-001 Status: APPROVED Effective Date: 2025-12-07 Owners: Platform Reliability Guild, Gateway Guild

Overview

This contract defines the rate-limiting design for Stella Ops API endpoints: how requests are tiered, keyed, throttled, observed, and surfaced to clients so that resources stay fairly allocated, abuse is contained, and client behaviour is consistent across services.

Audience: Gateway and service engineers implementing or tuning rate limits, SDK authors building client-side retry/backoff, and operators sizing tenant quotas.

Design contract. This document is the agreed target design. The Policy Engine already enforces a per-host token-bucket limiter (see Policy Studio API Contract, error code ERR_POL_007); the tiered-quota, exemption, and SDK surfaces below are the design the Gateway converges toward. Verify the live limiter configuration against the Router gateway before depending on a specific tier value.

Rate Limiting Strategy

Tiered Rate Limits

TierRequests/MinuteRequests/HourBurst LimitTypical Use Case
Free601,00010Evaluation, small projects
Standard30010,00050Production workloads
Enterprise1,00050,000200Large-scale deployments
UnlimitedNo limitNo limitNo limitInternal services, exempt clients

Per-Endpoint Rate Limits

Some endpoints have additional rate limits based on resource intensity:

Endpoint CategoryRate LimitRationale
/api/risk/simulation/*30/minCPU-intensive simulation
/api/risk/simulation/studio/*10/minFull breakdown analysis
/system/airgap/seal5/hourCritical state change
/policy/decisions100/minLightweight evaluation
/api/policy/packs/*/bundle10/minBundle compilation
Export endpoints20/minI/O-intensive operations

Implementation

Algorithm

Use Token Bucket algorithm with the following configuration:

rate_limit:
  algorithm: token_bucket
  bucket_size: ${BURST_LIMIT}
  refill_rate: ${REQUESTS_PER_MINUTE} / 60
  refill_interval: 1s

Rate Limit Headers

All responses include standard rate limit headers:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295
X-RateLimit-Reset: 1701936000
X-RateLimit-Policy: standard
Retry-After: 30

Rate Limit Response

When rate limit is exceeded, return:

HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 30

{
  "type": "https://stellaops.org/problems/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded your rate limit of 300 requests per minute.",
  "instance": "/api/risk/simulation",
  "limit": 300,
  "remaining": 0,
  "reset": 1701936000,
  "retryAfter": 30
}

Rate Limit Keys

Primary Key: Tenant ID + Client ID

rate_limit_key = "${tenant_id}:${client_id}"

Fallback Keys

  1. Authenticated: tenant:${tenant_id}:user:${user_id}
  2. API Key: apikey:${api_key_hash}
  3. Anonymous: ip:${client_ip}

Exemptions

Exempt Endpoints

The following endpoints are exempt from rate limiting:

Exempt Clients

Quota Management

Tenant Quota Tracking

quota:
  tracking:
    storage: redis  # Valkey (Redis-compatible)
    key_prefix: "stellaops:quota:"
    ttl: 3600  # 1 hour rolling window

  dimensions:
    - tenant_id
    - endpoint_category
    - time_bucket

Quota Alerts

ThresholdAction
80% consumedEmit quota.warning event
95% consumedEmit quota.critical event
100% consumedBlock requests, emit quota.exceeded event

Configuration

Gateway Configuration

# gateway/rate-limits.yaml
rateLimiting:
  enabled: true
  defaultTier: standard

  tiers:
    free:
      requestsPerMinute: 60
      requestsPerHour: 1000
      burstLimit: 10
    standard:
      requestsPerMinute: 300
      requestsPerHour: 10000
      burstLimit: 50
    enterprise:
      requestsPerMinute: 1000
      requestsPerHour: 50000
      burstLimit: 200

  endpoints:
    - pattern: "/api/risk/simulation/*"
      limit: 30
      window: 60s
    - pattern: "/api/risk/simulation/studio/*"
      limit: 10
      window: 60s
    - pattern: "/system/airgap/seal"
      limit: 5
      window: 3600s

Policy Engine Configuration

// PolicyEngineRateLimitOptions.cs
public static class PolicyEngineRateLimitOptions
{
    public const string PolicyName = "PolicyEngineRateLimit";

    public static void Configure(RateLimiterOptions options)
    {
        options.AddTokenBucketLimiter(PolicyName, opt =>
        {
            opt.TokenLimit = 50;
            opt.QueueLimit = 10;
            opt.ReplenishmentPeriod = TimeSpan.FromSeconds(10);
            opt.TokensPerPeriod = 5;
            opt.AutoReplenishment = true;
        });
    }
}

Monitoring

Metrics

MetricTypeLabels
stellaops_rate_limit_requests_totalCountertier, endpoint, status
stellaops_rate_limit_exceeded_totalCountertier, endpoint
stellaops_rate_limit_remainingGaugetenant_id, tier
stellaops_rate_limit_queue_sizeGaugeendpoint

Alerts

# prometheus/rules/rate-limiting.yaml
groups:
  - name: rate_limiting
    rules:
      - alert: HighRateLimitExceeded
        expr: rate(stellaops_rate_limit_exceeded_total[5m]) > 10
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High rate of rate limit exceeded events"

Integration with Web UI

Client SDK Configuration

// stellaops-sdk/rate-limit-handler.ts
interface RateLimitConfig {
  retryOnRateLimit: boolean;
  maxRetries: number;
  backoffMultiplier: number;
  maxBackoffSeconds: number;
}

const defaultConfig: RateLimitConfig = {
  retryOnRateLimit: true,
  maxRetries: 3,
  backoffMultiplier: 2,
  maxBackoffSeconds: 60
};

UI Rate Limit Display

The Web UI displays rate limit status in the console header with:

Changelog

DateVersionChange
2025-12-071.0.0Initial contract definition

References