7.8 KiB
Trace Analysis: Builder/Reviewer Approval Gate Failures
Date: 2026-10-10 Analyzed:
20261009T143045Z(11,261 chars) +20261010T143005Z(18,721 chars) trace reports Scope: 24+ blocked builder/reviewer sessions, 20+ finding files, 100+ evidence instances Status: Diagnosis complete, fix pending Tony's approval
1. Root Cause
The builder and reviewer profiles run headless (-q / --oneshot mode) with approvals.mode unset (defaults to manual). Every terminal or execute_code call that matches a "dangerous pattern" triggers an approval prompt. In headless mode there is no user to approve, so the command is denied by timeout (default 60s) and the agent receives a BLOCKED result.
The builder profile's config.yaml currently has:
approvals:
destructive_slash_confirm: false
But no mode key, so the default manual mode applies. The destructive_slash_confirm flag only controls the / slash-command confirmation, not the terminal approval gate.
Why the agent's workaround also fails
When a terminal call is BLOCKED, the agent (correctly) falls back to execute_code to accomplish the same work. But the execute_code tool is also gated — it runs Python in a subprocess, which is flagged as a dangerous pattern (python -e / script execution). So the fallback gets blocked too. This creates the repeated pattern:
BLOCKED: terminal (dangerous pattern) → retry with execute_code → BLOCKED: execute_code (approval)
This is the single largest source of the 24+ blocked sessions and ~120 BLOCKED: occurrences across 24+ sessions.
The dangerous patterns being triggered
From the trace evidence, the specific patterns matching:
| Pattern | Why it matches |
|---|---|
bash -c / sh -c |
Builder runs bash -c 'cd /path && python script.py' for inline scripts |
python -e / python -c |
Agent uses execute_code which runs python -c '<code>' |
rm -r / recursive delete |
Builder cleans up temp files, old workspaces, test artifacts |
rm ... / (root path) |
Cleanup touches /tmp/ or /mnt/c/Users/... paths |
kill -9 / pkill |
Process cleanup for stuck background processes |
> /etc/ or >> /etc/ |
Config file writes (rare, 1-2 occurrences) |
Secondary issues (from trace reports)
-
write_file pagination paradox (10 occurrences):
write_filerefuses to overwrite without a priorread_file. The builder writes to files it created in the same session but hasn't read back. This is a tool-protocol issue, not an approval issue. -
Terminal timeout 180s: The builder's
terminal.timeout: 180is too low for long-running test suites or large file operations. The reviewer has no explicit timeout (defaults to 300s). -
Tool loop guardrail not configured: Both profiles have
tool_loop_guardrails: warnings_enabled: true, hard_stop_enabled: falsewith emptywarn_after/hard_stop_after. The trace shows 22 tool-loop warnings (30+ identical failures) that never escalate to a hard stop, so the agent keeps retrying the same blocked command. -
No model fallback for builder: The trace shows the builder's model (DeepSeek via OpenRouter) hit
502 upstream_service_erroredon 2026-10-09. The fallback tocustom:brother-5090/Qwen3.6-27B-MTP-pi-reasoning-Q4_K_Mworked, but the session already had accumulated context that made recovery slow.
2. Recommended Fix
Fix A: Set approval mode to smart for builder/reviewer (PRIMARY)
In builder/config.yaml and reviewer/config.yaml:
approvals:
mode: smart
timeout: 60
destructive_slash_confirm: false
Why smart and not off:
smartuses an auxiliary LLM to assess risk. Low-risk commands (running Python scripts, reading files,rm -rf /tmp/...) are auto-approved. Genuinely dangerous commands (rm -rf /, fork bombs, block device writes) are auto-denied. Uncertain cases escalate to a manual prompt.offdisables ALL approval checks. The docs explicitly warn: "Use only in trusted environments (CI/CD, containers, etc.)" and it still respects the hardline blocklist.- The builder/reviewer work on Tony's local machine with real projects.
smartgives the right balance: it unblocks the 95% of commands that are actually safe (running tests, cleaning temp files, reading code) while still catching anything genuinely catastrophic.
If Tony wants zero prompts: mode: off is the alternative. The hardline blocklist still protects against rm -rf /, fork bombs, mkfs, etc.
Fix B: Configure tool loop guardrails (SECONDARY)
In both builder/config.yaml and reviewer/config.yaml:
tool_loop_guardrails:
warnings_enabled: true
hard_stop_enabled: true
warn_after: 3
hard_stop_after: 5
Why: The traces show agents hitting the same BLOCKED command 10-30 times before giving up. With hard_stop_after: 5, the agent is forced to change strategy after 5 identical failures instead of burning context tokens on retries.
Fix C: Increase terminal timeout for builder (TERTIARY)
terminal:
timeout: 300
Why: The builder runs test suites, builds, and large file operations. 180s is too aggressive — the trace shows [Command timed out after 180s] findings. 300s matches the reviewer's effective timeout.
Fix D: Add command_allowlist for known-safe patterns (OPTIONAL)
If Tony wants to skip even the smart LLM assessment for the most common patterns:
command_allowlist:
- rm
- python
- bash
- sh
- pkill
- kill
Why: These patterns are the most common triggers. Adding them to the allowlist means they're silently approved without even consulting the smart-mode LLM. Risk: this is broader than ideal — rm and bash allowlisted means any rm or bash command passes. The smart mode in Fix A already handles this more precisely. Only use Fix D if Fix A still shows blocking.
3. What This Does NOT Fix
- write_file pagination paradox: This is a tool-protocol issue. The builder needs to
read_filebeforewrite_fileon files it created. This is a prompt/skill issue, not a config issue. The fix is in the builder's system prompt or a skill that teaches the read-before-write pattern. - Model 502 errors: The fallback worked. If this becomes frequent, consider adding a second fallback or pinning to a local model for reliability.
- The kanban launch pattern: The builder/reviewer are launched via
work kanban task t_XXX. If the kanban launcher passes--yoloor setsHERMES_YOLO_MODE=1in the environment, that would also solve the approval issue without config changes. But this requires modifying the launcher, which is a code change, not a config change.
4. Application Steps
- Back up both config files before editing
- Edit
builder/config.yaml: addmode: smartunderapprovals:, addtool_loop_guardrailsblock, changeterminal.timeout: 300 - Edit
reviewer/config.yaml: same changes - Restart any running builder/reviewer sessions (or wait for next kanban dispatch)
- Verify on next trace-review run:
BLOCKED:count should drop from ~120 to near 0
5. Risk Assessment
| Change | Risk | Mitigation |
|---|---|---|
approvals.mode: smart |
Low — LLM assesses risk, auto-denies genuinely dangerous | Hardline blocklist still active as floor |
approvals.mode: off |
Medium — all prompts disabled | Hardline blocklist still active; use only if smart still blocks |
tool_loop_guardrails.hard_stop_after: 5 |
Low — forces strategy change after 5 retries | Agent may give up too early on legitimately slow operations |
terminal.timeout: 300 |
Low — longer wait | Commands that hang will take longer to detect |
command_allowlist (optional) |
Medium — broad patterns | Only apply if smart mode still blocks; start with specific patterns |