A host-declared mutating capability (mutationClass mutating_shell) now reaches the UNGUARDED_MUTATION decision. Previously the registry computed the class (Bash to cls=mutating_shell guarded=true) but ToolCallDescriptor had no field for it (types.ts:215-223), so decideUnguardedMutation never saw it and raw Bash mutations slipped through: kubectl apply, terraform apply, helm upgrade, rm -rf, gh pr merge, curl to a deploy webhook all scored SKIPPED with executed=true — even with an explicit mutationClass:mutating_shell declaration. The fix routes the already-computed class to the decision (types.ts additive mutationClass, tool-registry stamps the binder result, unguarded-mutation isDeclaredMutatingClass prefix-tests mutating, guard.ts isMutatingCall||declaredMutating). All six mutations now block, executionAttempted=false. NOT a command classifier: no line reads the command string — a string test loses to sh -c/alias/wrapper/base64 while looking like it wins; a source test asserts guard.ts/unguarded-mutation.ts contain no kubectl/terraform/helm/command pattern. ls -la under a mutating_shell descriptor also blocks — correct, not collateral: a raw shell is undecidable, and reading it as a read would be the guess an attacker writes ls -la; kubectl apply around. The safe architecture is capability-narrowing (remove raw shell from the guarded host); the opt-out is CODERIFTS_ADVISORY=1, loud. 1203/1203.