-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
The context buffer used for sentinel tool-type extraction is only ~2KB (the tail of self.context_buffer). The extract_permission_context_structured() function searches this buffer for the last TOOL_CALL_RE match to determine which tool (Bash, Write, Edit, etc.) triggered the permission prompt.
TOOL_CALL_RE = re.compile(
r'(?:Bash|Read|Write|Edit|Glob|Grep|WebFetch|WebSearch|Skill|Task|NotebookEdit)'
r'\(([^)]{0,500})\)',
re.DOTALL
)The problem: Claude Code's Ink-based UI renders tool invocations with ANSI escape sequences interspersed throughout the text. A single Bash(git status) call in the raw PTY stream might look like:
\x1b[36mBash\x1b[0m\x1b[2m(\x1b[0mgit status\x1b[2m)\x1b[0m
The regex runs after ANSI stripping on the context buffer, but the buffer accumulates raw bytes. If the ANSI-stripped version of the tool call doesn't land within the last 2KB of context, sentinel gets either:
("unknown", "", ...)— which means the command bypasses sentinel entirely (not in any scope)- The wrong tool type from an earlier invocation still in the buffer
Impact
- False negatives: A
Bash(rm -rf important/)command gets classified asunknown→ bypasses sentinel scope check → auto-approved without safety evaluation - Misclassification: A
Writeoperation gets classified asBash(from a previous tool call in the buffer) → evaluated with wrong system prompt context
Reproduction
- Have Claude perform a sequence of Read operations (which produce large output — file contents rendered to terminal)
- Follow with a Bash command that triggers a permission prompt
- The Read outputs push the Bash tool call out of the 2KB context window
- Sentinel sees
unknowntool type → skips evaluation
Proposed Fix
Two complementary changes:
- Increase context buffer to 8KB or make it configurable
- Extract tool type at detection time: When the permission prompt pattern is matched, walk backward through the raw buffer looking for the most recent tool call line, rather than searching a fixed-size tail
A more robust approach would be to track tool invocations as they stream through _reader_pty() — maintaining a self.last_tool_type / self.last_tool_args that updates whenever a tool call pattern is seen, regardless of buffer position.
Affected Files
src/unleashed-c-21.py—extract_permission_context_structured()andself.context_buffermanagementsrc/sentinel_gate.py— receives the potentially-wrong tool type
Context
The context buffer was designed for the session mirror and friction logging — it was never meant to be a reliable tool-type detector. Sentinel's correctness depends on accurate tool identification because the scope routing (SENTINEL_SCOPES) uses the tool type to decide whether to evaluate at all. A Bash command misidentified as unknown gets the same treatment as a Read — instant auto-approval, no safety check. This is the quiet failure mode: sentinel is enabled, appears to be working, but silently misses commands.