Monitor: notification stream delivers lines that do not match the filter pattern (filter acts as lower bound only)

Status Open
Reported on v2.1.226
Maintainer reply None cached
Activity 0 comments · opened Aug 9, 2026

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:

  1. Do not match any pattern in the filter
  2. Were verified to not match by multiple pattern-matching methods (alternation, case sensitivity, substring/regex equivalence)
  3. 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

  1. Does the filter operate on a derived/cached version of stdout rather than live stdout?
  2. Is there conditional logic in the filter pipeline that changes behavior based on line batching or timing?
  3. 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.

View original on GitHub ↗