fix: make NO_REPLY suppression and sanitization explicit - #785
fix: make NO_REPLY suppression and sanitization explicit#785lilyshen0722 wants to merge 4 commits into
Conversation
Review — @sprint-review ·
|
| input | result |
|---|---|
```text\nNO_REPLY\n``` |
'' — message vanishes |
`NO_REPLY` |
`NO_REPLY` — preserved ✅ |
So a doc or review comment that illustrates the sentinel as a standalone fenced block posts as nothing. That is precisely the documentation use case this PR exists to enable — the KB entry describing this rule, if it shows the token as a fenced example, disappears.
This is a real tradeoff, not an obvious bug, which is why I'm not blocking on it. Reversing the order means a model that wraps its silent reply in a code fence would post a visible NO_REPLY into a pod — the current order is defensively correct for that case. Two acceptable resolutions:
- Keep the order, fix the comment, and add a test pinning
fenced-sentinel-only → ''as intended behavior rather than an accident. (My preference — it's the safe direction, and an untested edge is how this whole class of bug starts.) - Exempt the outer-fence case from total-match, accepting the leakage risk.
Either way the current state has a comment asserting something the code doesn't do — which is the phantom-contract shape the sprint's own checklist rule 10 names.
Two consistency items outside this PR's diff
CLAUDE.md:418still says the sentinel "will be sent verbatim." It is not verbatim — bare tokens are stripped, before and after this PR. This was flagged as an open action two rounds ago and is still open; it isn't in this diff. Now that fix: make NO_REPLY suppression and sanitization explicit #785 changes the surrounding behavior, the line is wrong in a new way and should ride whichever PR lands next.- The review-checklist draft's rule 7 records a superseded ruling. It states mutation is "stripped at the delivery layer … word-boundary" — the pre-fix: make NO_REPLY suppression and sanitization explicit #785 behavior. fix: make NO_REPLY suppression and sanitization explicit #785 changes that to bare-stripped/backtick-preserved. The checklist is landing in a different PR, so two in-flight artifacts now disagree about the same contract. Whichever lands second needs to reconcile.
What I did NOT verify
- I ran the unit suite and reproduced the main-comparison; I did not run the
clawdbot-e2eservice test in this diff, nor the full backend suite. - CI status on
47c94325not checked at review time. - The edge-case results above are from direct calls to
sanitizeAgentContent, not from a live pod post. #784's two legacy.includes(...)bridges are correctly out of scope here; I have not looked at them.
Outcome
Agent messages now use two explicit sentinel contracts:
Closes #783.
Changes
Proof
Node 20:
tsc --noEmit -p tsconfig.typescheck.json: cleanThe first code-span implementation triggered a high-severity CodeQL polynomial-regex alert on attacker-controlled message text. The shipped implementation uses delimiter pairing plus a linear scan and cleared CodeQL at the prior head; fresh checks are running for this comment/test-only follow-up.
Focused ESLint is not a useful signal for these legacy test files: it reports their pre-existing TS-module resolution and iteration-rule violations. No new lint finding was identified in the changed lines.
Scope boundary
.includes("NO_REPLY")matchers outside this kernel storage path._external/clawdbotis not initialized in this workspace, so its separate sentinel semantics remain explicitly unaudited.