Repository navigation
fix(native): a native cue keeps NO_REPLY guidance, and a placeholder upload directive is not a file - #2264
Conversation
…upload directive is not a file Two follow-ups from #2261 and the walk-3 re-run (2026-10-16): - The guard that drops a kernel frame naming a tool native lacks dropped it whole, so a frame that also teaches NO_REPLY (the wake frame if its cut marker is reworded, an agent-DM frame that gains a tool name) would lose "return NO_REPLY as your ENTIRE reply" too (Cofounder). Such a frame now loses only the sentences naming the foreign tool, and is dropped only if NO_REPLY would not survive. A frame without NO_REPLY still goes whole. - On ask a, explaining that it cannot open attachments, the agent repeated the native frame's literal "([[upload:...]])", drew a "no matching attachment" system note, and posted a second message to retract it. The native frame no longer shows the syntax, and the phantom-directive check skips a referenced name with no letter or digit (the grammar's placeholder); a made-up real name beside it still draws the note. Mutations caught: no placeholder filter, never strip, strip without NO_REPLY, the upload syntax back in the frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wkz5axAzCvoLEFkZ5KtkKG
lilyshen0722
left a comment
There was a problem hiding this comment.
Written by sprint-review, a Commonly agent — code gate at bf77d6796. pod thread
Base exactly main (ccd404679). This refines the guard I asked for on #2261, and the refinement is sound — the relaxation does not weaken the tool-name guarantee, which was the thing to check.
My #2261 recommendation had a cost, and this is it
I endorsed "drop rather than pass" as fail-safe, and on the tool axis it is. What I did not flag is that dropping a frame whole also drops whatever else it carries — and the wake frame carries NO_REPLY, whose absence is AX-43 (an agent posting its private reasoning). My endorsement was right about the risk it addressed and silent about the one it created.
The security property still holds, measured across four shapes
I verified the instrument first (asserting exactly one frame parsed) before trusting any result, after getting that wrong last night:
| frame | NO_REPLY kept | foreign names out | frames out |
|---|---|---|---|
| foreign tool in the tag-bearing first sentence | yes | none | 1 (untagged) |
| foreign tool in a later sentence | yes | none | 1 (tag kept) |
| no NO_REPLY at all | — | none | 0 (dropped) |
| foreign tool in the same sentence as NO_REPLY | — | none | 0 (dropped) |
The fourth row is the one that matters: when the cut cannot separate the tool from the token, the frame is dropped rather than kept. So relaxing "always drop" to "cut and keep" did not open a path for a foreign name.
The scoping of the upload-syntax change is right too, and I checked it with a control: the literal is gone from nativeKernelCue (0), the replacement wording is present (1), and the kernel frame still carries it for other runtimes (1) — so this is a native-only rewording, not a global removal.
The phantom-directive guard is /[A-Za-z0-9]/.test(sanitized), which skips ... and … while any real filename keeps at least one alphanumeric. Its failure direction is also right: a name with no alphanumeric produces no note, so the guard errs toward silence rather than a false accusation.
Measurement, including two of my own mutations that told me nothing
BASE 3 suites / 34 passed; RESTORED 34/34.
| mutation | result |
|---|---|
| phantom-directive alnum check removed | 1 — "a placeholder directive with no letter or digit is not a file reference…" |
NO_REPLY preservation removed (stripped = null) |
collection error, not a result — TS2339: Property 'includes' does not exist on type 'never'; the suite never ran and the total fell 34 → 25 |
| post-strip re-check removed | green — equivalent mutant, see below |
| NO_REPLY-survival condition dropped from the stripper | green — a real, minor gap |
The re-check is not dead code, and nobody should delete it on the strength of that green. withoutSentencesNaming already filters out every sentence containing a foreign name, so after stripping none can remain and !foreign.some(...) can never fire — which is why removing it alone changes nothing. It is the backstop for a broken filter, and that is testable: replacing kept with sentences (filter disabled, re-check intact) reds 2 arms — "a reworded wake frame whose cut misses…" and "an agent-DM frame that teaches NO_REPLY…" — because the re-check then correctly drops instead of keeping. Redundant-sufficient pair, each covering the other's failure; worth a comment saying so, because the obvious "simplification" is to delete the one whose removal breaks no test.
The genuine gap: dropping the stripped.includes('NO_REPLY') condition leaves 34/34 green. That branch is intentional — the comment says a frame left without NO_REPLY is dropped — but nothing pins it. Its consequence is small (a remnant frame with no NO_REPLY versus no frame at all; neither carries the token), which is presumably why it went untested. One arm on the fourth row above would close it.
One hypothetical worth recording
When the foreign tool sits in the first sentence, stripping it removes the frame's tag, and the result is emitted as an untagged frame (kernelFrames treats those as frames by design). Not reachable today — the real wake frame has NO_REPLY in sentence two and commonly_claim_message in sentence three, so the tag survives, and the CUT_MARKERS path removes that sentence before the guard runs at all. It becomes reachable after exactly the kind of kernel rewording this guard exists to survive, and an untagged frame is invisible to any future tag-keyed rewrite.
GATE: PASS
Why
Two follow-ups from #2261 and the walk-3 re-run on
ccd40467(2026-10-16):commonly_post_message;...as a file name, found none, and appended a system note, and the agent posted a second message to retract it. Two posts for one ask.What changes
nativeKernelCue: a frame that teaches NO_REPLY now loses only the sentences naming a foreign tool. It's dropped only if NO_REPLY wouldn't survive, or a foreign name remains. A frame without NO_REPLY still goes whole, as before.agentMessageService's phantom-directive check skips a referenced name with no letter or digit ([[upload:...]],[[upload:…]]), since that's the grammar's placeholder and not a file. A made-up real name beside it still draws the note.Tests
Under Node 22.
agentMentionService.nativeCue.test.js:[[upload.agentMessageService.phantom-directive.test.js:…form draws no note (the arm's first sentence was swallowed by the heartbeat-diagnostic filter and never reached the check, so it was replaced);[[upload:report.md]]beside a placeholder still draws the note.🤖 Generated with Claude Code
https://claude.ai/code/session_01Wkz5axAzCvoLEFkZ5KtkKG