Skip to content

fix(bridges): silence (file not found:) Discord/Telegram noise from prose-quoted markers - #987

Merged
sonichi merged 2 commits into
sonichi:mainfrom
VasiliyRad:fix/file-marker-extraction-noise
May 22, 2026
Merged

sonichi merged 2 commits into
sonichi:mainfrom
VasiliyRad:fix/file-marker-extraction-noise

Conversation

@VasiliyRad

Copy link
Copy Markdown
Contributor

The bug

An agent's reply body sometimes contains inline-code prose describing the file-marker convention itself, e.g.:

Body example like `[file: /tmp/sutando-x.png]` reached the user…

The bridge's marker regex is markdown-context-blind, extracts the substring, finds no such file at /tmp/sutando-x.png, and ships (file not found: /tmp/sutando-x.png) as a Discord/Telegram message after the agent's clean reply. Confusing user-visible noise.

Fix: minimum user-impact

Two layers considered:

  1. Make extraction markdown-aware — principled but invasive.
  2. Silence the user-facing warning for the missing-file case — real typos still surface via stderr; only the user-visible noise goes away.

This PR ships #2. Replaces four (file not found:) send sites with stderr log lines:

File Path
src/discord-bridge.py poll_results (channel replies)
src/discord-bridge.py poll_proactive (owner DMs)
src/discord-bridge.py poll_dm_fallback channel-redirect branch
src/telegram-bridge.py send_reply

Each replacement carries a comment pointing back to this bug class so the next refactor doesn't restore the warning by accident.

What's NOT silenced

(file not allowed: ...) / (file access denied: ...) — the allowlist rejection branch. That's a security signal worth surfacing to both user and operator. Test pins this contract.

Tests

tests/discord-bridge-prose-marker.test.py (3 cases) — source-grep regression guards. Invoking the async poll_* methods end-to-end would need a discord.py harness, and the fix is a local behavioral change in well-bounded branches that grep verifies precisely.

Test plan

  • python3 tests/discord-bridge-prose-marker.test.py — 3/3 pass
  • Existing tests still pass (no behavior change for _is_path_sendable, chunker, or marker extraction itself)
  • Manual: send a reply with a [file: /no-such-path] substring inside backticks — verify the bridge logs [file marker, file not found — likely a prose quotation] to stderr and ships NO follow-up message to Discord

🤖 Generated with Claude Code

## The bug

An agent's reply body sometimes contains an inline-code description
of the file-marker convention itself, e.g.:

    Body example like `[file: /tmp/sutando-x.png]` reached the user…

The bridge's `[file:|send:|attach:]` regex is markdown-context-blind:
it extracts every matching substring regardless of whether it sits
inside backticks, a fenced code block, a blockquote, or plain prose.
For prose-quoted markers, the path doesn't exist, and the
`(file not found: ...)` Discord/Telegram message lands in the user's
DM as confusing noise AFTER the agent's clean reply.

## Fix: minimum user-impact

Two layers were considered:

1. Make extraction markdown-aware. Principled but invasive (regex ->
   real parser; reaches every send path).
2. Silence the user-facing warning for the missing-file case. Real
   typos still surface to operators via stderr; only the user-
   visible Discord/Telegram noise goes away.

This PR ships sonichi#2. Replaces four `(file not found:)` send sites with
stderr log lines:

  - src/discord-bridge.py: poll_results, poll_proactive,
    poll_dm_fallback channel-redirect
  - src/telegram-bridge.py: send_reply

Each carries a comment pointing back to this bug class so the next
refactor doesn't restore the warning by accident.

## What's NOT silenced

`(file not allowed: ...)` / `(file access denied: ...)` — the
allowlist rejection branch. That's a security signal (attempted
exfil of a file outside SEND_ALLOWED_ROOTS / SEND_ALLOWED_PREFIXES)
worth surfacing to both user and operator. Test pins this contract.

## Tests

