ALTER TABLE IF EXISTS gateway_runner_policies
  ADD COLUMN IF NOT EXISTS cache_affinity_policy jsonb NOT NULL DEFAULT '{
    "enabled": true,
    "modelTypes": ["chat", "text_generate", "responses"],
    "minSamples": 3,
    "minInputTokens": 512,
    "staleAfterSeconds": 86400,
    "maxPriorityBoost": 20,
    "emaAlpha": 0.35
  }'::jsonb;

UPDATE gateway_runner_policies
SET cache_affinity_policy = COALESCE(NULLIF(cache_affinity_policy, '{}'::jsonb), '{
      "enabled": true,
      "modelTypes": ["chat", "text_generate", "responses"],
      "minSamples": 3,
      "minInputTokens": 512,
      "staleAfterSeconds": 86400,
      "maxPriorityBoost": 20,
      "emaAlpha": 0.35
    }'::jsonb),
    metadata = COALESCE(metadata, '{}'::jsonb) || jsonb_build_object('cacheAffinityPolicy', '0055_cache_affinity_routing'),
    updated_at = now();

CREATE TABLE IF NOT EXISTS gateway_cache_affinity_stats (
  client_id text NOT NULL,
  cache_affinity_key text NOT NULL,
  platform_id uuid REFERENCES integration_platforms(id) ON DELETE SET NULL,
  platform_model_id uuid REFERENCES platform_models(id) ON DELETE SET NULL,
  model_type text NOT NULL,
  request_count bigint NOT NULL DEFAULT 0,
  input_tokens bigint NOT NULL DEFAULT 0,
  cached_input_tokens bigint NOT NULL DEFAULT 0,
  ema_hit_ratio numeric NOT NULL DEFAULT 0,
  last_hit_ratio numeric NOT NULL DEFAULT 0,
  last_observed_at timestamptz NOT NULL DEFAULT now(),
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY (client_id, cache_affinity_key)
);

CREATE INDEX IF NOT EXISTS idx_gateway_cache_affinity_key_observed
  ON gateway_cache_affinity_stats(cache_affinity_key, last_observed_at DESC);

CREATE INDEX IF NOT EXISTS idx_gateway_cache_affinity_platform_model
  ON gateway_cache_affinity_stats(platform_model_id, cache_affinity_key);
