{"record":{"id":"a767c12ae59f9a48","repo":"xai-org/x-algorithm","slug":"bdsm-challenge-salt-env-var-is-required-for-challe","errorCode":null,"errorMessage":"BDSM_CHALLENGE_SALT env var is required for challenge routing","messagePattern":"BDSM_CHALLENGE_SALT env var is required for challenge routing","errorType":"validation","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"bdsm/runtime/score_results_sink_focal.py","lineNumber":59,"sourceCode":"        def is_active(self, uid):\n            return False\n\n        def is_active_many(self, uids):\n            return set()\n\n        def mark_active(self, uid):\n            pass\n\n        def get_metrics(self):\n            return {\"enabled\": False}\n\n    _trace = _NoopTrace()\n\n\ndef _challenge_salt() -> bytes:\n    salt = os.environ.get(\"BDSM_CHALLENGE_SALT\", \"\")\n    if not salt:\n        raise RuntimeError(\"BDSM_CHALLENGE_SALT env var is required for challenge routing\")\n    return salt.encode()\n\n\nDEFAULT_BOOTSTRAP = \"localhost:9092\"\n\nHEAD_NAMES = {\n    0: \"FollowBot\",\n    1: \"LikeBot\",\n    2: \"EngagementAmplifier\",\n    3: \"ReplySpamBot\",\n    4: \"TweetSpamBot\",\n    5: \"RTBot\",\n    6: \"MultiActionBot\",\n    7: \"LegitimateUser\",\n}\n\n\ndef _resolve_head_names(_model_version):","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/bdsm/runtime/score_results_sink_focal.py#L41-L77","documentation":"Challenge routing in the focal score sink hashes labels with a salt from the BDSM_CHALLENGE_SALT environment variable. _challenge_salt raises RuntimeError when the var is unset or empty, because unsalted routing would be predictable and gameable.","triggerScenarios":"Running score_results_sink_focal (or any path reaching pick_challenge_label/_cusp_lane/_paused_head_lane/_spam_bounce_lane) in a process where BDSM_CHALLENGE_SALT is unset or empty; a dotenv file that omits it; the var lost in a container image rebuild.","commonSituations":"New deployment environment (k8s secret not mounted); local run without copying the env template; secret renamed; CI run lacking prod secrets.","solutions":["Set BDSM_CHALLENGE_SALT to the deployment's salt value (from the secret store) before starting the sink","Add it to the container spec/k8s secret so it is always mounted","Add a startup preflight assertion for required env vars to fail before any work begins","Document required env vars in the service runbook"],"exampleFix":"# before\npython -m bdsm.runtime.score_results_sink_focal ...\n# after\nexport BDSM_CHALLENGE_SALT=\"$SALT_FROM_SECRET_STORE\"\npython -m bdsm.runtime.score_results_sink_focal ...","handlingStrategy":"validation","validationCode":"import os\nassert os.environ.get('BDSM_CHALLENGE_SALT'), 'BDSM_CHALLENGE_SALT must be set'","typeGuard":null,"tryCatchPattern":"try:\n    salt = _challenge_salt()\nexcept RuntimeError:\n    salt = load_salt_from_secret_store().encode()","preventionTips":["Declare the env var in container specs/k8s secrets","Fail fast on missing env at process start, not at first challenge","Add a config preflight check to the entrypoint"],"tags":["python","environment-variable","secrets","runtime"],"backgroundTag":"missing-env-var","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}