`tests/discord-bridge-prose-marker.test.py` (3 cases) — source-grep
regression guards:

  - no `.send(f"(file not found: ...)` patterns remain in discord-bridge
  - telegram-bridge specifically pinned alongside Discord (bridges
    historically drift on shared patterns)
  - `(file not allowed: ...)` still surfaces (security signal)

Source-grep is the right shape — invoking the async poll_* methods
end-to-end would need a discord.py harness, and the fix is a local
behavioral change in well-bounded branches that grep verifies
precisely.

Co-Authored-By: Vasiliy's Sutando <noreply@anthropic.com>
@CLAassistant

CLAassistant commented May 21, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@sonichi

sonichi commented May 21, 2026

Copy link
Copy Markdown
Owner

LGTM. Right call to pick the minimum-impact layer — making the marker-extraction markdown-aware would have been a bigger refactor with its own edge-case surface (nested backticks, indented blocks, escaped backticks), and the missing-file case is genuinely "agent wrote prose about a file-marker convention", not actionable user information.

Critically, the security signal ((file not allowed: ...) / (file access denied: ...)) stays surfaced to the user — that's the allowlist-rejection branch from _is_path_sendable, and silencing it would hide path-allowlist bypass attempts. The test pinning that contract is the part I'd want to see most.

Replacing the four warning-send sites with stderr lines preserves operator visibility for real typos (operator sees stderr) without polluting the user-visible reply (user doesn't). Right asymmetry.

The "comment at each replacement pointing back to this bug class" pattern is the kind of thing that prevents a future refactor from silently restoring the warning. Worth keeping intact.

@sonichi
sonichi merged commit 959216c into sonichi:main May 22, 2026
2 checks passed
liususan091219 pushed a commit to liususan091219/sutando-fork that referenced this pull request May 28, 2026
…rs (sonichi#987)

## The bug

An agent's reply body sometimes contains an inline-code description
of the file-marker convention itself, e.g.:

    Body example like `[file: /tmp/sutando-x.png]` reached the user…

The bridge's `[file:|send:|attach:]` regex is markdown-context-blind:
it extracts every matching substring regardless of whether it sits
inside backticks, a fenced code block, a blockquote, or plain prose.
For prose-quoted markers, the path doesn't exist, and the
`(file not found: ...)` Discord/Telegram message lands in the user's
DM as confusing noise AFTER the agent's clean reply.

## Fix: minimum user-impact

Two layers were considered:

1. Make extraction markdown-aware. Principled but invasive (regex ->
   real parser; reaches every send path).
2. Silence the user-facing warning for the missing-file case. Real
   typos still surface to operators via stderr; only the user-
   visible Discord/Telegram noise goes away.

This PR ships sonichi#2. Replaces four `(file not found:)` send sites with
stderr log lines:

  - src/discord-bridge.py: poll_results, poll_proactive,
    poll_dm_fallback channel-redirect
  - src/telegram-bridge.py: send_reply

Each carries a comment pointing back to this bug class so the next
refactor doesn't restore the warning by accident.

## What's NOT silenced

`(file not allowed: ...)` / `(file access denied: ...)` — the
allowlist rejection branch. That's a security signal (attempted
exfil of a file outside SEND_ALLOWED_ROOTS / SEND_ALLOWED_PREFIXES)
worth surfacing to both user and operator. Test pins this contract.

## Tests

`tests/discord-bridge-prose-marker.test.py` (3 cases) — source-grep
regression guards:

  - no `.send(f"(file not found: ...)` patterns remain in discord-bridge
  - telegram-bridge specifically pinned alongside Discord (bridges
    historically drift on shared patterns)
  - `(file not allowed: ...)` still surfaces (security signal)

Source-grep is the right shape — invoking the async poll_* methods
end-to-end would need a discord.py harness, and the fix is a local
behavioral change in well-bounded branches that grep verifies
precisely.

Co-authored-by: Vasiliy's Sutando <noreply@anthropic.com>
Co-authored-by: Chi Wang <4250911+sonichi@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants