# Performance Budgets in dcg: How the 200ms Timeout Enforces Low Latency

> Learn about performance budgets and how Dicklesworthstone dcg enforces a 200ms timeout. Discover how this ensures low latency in command validation.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: performance
- Published: 2026-07-16

---

**The Destructive Command Guard (`dcg`) enforces a hard 200ms timeout on its PreToolUse hook to guarantee that command validation never introduces perceptible lag, failing open (allowing the command) if the deadline is exceeded.**

The `dcg` (destructive_command_guard) repository provides a synchronous safety layer that inspects shell commands before execution in AI coding agents. Because this check blocks the command from running, the project defines strict **performance budgets** that each processing stage must respect to maintain a snappy user experience. These budgets culminate in a 200ms hard deadline that ensures the tool never becomes a bottleneck in the development workflow.

## What Are Performance Budgets in dcg?

**Performance budgets** are maximum latency allocations assigned to specific stages of the command evaluation pipeline. Each budget targets a sub-millisecond or low-millisecond threshold to ensure the total processing time remains imperceptible to users.

The budgets are enforced across these key stages:

- **Quick-reject filter** (< 50 µs): Implemented in [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs), this stage uses `memchr` and `RegexSet` to eliminate over 99% of harmless commands before expensive processing begins.
- **Fast-path normalization** (< 500 µs): The [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs) module handles path stripping, alias expansion, and basic tokenization.
- **Pattern matching** (< 1 ms): Also in [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs), compiled static regexes (via `lazy_static!`) classify commands as safe or destructive.
- **Heredoc extraction** (< 2 ms): The [`src/heredoc.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/heredoc.rs) parser processes complex multi-line inputs only when necessary.
- **Full pipeline with AST matching** (< 20 ms): The [`src/ast_matcher.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/ast_matcher.rs) module provides deep analysis for edge cases, validated by the benchmark suite in [`benches/heredoc_perf.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/benches/heredoc_perf.rs) and [`benches/hook_latency.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/benches/hook_latency.rs).

## How dcg Enforces the 200ms Timeout

The **200ms deadline** represents the total time budget for the entire PreToolUse hook execution. If processing exceeds this limit, `dcg` implements a fail-open policy to prevent workflow disruption.

The enforcement mechanism follows four steps:

1. **Start timer**: As soon as `dcg` reads the JSON hook input in `src/hook.rs::run`, it records `Instant::now()`.
2. **Execute pipeline**: The command flows through quick-reject, normalization, pattern matching, optional heredoc parsing, and suggestion scoring.
3. **Check elapsed time**: Immediately before writing the final JSON denial in [`output/denial.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/output/denial.rs), the code verifies:

```rust
if start.elapsed().as_millis() > HOOK_TIMEOUT_MS {
    // Fail-open: silently allow the command
    std::process::exit(0);
}

```

4. **Emit result**: If under budget, the normal allow/deny decision outputs as JSON; otherwise, the process exits with code 0, allowing the command to run.

The constant `HOOK_TIMEOUT_MS` is defined in [`src/perf.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/perf.rs) as `const HOOK_TIMEOUT_MS: u64 = 200;`, centralizing the deadline configuration.

## Why a 200ms Fail-Open Policy?

A defensive security tool that stalls the developer's workflow would quickly be disabled. The **200ms figure** was chosen after profiling real-world workloads on Linux and Windows, sitting comfortably below the typical "thinking" latency of code-assistant UIs.

By failing open—allowing the command rather than blocking indefinitely—`dcg` balances **safety** (catching most dangerous commands quickly) with **usability** (never introducing noticeable lag). This guarantee ensures that even pathological inputs, such as deeply nested heredocs, cannot freeze the agent interface.

## Validating Performance with Benchmarks

The project maintains rigorous performance validation through dedicated benchmark suites. The [`benches/hook_latency.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/benches/hook_latency.rs) file measures end-to-end hook latency to verify the < 200ms target, while [`benches/heredoc_perf.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/benches/heredoc_perf.rs) focuses on heredoc extraction and AST matching performance.

Developers can observe the internal timer in debug builds by running with `RUST_LOG=debug` to verify budget compliance:

```rust
// In src/hook.rs (debug builds only)
log::debug!("Hook elapsed: {} ms", start.elapsed().as_millis());

```

You can also test the timeout behavior directly:

```bash

# Normal safe command (fast path)

echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' \
| cargo run --release

# A deliberately complex heredoc that approaches the budget

cat <<'EOF' > /tmp/large_script.sh
$(yes "echo hello" | head -n 50000)
EOF

echo '{"tool_name":"Bash","tool_input":{"command":"bash /tmp/large_script.sh"}}' \
| cargo run --release

# If parsing the heredoc would exceed 200ms, dcg silently allows the command.

```

## Summary

- **Performance budgets** in `dcg` allocate specific latency limits (< 50 µs to < 20 ms) to each processing stage in [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs), [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs), and [`src/heredoc.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/heredoc.rs).
- The **200ms timeout** is enforced in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs) by checking `Instant::elapsed()` against `HOOK_TIMEOUT_MS` defined in [`src/perf.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/perf.rs).
- If the deadline is exceeded, `dcg` **fails open** by exiting with code 0, ensuring user workflow never stalls.
- The benchmark suite in [`benches/hook_latency.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/benches/hook_latency.rs) validates that real-world processing stays well under the 200ms budget.

## Frequently Asked Questions

### What happens if a command takes longer than 200ms to evaluate?

If processing exceeds the 200ms limit defined in [`src/perf.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/perf.rs), `dcg` immediately exits with code 0 and empty stdout, allowing the command to run. This fail-open policy ensures that complex heredocs or edge-case inputs never block the developer's terminal.

### Why does dcg use a fail-open policy instead of blocking slow commands?

Blocking indefinitely would create a poor user experience and incentivize developers to disable the tool entirely. By failing open, `dcg` guarantees that its safety checks never introduce perceptible lag, maintaining a balance between security and workflow velocity.

### Which file defines the 200ms timeout constant?

The timeout value is defined as `const HOOK_TIMEOUT_MS: u64 = 200;` in [`src/perf.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/perf.rs). This constant is imported and checked in [`src/hook.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/hook.rs) right before the evaluation result is emitted.

### How does the quick-reject filter achieve sub-50-microsecond performance?

The filter in [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs) uses `memchr` and pre-compiled `RegexSet` patterns via `lazy_static!` to eliminate over 99% of harmless commands without invoking heavier normalization or AST parsing stages.