{"record":{"id":"4657c1a54b6e09f2","repo":"nextlevelbuilder/ui-ux-pro-max-skill","slug":"unknown-decision-rule-action","errorCode":null,"errorMessage":"unknown decision-rule action: {}","messagePattern":"unknown decision-rule action: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/ui-ux-pro-max/scripts/reasoning_contract.py","lineNumber":92,"sourceCode":"        raise ValueError(\"decision rules must be a JSON object\")\n    for condition, actions in rules.items():\n        if condition not in ALLOWED_CONDITIONS:\n            raise ValueError(\"unknown decision-rule condition: {}\".format(condition))\n        if not isinstance(actions, list) or not actions:\n            raise ValueError(\"{} must map to a non-empty action array\".format(condition))\n        for action in actions:\n            _validate_action(action)\n        if len(actions) != len(set(actions)):\n            raise ValueError(\"{} contains duplicate actions\".format(condition))\n    return rules\n\n\ndef _validate_action(action):\n    if not isinstance(action, str) or \":\" not in action:\n        raise ValueError(\"action must use a known prefix: {}\".format(action))\n    prefix, value = action.split(\":\", 1)\n    if prefix not in ACTION_PREFIXES:\n        raise ValueError(\"unknown decision-rule action: {}\".format(action))\n    if prefix in TOKEN_ACTION_PREFIXES and not TOKEN_RE.fullmatch(value):\n        raise ValueError(\"invalid {} action value: {}\".format(prefix, value))\n    if prefix == \"pattern\" and not value.strip():\n        raise ValueError(\"pattern action must name a pattern\")\n    if prefix == \"mode\" and value not in {\"dark\", \"light\"}:\n        raise ValueError(\"mode action must be dark or light\")\n\n\ndef apply_decision_rules(rules, query):\n    \"\"\"Return deterministic mutations and an audit trail; never execute data.\"\"\"\n    normalized = str(query or \"\").casefold()\n    result = {\"activated\": [], \"style_ids\": [], \"constraints\": [],\n              \"pattern\": None, \"mode\": None}\n    for condition, actions in rules.items():\n        active = condition == \"must_have\" or any(\n            pattern.search(normalized)\n            for pattern in CONDITION_PATTERNS.get(condition, ()))\n        if not active:","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/nextlevelbuilder/ui-ux-pro-max-skill/blob/a38d04c3d5c298c851dbe5e6ee1965ee3de42cb5/src/ui-ux-pro-max/scripts/reasoning_contract.py#L74-L110","documentation":"After splitting an action at its first ':', the prefix must be one of ACTION_PREFIXES = {constraint, style, pattern, mode} (reasoning_contract.py:46). Any other prefix — a typo like 'themes:', an invented verb like 'enable:', or a renamed prefix from a different toolkit version — raises this ValueError echoing the full action.","triggerScenarios":"_validate_action(\"themes:dark\"), _validate_action(\"font:serif\"), or _validate_action(\"enable:pattern\") — all pass the ':' check at line 90 but fail the prefix membership test at line 92.","commonSituations":"Extending the rule vocabulary without updating ACTION_PREFIXES; porting rules from another design-system tool with different action names.","solutions":["Use only the four prefixes: constraint:, style:, pattern:, mode:.","If you intended a new effect kind, add it to ACTION_PREFIXES (and TOKEN_ACTION_PREFIXES if its value is a kebab-token) in reasoning_contract.py, plus handling in apply_decision_rules and tests.","Check for stale rule payloads after upgrading the toolkit if the prefix set changed."],"exampleFix":"// before\n{\"if_luxury\": [\"themes:gold\"]}\n\n// after\n{\"if_luxury\": [\"style:luxury-gold\"]}","handlingStrategy":"validation","validationCode":"from src.ui_ux_pro_max.scripts.reasoning_contract import ACTION_PREFIXES\nbad = [a for a in all_actions if a.split(\":\", 1)[0] not in ACTION_PREFIXES]\nif bad:\n    raise ValueError(f\"actions with unknown prefix: {bad}; allowed prefixes: {sorted(ACTION_PREFIXES)}\")","typeGuard":"def has_known_prefix(action: str) -> bool:\n    return action.split(\":\", 1)[0] in {\"constraint\", \"style\", \"pattern\", \"mode\"}","tryCatchPattern":null,"preventionTips":["Derive allowed prefixes from ACTION_PREFIXES rather than a local copy, so vocabulary changes propagate.","Add contract unit tests whenever you extend ACTION_PREFIXES."],"tags":["decision-rules","closed-vocabulary","validation"],"backgroundTag":null,"analyzedSha":"a38d04c3d5c298c851dbe5e6ee1965ee3de42cb5","analyzedAt":"2026-08-14T18:51:02.321Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}