Skip to content

workflow_sink's mention parser never masks code regions — @name inside a code span wakes the agent #7660

Description

@vimergent

Split from the parser-divergence cluster (#2526, #2686). This is a different failure direction from those: they are silent non-notification, this is a silent false notification, in the same function.

Problem

resolve_mention_pubkeys in crates/buzz-relay/src/workflow_sink.rs never masks code regions. So a workflow-rendered message containing an @name inside an inline code span or a fenced block emits a real p tag, and those p tags gate ACP agent wake (event_mentions_agent, crates/buzz-acp/src/lib.rs).

Workflow text is machine-generated markdown, and agents emit code constantly — a code sample naming an agent is documentation, not an address.

This is the mirror of the CLI issue noted as item 3 of #2526. That one was fixed on the CLI side: resolve_content_mentions now strips code regions before @name extraction (crates/buzz-cli/src/commands/messages.rs:166 feeding :226). The relay path never got the equivalent, exactly as #2526 describes the TS/Rust drift pattern — one surface moves, the other does not.

Measured on pristine main

A probe test appended to the tests module in crates/buzz-relay/src/workflow_sink.rs, one member ("Robby", <pubkey>), calling resolve_mention_pubkeys directly:

let got = resolve_mention_pubkeys("see `ping @Robby` for syntax", &members);
// PROBE inline-code-span result: ["aaaa…aaaa"]   <- the code span resolved a real pubkey

The assertion got.is_empty() fails: the mention inside the backtick span wakes Robby.

Verified against crates/buzz-relay/src/workflow_sink.rs as it stands on main today: is_left_boundary is still at line 102 and the file contains zero references to strip_code_regions. git log <earlier-sha>..main -- crates/buzz-relay/src/workflow_sink.rs is empty, so #6953 ("fix(acp): wake agents from workflow messages") did not touch this file.

Note this is independent of the left-boundary widening in #2686 / #2691. Whitespace was always an opener, so `see @Robby` resolved before any boundary change and still will after one. Widening the opener set slightly extends the surface (`(@Robby)` also matches) but is not the cause.

Suggested direction

buzz-relay already depends on buzz-sdk (crates/buzz-relay/Cargo.toml), and buzz_sdk::mentions::strip_code_regions is already pub and already used on the CLI path. Calling it in resolve_mention_pubkeys before scanning is a two-line change.

One implementation note that is easy to get wrong: strip_code_regions is not length-preserving. Measured — "a code @x b" (13 chars) returns "a b" (5 chars). Any caller that maps positions back onto the original string will corrupt them.

That happens to be safe in resolve_mention_pubkeys specifically, because at and consumed are internal to the scanned copy and nothing position-derived escapes the function — it returns pubkeys ordered by first appearance, and masking does not reorder surviving prose. Worth stating explicitly in a comment so a future refactor that does surface offsets does not silently break.

A second, narrower limitation worth a test vector either way: a fence that does not begin at a line start is not masked at all. Measured — "pre ```\nblk @y\n``` post" returns "pre \nblk @y\n ", leaving the mention intact, because is_fence_start` requires the fence to follow a newline or only whitespace. Mid-line fences are unusual in prose but not in machine-rendered text.

Test vectors

Suggested cases for the workflow parser, the first three being the actual fix:

body expected
see `ping @Robby` for syntax no wake
```\nping @Robby\n``` no wake
`code` then @Robby please wake (masking must not swallow surrounding prose)
heads up @Robby (positive control) wake
alice@Robby (negative control, already passing) no wake

#2526 notes that none of the existing 69 mention tests place an emphasis character next to an @; similarly there is currently no workflow-parser test involving code at all.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions