DobermanDocs
Menu

Reference Reason codes

Reason codes

Every non-PASS Doberman decision carries one or more ReasonCode values plus a human explanation. This page catalogues every member of ReasonCode in src/doberman/models.py, the module where it is actually attached to a decision, and what it means in plain language. The enum currently defines 57 codes. doberman log and doberman tune --json (see CLI reference) both surface these values directly, so matching on the name here is the stable way to script against a decision.


Code Group Raised in Meaning
normalization_failed General engine/rules/normalization.py, proxy/normalize.py The proxy's normalize() step raised, so the action falls back to a conservative high-risk placeholder and escalates to authentication instead of passing through un-normalized.
unknown_tool General (reserved, enum only) Reserved for a requested tool name absent from the downstream tool list. Defined for that purpose but not wired to a raise site in shipped code.
downstream_error General proxy/executor.py The downstream MCP tool call raised while being forwarded, so the result is denied and the failure is never exposed to the agent.
objective_guardrail_error General engine/decision_engine.py, proxy/executor.py The objective guardrail, or a post-decision integrity check such as the output secret scan or artifact digest check, raised an unhandled exception, so the action fails closed to BLOCK.
subjective_guardrail_error General engine/decision_engine.py, engine/subjective.py The subjective guardrail raised an unhandled exception after the objective guardrail already passed, so the action escalates to authentication instead of silently passing.
subjective_block_clamped General engine/decision_engine.py, policy/drift.py The subjective guardrail returned BLOCK, but none of its reason codes sit on the hard-block allowlist, so the execution rule clamps that BLOCK down to AUTH and records that the clamp happened.
proxy_handler_error General proxy/executor.py An unhandled exception escaped the proxy's top-level tools/call handler, outside normalize()'s and decide()'s own error handling, so the call is denied carrying only the exception's class name, never its message.
secret_exfiltration Objective guardrail engine/rules/secrets.py, hosthooks/hookio.py, policy/modes.py, proxy/executor.py A known credential or secret pattern, or a base64/hex payload that decodes to one, appeared in an action headed to an external destination. The rule hard-blocks it in every mode.
sensitive_secret_access Objective guardrail auth/challenge.py, engine/rules/secrets.py, proxy/executor.py The action reads or targets a file recognized as holding secrets, such as .env or a private key, with no evidence it is leaving the session, so it requires authentication.
possible_high_entropy_secret Objective guardrail engine/rules/secrets.py Only the weak, purely statistical high-entropy heuristic matched: no known credential shape and no secret file, so the action requires authentication. It is a lower-confidence sibling of sensitive_secret_access, kept separate so output scanning can pass through likely-benign hashes, UUIDs, and base64 fragments instead of hard-blocking a benign read.
protected_path_blocked Objective guardrail engine/rules/commands.py, engine/rules/paths.py, policy/modes.py The target path resolves inside a location explicitly protected by policy, such as Doberman's own control-plane files, so the rule hard-blocks the action.
sensitive_path_access Objective guardrail auth/challenge.py, engine/rules/paths.py, policy/drift.py The target path matches a sensitive-but-not-protected location, so the action requires authentication before it proceeds.
destructive_command Objective guardrail engine/rules/commands.py, policy/modes.py A shell or git command matched a pattern that irreversibly destroys data or history: a recursive force-delete, a history rewrite, or piping a downloaded payload into a shell.
environment_dump_command Objective guardrail engine/rules/commands.py A shell command whose sole effect is to enumerate or print the process environment (bare env, any form of printenv, export/export -p, declare -x/typeset -x with no named variable, or a PowerShell Env: drive listing). This is a locally scoped read of a common secret carrier, so it requires authentication before it runs.
bulk_operation Objective guardrail auth/challenge.py, engine/rules/commands.py, policy/drift.py A command deletes at or above the configured bulk-operand threshold, so it requires authentication before the mass operation proceeds.
opaque_command Objective guardrail auth/challenge.py, engine/rules/commands.py A command's effect cannot be determined statically, an inline shell payload (-c ...) or a command that fails to parse safely, so it requires authentication before it runs.
unknown_external_destination Objective guardrail auth/challenge.py, egress/local.py, engine/rules/destinations.py A network destination is not on the trusted-host allowlist and cannot otherwise be classified as safe, so it requires authentication, subject to mode thresholds and any proven-broker override.
egress_requires_auth Objective guardrail engine/rules/destinations.py A shell, package-install, or git command has an external destination whose runtime route static parsing cannot prove, so it requires authentication regardless of how trusted the parsed host looks.
encoded_exfiltration Objective guardrail auth/challenge.py Reserved for a base64/hex-encoded payload that decodes to a secret pattern. It is wired into auth tiering and policy, but the shipped secrets rule currently reports such decoded hits as secret_exfiltration or possible_high_entropy_secret, so this code is not presently emitted.
tool_schema_changed Objective guardrail proxy/executor.py The tool's (name, description, inputSchema) fingerprint no longer matches the pinned one, a possible rug-pull. This is AUTH in Light/Balanced and BLOCK in Strict/Paranoid until a human re-approves the pin.
rule_error Objective guardrail engine/objective.py, engine/subjective.py An individual objective or subjective rule raised, or returned something other than a GuardrailResult, while being evaluated. That one rule's result is isolated to AUTH instead of forcing a silent PASS or an unrelated hard BLOCK.
role_blocked_target Role policy engine/rules/role_boundary.py, policy/modes.py The active agent role's boundary matcher explicitly denies this target, so the rule hard-blocks the action.
role_out_of_scope Role policy auth/challenge.py, engine/rules/role_boundary.py, policy/drift.py The action falls outside the boundaries declared for the agent's active role without being on an explicit block list, so it requires authentication (a role elevation).
policy_source_blocked Role policy engine/rules/policy_source.py, policy/modes.py The instruction's originating source is on a higher-authority policy source's block list, so the rule hard-blocks the action.
policy_source_sensitive Role policy auth/challenge.py, engine/rules/policy_source.py The instruction's originating source is classified as sensitive, but not blocked, by the policy source, so it requires authentication.
unusual_for_workflow Subjective layer engine/subjective.py, policy/drift.py The action deviates from this agent's own learned per-workflow behavioral baseline, raising the subjective verdict.
unusual_for_deployment Subjective layer engine/subjective.py, policy/drift.py The action's surprise score, computed across the universal three-axis algebra, exceeds this deployment's care threshold, raising the subjective verdict.
confidentiality_sensitive_destination Subjective layer engine/subjective.py An above-threshold action's dominant care dimension is confidentiality, and the destination itself is sensitive.
irreversible_high_blast Subjective layer engine/subjective.py An above-threshold action's dominant care dimension is irreversibility and blast radius rather than confidentiality: it would be hard to undo and would affect a lot if it went wrong.
lethal_trifecta Subjective layer engine/decision_engine.py, engine/subjective.py, subjective/revealed.py The action's algebra shows untrusted-data provenance, access to private data, and an external communication channel all at once, flooring the verdict to AUTH (BLOCK in Strict/Paranoid). It is the only subjective code allowed onto the hard-block allowlist.
unclassified_action Subjective layer engine/subjective.py, policy/drift.py The action's algebra classification is still effectively unknown by the time the subjective layer runs, so it is flagged rather than treated as benign.
pii_data_class_egress Objective guardrail engine/rules/data_classes.py The outbound payload contains checksum-valid personal or financial data: a payment card number (issuer prefix plus Luhn check), an IBAN (mod-97), or a dashed US SSN. Because the action has an external destination, every mode requires authentication. Only the class label is recorded, never the matched value.
smuggled_token_channel Token-channel defense engine/rules/token_channels.py A deterministic, near-zero-false-positive objective token-channel signature matched: tokens smuggled through an unexpected channel. It produces AUTH or BLOCK depending on severity.
anomalous_token_pattern Token-channel defense engine/detectors/token_channels.py The subjective token-channel detector found a soft, probabilistic out-of-distribution signal: homoglyph confusables, under-trained glitch fragments, NFKC-normalization smuggling, or anomalous control/private-use characters. It requires authentication.
oversized_encoded_blob Encoded-exfiltration detector engine/detectors/base64_blob.py The subjective base64-blob detector found a suspiciously large base64-looking payload in a tool argument, a common encode-and-exfiltrate shape (file or secret contents smuggled out as one blob). It checks shape and size only, never decodes, and raises only to AUTH.
multi_step_exfil Host-hook containment engine/taint_floor.py, hosthooks/hookio.py This egress action's session already carries taint from an earlier call that read a secret. Even though this call's own payload looks clean, the verdict is raised (AUTH, or BLOCK in Strict/Paranoid) as a potential cross-call exfiltration.
confirmed_exfil Host-hook containment engine/taint_floor.py, hosthooks/hookio.py An outbound value's keyed-HMAC fingerprint matches a secret read earlier in this same session, confirming a read-then-send exfiltration. The rule hard-blocks it in every mode.
turn_gate_error Turn gate engine/decision_engine.py, turngate/heuristics.py, turngate/hook.py The turn gate, either its Tier 0 signature scan or its Tier 1 heuristics, raised while evaluating a turn. It escalates to authentication (fails upward) instead of silently passing.
instruction_nullification Turn gate turngate/repeat.py, turngate/signatures.py A turn's text matched a Tier 0 pattern telling the agent to ignore, disregard, or override its previous instructions. Doberman blocks it outright if issued or found in untrusted content, and requires authentication if merely discussed in typed text.
authority_override Turn gate turngate/repeat.py, turngate/signatures.py A turn's text matched a Tier 0 authority-impersonation, jailbreak/mode-switch, or system-prompt-exfiltration pattern. Doberman blocks it outright if issued or found in untrusted content, and requires authentication if merely discussed.
secret_export Turn gate turngate/repeat.py, turngate/signatures.py A turn's text matched a Tier 0 credential, key, or token export request, for example "send me the API key." Doberman blocks it outright if issued or found in untrusted content, and requires authentication if merely discussed.
encoded_payload Turn gate turngate/repeat.py, turngate/signatures.py A turn contains a long, high-entropy base64/hex run or a punycode host, an encoded-carrier signature. Doberman blocks it in untrusted content and steps it up to authentication in typed content, since a user pasting base64 is plausibly legitimate.
indirect_injection Turn gate turngate/repeat.py, turngate/signatures.py A Tier 0 signature matched inside an untrusted, pasted or tool-fetched, content segment. Doberman treats this as indirect prompt injection and blocks it unconditionally, regardless of issue or mention framing.
embedded_instruction Turn gate turngate/heuristics.py Tier 1 heuristics detected an agent-directed imperative embedded in an untrusted content segment, escalating the turn to authentication.
persona_override Turn gate turngate/heuristics.py Tier 1 heuristics matched a persona- or role-override phrase in the turn, requiring authentication.
obfuscated_content Turn gate turngate/heuristics.py Tier 1 heuristics found obfuscated or sub-threshold encoded content that does not reach the hard encoded_payload carrier threshold, requiring authentication.
urgency_secrecy_framing Turn gate turngate/heuristics.py Tier 1 heuristics matched language that combines urgency and secrecy framing, a common social-engineering pattern, requiring authentication.
stylometric_outlier Turn gate turngate/heuristics.py The turn's writing style is an extreme statistical outlier for this session and coincides with a sensitive apparent intent, requiring authentication. Style alone never triggers this on its own.
repeat_after_block Turn gate turngate/hook.py, turngate/repeat.py An identical, same-fingerprint turn was resubmitted after being blocked. This converts the automatic block into a one-time AUTH challenge for the first repeat instead of blocking again outright.
turn_blocked_repeatedly Turn gate turngate/repeat.py A resubmitted turn's repeat challenge was already denied once, and the lockout threshold is reached. The rule hard-blocks further resubmission for a cooldown window instead of re-challenging.
egress_route_divergence Egress broker engine/rules/destinations.py A broker-observed connection for this entity, within a bounded recent window, actually went somewhere that diverges from this rule's static host-trust classification. This retroactively raises the already-computed verdict.
egress_broker_enforced Egress broker engine/rules/destinations.py A broker proven to enforce egress attests that this exact destination is allowlisted and will itself be enforced at the socket, so the rule contributes PASS instead of its usual AUTH.
egress_blocked_by_mode Egress broker engine/rules/destinations.py In Paranoid mode only, a broker proven to enforce egress attests that this exact destination is not allowlisted and will itself drop it at the socket, so the rule hard-blocks instead of its usual AUTH. This code is dormant in every other mode, and with no broker present.
anomalous_egress_velocity Egress broker engine/rules/destinations.py A bounded, in-memory per-entity velocity tracker detected a burst, volume, or fan-out anomaly across this entity's broker-observed connections in the same recent window egress_route_divergence uses. This retroactively raises the already-computed verdict.
artifact_digest_mismatch Artifact digest verification proxy/executor.py A pinned expected sha256 digest exists for a previously fetched identity, and the freshly returned tool-result content's digest disagrees with it. The result is withheld from the agent post-fetch.
correlated_trifecta Session correlator engine/correlator.py This session's recent decision history shows an untrusted-provenance ingress and a sensitive or secret read as separate earlier calls, and the current action is an external egress: a lethal trifecta assembled across calls rather than within one.
correlated_destructive_flow Session correlator engine/correlator.py This session's recent decision history shows a broad read or enumeration and a shell command as separate earlier calls, and the current action is an external egress: a possible archive-then-exfiltrate flow.

Notes#

  • Match on the enum name in automation. Values are stable strings, but the name is what the code actually branches on.
  • Evidence may be redacted before it reaches a log or a UI. Reason codes are the machine-stable half of explainability; the explanation string on a Decision is the human-readable half.
  • When you add a ReasonCode, update this table in the same PR. tests/unit/test_reason_codes_documented.py fails the build otherwise.
Doberman v0.18.3 · Apache-2.0 · Defense-in-depth, not airtight.

navigate open esc close