{"record":{"id":"080c616f0ea7003e","repo":"Hmbown/CodeWhale","slug":"invalid-auto-review-kind-index-action-kind","errorCode":null,"errorMessage":"Invalid auto_review.{kind}[{index}].action_kind '{action_kind}': expected read, write, shell, external, publish, or destructive.","messagePattern":"Invalid auto_review\\.(.+?)\\[(.+?)\\]\\.action_kind '(.+?)': expected read, write, shell, external, publish, or destructive\\.","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/config.rs","lineNumber":3042,"sourceCode":"    for (index, rule) in rules.iter().enumerate() {\n        if rule\n            .text_contains\n            .as_deref()\n            .is_some_and(|value| !value.trim().is_empty())\n        {\n            anyhow::bail!(\n                \"Invalid auto_review.{kind}[{index}].text_contains: user-intent matching was retired; scope the rule with tool and/or action_kind.\"\n            );\n        }\n        if !rule.has_matcher() {\n            anyhow::bail!(\n                \"Invalid auto_review.{kind}[{index}]: set at least one of tool or action_kind.\"\n            );\n        }\n        if let Some(action_kind) = rule.action_kind.as_deref() {\n            let normalized = action_kind.trim().to_ascii_lowercase().replace('-', \"_\");\n            if parse_auto_review_action_kind(&normalized).is_none() {\n                anyhow::bail!(\n                    \"Invalid auto_review.{kind}[{index}].action_kind '{action_kind}': expected read, write, shell, external, publish, or destructive.\"\n                );\n            }\n            if kind == \"allow\"\n                && !matches!(\n                    normalized.as_str(),\n                    \"read\" | \"write\" | \"shell\" | \"external\" | \"publish\" | \"destructive\"\n                )\n            {\n                anyhow::bail!(\n                    \"Invalid auto_review.allow[{index}].action_kind '{action_kind}': this retired narrow kind cannot safely widen to a v0.9.8 decision class; replace it with an exact tool rule or a current action_kind.\"\n                );\n            }\n        }\n    }\n    Ok(())\n}\n","sourceCodeStart":3024,"sourceCodeEnd":3060,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/config.rs#L3024-L3060","documentation":"An auto_review rule's action_kind failed to parse after normalization (trim, lowercase, '-' to '_'): crates/tui/src/config.rs:3042 accepts exactly read, write, shell, external, publish, or destructive (plus parse_auto_review_action_kind aliases such as mcp_read for read). The invalid value is echoed in the message.","triggerScenarios":"A typo, a retired kind name (e.g. 'exec', 'net'), or a made-up class from older docs; casing and hyphens are fine ('Shell' and 'content-publish' normalize correctly).","commonSituations":"Configs migrated between versions where kind names changed; guesswork values instead of copying the enumerated list.","solutions":["Replace the value with one of: read, write, shell, external, publish, destructive","If the intent has no matching class, scope by tool = \"<tool-id>\" instead","Re-run config load to confirm"],"exampleFix":"# config.toml - before\n[[auto_review.deny]]\naction_kind = \"exec\"\n\n# config.toml - after\n[[auto_review.deny]]\naction_kind = \"shell\"\n","handlingStrategy":"validation","validationCode":"const ACTION_KINDS: [&str; 6] = [\"read\",\"write\",\"shell\",\"external\",\"publish\",\"destructive\"];\nfn valid_action_kind(k: &str) -> bool {\n    ACTION_KINDS.contains(&k.trim().to_ascii_lowercase().replace('-', \"_\").as_str())\n}","typeGuard":"fn parse_action_kind(raw: &str) -> Option<&'static str> {\n    let n = raw.trim().to_ascii_lowercase().replace('-', \"_\");\n    match n.as_str() { \"read\"|\"mcp_read\" => Some(\"read\"), \"write\" => Some(\"write\"), \"shell\" => Some(\"shell\"), \"external\" => Some(\"external\"), \"publish\" => Some(\"publish\"), \"destructive\" => Some(\"destructive\"), _ => None }\n}","tryCatchPattern":"// Validate the enum before writing config files programmatically\nlet kind = parse_action_kind(user_input).ok_or_else(|| anyhow!(\"unknown action_kind {user_input}\"))?;","preventionTips":["Copy the enumerated list from the error message, not from memory","Note casing and hyphens normalize; only the value itself must be known"],"tags":["config","auto-review","validation","enum"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}