"""生成链路的显式灰度开关。""" import os import hashlib DEFAULTS = { "DOCUMENT_IR_V1": True, "PLAN_SNAPSHOT_V1": True, "SCENARIO_ENGINE_V2": False, "OUTPUT_RECONCILIATION_V1": True, "RETENTION_CLEANUP_V1": False, } def enabled(name: str) -> bool: if name not in DEFAULTS: raise KeyError(f"unknown feature flag: {name}") value = os.getenv(f"INSURANCE_{name}") if value is None: return DEFAULTS[name] return value.strip().lower() in {"1", "true", "yes", "on"} def public_flags() -> dict[str, bool]: return {name: enabled(name) for name in DEFAULTS} def enabled_for(name: str, *, identity: str = "", profile: str = "") -> bool: """支持按 profile 白名单和稳定百分比分桶的灰度判断。""" if not enabled(name): return False profiles = { item.strip() for item in os.getenv(f"INSURANCE_{name}_PROFILES", "").split(",") if item.strip() } if profiles and profile not in profiles: return False percentage = _percentage(name) if percentage >= 100: return True if percentage <= 0 or not identity: return False bucket = int(hashlib.sha256(f"{name}:{identity}".encode("utf-8")).hexdigest()[:8], 16) % 100 return bucket < percentage def rollout_config() -> dict: return { name: { "enabled": enabled(name), "percentage": _percentage(name), "profiles": [item for item in os.getenv(f"INSURANCE_{name}_PROFILES", "").split(",") if item], } for name in DEFAULTS } def _percentage(name: str) -> int: try: return max(0, min(100, int(os.getenv(f"INSURANCE_{name}_PERCENT", "100")))) except ValueError: return 0