# How to Debug Why a Command Is Being Incorrectly Blocked or Allowed in Destructive Command Guard

> Debug incorrect command blocks or allows in Destructive Command Guard with the dcg explain command. Get a detailed decision trace to pinpoint blocking triggers.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: how-to-guide
- Published: 2026-07-22

---

**Use the `dcg explain` command to generate a detailed decision trace that reveals exactly which evaluation stage triggered the block, including pattern matches, allowlist lookups, and normalization steps.**

Destructive Command Guard (`dcg`) evaluates shell commands through a deterministic Rust pipeline before execution. When the tool incorrectly blocks a safe command or allows a destructive one, tracing the evaluation logic in the `Dicklesworthstone/destructive_command_guard` repository lets you identify whether the issue stems from aggressive regex patterns, allowlist misconfigurations, or wrapper binary normalization.

## Understanding the Evaluation Pipeline

`dcg` processes every command through six distinct stages defined in [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs). Understanding these stages is essential for debugging unexpected decisions.

### Stage 1: Quick-Reject Filter

The pipeline first applies fast substring checks using `memchr` and `aho-corasick` algorithms to discard obviously safe commands. If your command contains common safe signatures, it bypasses expensive regex operations entirely. Check the **quick-reject outcome** in your debug trace to see if this short-circuit logic triggered unexpectedly.

### Stage 2: Normalization

The engine strips wrapper binaries and expands aliases in [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs). Paths like `/usr/bin/git` or `git-bash` are removed, and the transformation is recorded for debugging. If your command was modified before evaluation, the normalized form appears in the trace output.

### Stage 3: Allowlist Lookup

`dcg` checks three hierarchical TOML files: [`.dcg/allowlist.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg/allowlist.toml) (project), `~/.config/dcg/allowlist.toml` (user), and [`/etc/dcg/allowlist.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/allowlist.toml) (system). If a rule ID matches in [`src/allowlist.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/allowlist.rs), evaluation stops immediately and the command is allowed regardless of destructive potential.

### Stage 4: Pattern Matching

The core engine compiles patterns once using `fancy-regex` and returns a `MatchInfo` struct containing the rule ID, severity, confidence score, and byte span. **Safe patterns** (`SAFE_PATTERNS`) are checked first, followed by **destructive patterns** (`DESTRUCTIVE_PATTERNS`). The first match determines the initial decision.

### Stage 5: Heredoc and AST Analysis

For commands embedding scripts (e.g., `bash <<'EOF' … EOF`), [`src/heredoc.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/heredoc.rs) extracts the embedded language and runs AST-based matching. If parsing times out, a bounded-analysis fallback applies conservative rules that may incorrectly allow or deny complex commands.

### Stage 6: Decision Construction

Final decisions are assembled in [`src/trace.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/trace.rs) as an `ExplainTrace` struct. If destructive patterns matched, the tool emits a denial JSON; otherwise, the command proceeds silently.

## Generating a Debug Trace with `dcg explain`

The most direct method to debug why a command is being incorrectly blocked or allowed is the built-in explain sub-command:

```bash
dcg explain "git reset --hard HEAD~5"

```

This outputs a human-readable tree showing:

- **Original and normalized command** – reveals stripped wrappers
- **Quick-reject outcome** – indicates if fast-filtering applied
- **Pattern matches** – displays rule IDs (e.g., `core.git:reset-hard`), regex snippets, severity levels, and confidence scores
- **Allow-once code** – provides the short code for `dcg allow-once` if the command was denied

For programmatic analysis, use the JSON format:

```bash
dcg explain "rm -rf ./tmp/*" --format json

```

The JSON output includes the `decision` field (`allow` or `deny`), the `matched_span` byte positions, and the full `ExplainTrace` serialization defined in [`src/trace.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/trace.rs).

## Common Causes of Incorrect Blocking or Allowing

### Safe Commands Being Denied

A safe command typically triggers a denial when it matches a destructive pattern before the safe whitelist evaluation. For example, `git clean -f` matches `core.filesystem:rm-rf-general` because the regex engine evaluates destructive patterns after safe patterns but may catch substrings incorrectly. Run `dcg explain` and examine the first matching rule ID to confirm.

### Destructive Commands Being Allowed

If a destructive command passes through, verify three potential causes in this order:

1. **Explicit allowlist entry** – Check [`.dcg/allowlist.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg/allowlist.toml) for the rule ID
2. **Quick-reject bypass** – Inspect whether a wrapper path in [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs) allowed the command to skip pattern matching
3. **Low-confidence fallback** – Review the `heredoc` section for bounded-analysis timeouts that default to permissive behavior

### Low Confidence Matches

When `dcg` cannot reliably parse mixed-language heredocs, the confidence score drops below 1.0. The [`src/heredoc.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/heredoc.rs) bounded-analysis fallback may conservatively allow dangerous commands if configured for safety-over-blocking, or deny safe ones if configured for strictness.

