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);