Monitor: notification stream delivers lines that do not match the filter pattern (filter acts as lower bound only)
Environment
- Claude Code: 2.1.226
- OS: macOS 26.5.2 (Apple Silicon)
- Shell: zsh
Reproduction
Setup: Arm a Monitor with a highly restrictive filter pattern containing NO positive matches for a common log entry type:
pattern: "EXIT|ERROR|CONTRADICTION|Traceback"
Configure the Monitor to watch a log that produces lines matching NONE of these patterns. Example log output:
INFO progress 1254/1922 (65.2%) done=936 empty=56 err=8 contradiction=0 ...
Prove the filter arms correctly by injecting a synthetic test line into the watched log that DOES match the pattern (e.g., a line containing "EXIT"). Confirm the Monitor delivers the injected line within seconds.
Observed Behavior: After the synthetic injection proves the Monitor is armed and delivers matching lines correctly, allow normal log output to resume. Non-matching lines continue to arrive in the notification stream even though they fail all four filter patterns.
Example: The line above (INFO progress 1254...) was delivered by a Monitor whose filter contained NONE of the tokens: no "INFO", no "progress" (exact substring match failed), no "CONTRADICTION", no "Traceback", no "EXIT", no "ERROR".
Expected Behavior
Only lines matching the filter pattern should arrive in the notification stream. A filter of EXIT|ERROR|CONTRADICTION|Traceback should NOT match or deliver a line consisting of INFO progress 1254/1922....
Actual Behavior
The notification stream receives lines that:
- Do not match any pattern in the filter
- Were verified to not match by multiple pattern-matching methods (alternation, case sensitivity, substring/regex equivalence)
- Arrive under the same task-id as the armed Monitor, ruling out orphaned processes or leftover task-ids
Impact
- Documentation Contract Violation: The Monitor documentation states that the filtered notification stream should be strictly filtered stdout. In this case, it is not.
- Context Overrun Risk: When users narrow a Monitor filter to reduce notification volume (common for context efficiency), they cannot rely on that filter to exclude noise. The filter acts as a lower bound on inclusion, not an upper bound on exclusion.
- Operational Consequence: Users seeking to reduce notification volume have no working lever other than stopping the Monitor entirely. Filter narrowing does not accomplish the intended reduction.
Mechanism Notes
- No orphaned Monitor (fresh task-id, armed 90 seconds before the problematic line arrived)
- No progress arm in the filter (the filter contains only four tokens, verified)
- No remote-shell quoting issues (grep is local, not over SSH)
- No case sensitivity issues (tested with real patterns extracted from the log)
- Syncing/parity is not a factor (single-machine reproduction)
Questions for Investigation
- Does the filter operate on a derived/cached version of stdout rather than live stdout?
- Is there conditional logic in the filter pipeline that changes behavior based on line batching or timing?
- Does the filter threshold differ from the subscription/delivery implementation?
---
Note: This issue arises from testing the actual Monitor behavior through injection-based proof rather than inspecting the filter definition. The defect was discovered when the filter, despite being airtight in code, failed to exclude in practice.