### Unfamiliar Rule IDs Triggering Blocks

New pattern packs (e.g., `cloud.aws`, `kubernetes.kubectl`) may overlap with existing safe patterns. Use `dcg explain_pattern <rule-id>` to view the full regex and description for any unfamiliar rule that appears in your trace.

## Step-by-Step Debugging Workflow

Follow this sequence when a command behaves unexpectedly:

1. **Capture the trace** – Run `dcg explain "<command>"` with the exact string, including quotes and escapes
2. **Verify normalization** – Check if [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs) altered the command by comparing `command` and `normalized` fields in the trace
3. **Check allowlists** – Search [`.dcg/allowlist.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg/allowlist.toml), `~/.config/dcg/allowlist.toml`, and [`/etc/dcg/allowlist.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/allowlist.toml) for the matching rule ID
4. **Analyze pattern logic** – If `core.filesystem:rm-rf-general` or similar matched, examine whether the regex is too aggressive for your use case
5. **Apply fixes** – Add the rule to your project allowlist with `dcg allowlist add <rule-id> --project`, or use `dcg allow-once <code>` for temporary bypass

## Code Examples for Debugging

### Getting Full JSON Explain Output

```bash
dcg explain "rm -rf ./tmp/*" --format json

```

Sample structured output:

```json
{
  "command": "rm -rf ./tmp/*",
  "normalized": "rm -rf ./tmp/*",
  "quick_reject": false,
  "matches": [
    {
      "rule_id": "core.filesystem:rm-rf-general",
      "severity": "high",
      "confidence": 1.0,
      "matched_span": [0, 14],
      "reason": "rm -rf without explicit safe path"
    }
  ],
  "decision": "deny",
  "allow_once_code": "a1b2c3"
}

```

### Explaining Specific Rule Definitions

```bash
dcg explain_pattern core.git:reset-hard

```

This queries the pattern metadata in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) and displays the regex source, severity classification, and human-readable description.

### Adding Rules to Project Allowlists

```bash
dcg allowlist add core.git:reset-hard --project

```

This appends the rule ID to [`.dcg/allowlist.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg/allowlist.toml), causing [`src/allowlist.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/allowlist.rs) to bypass destructive checks for this repository only.

### Using Allow-Once for Temporary Bypass

```bash

# After receiving a denial with code a1b2c3:

dcg allow-once a1b2c3

# Re-run your original command; the rule is accepted for 24 hours

```

The allow-once mechanism stores the code in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs) and validates it against pending denials.

## Summary

- **Use `dcg explain`** to generate a complete decision trace showing exactly why a command is being incorrectly blocked or allowed
- **Check [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs)** if wrapper binaries or aliases are being stripped unexpectedly
- **Inspect allowlist files** ([`.dcg/allowlist.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg/allowlist.toml), `~/.config/dcg/allowlist.toml`, [`/etc/dcg/allowlist.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/allowlist.toml)) when destructive commands pass through
- **Review [`src/heredoc.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/heredoc.rs)** output for low-confidence matches on embedded scripts
- **Reference [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs)** for the core pattern matching logic using `fancy-regex` and `MatchInfo` structs

## Frequently Asked Questions

### Why does `dcg explain` show a different command than what I typed?

The normalization stage in [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs) strips wrapper binaries like `/usr/bin/git` or `sudo` and expands shell aliases before evaluation. Check the `normalized` field in your explain trace to see the exact string that underwent pattern matching.

### How do I find which allowlist file is allowing a destructive command?

Run `dcg explain "<command>"` and look for the `allowlist_match` field in the JSON output. If present, the trace indicates which of the three tiers (project, user, or system) contained the matching rule. You can then inspect the specific TOML file referenced in [`src/allowlist.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/allowlist.rs).

### What does a confidence score below 1.0 mean in the explain output?

A confidence score less than 1.0 indicates that [`src/heredoc.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/heredoc.rs) could not fully parse an embedded script using AST analysis, triggering a bounded-analysis fallback. The tool made a probabilistic decision based on partial information, which may result in incorrectly blocking or allowing complex heredoc commands.

### Can I see which regex pattern actually matched my command?

Yes. Use `dcg explain_pattern <rule-id>` (for example, `dcg explain_pattern core.filesystem:rm-rf-general`) to view the full regex definition, severity level, and description. This helps determine if the pattern is overly broad and needs adjustment in your local configuration or an upstream contribution.