Skip to content

fix: suppress NO_REPLY at end of message (closes #111)#112

Merged
fitz123 merged 1 commit intomainfrom
issue-111-no-reply-eom
Apr 28, 2026
Merged

fix: suppress NO_REPLY at end of message (closes #111)#112
fitz123 merged 1 commit intomainfrom
issue-111-no-reply-eom

Conversation

@fitz123
Copy link
Copy Markdown
Owner

@fitz123 fitz123 commented Apr 27, 2026

Closes #111.

Summary

  • Pipeline-style cron prompts (workspace-health, memory-consolidation, backup-git) reliably produce <recap>\n\nNO_REPLY and the recap was being delivered as a real message
  • Extends suppression to also accept NO_REPLY alone on the last non-empty line of the trimmed output (in addition to the existing start-of-message rule from fix: NO_REPLY check should use trim/startsWith instead of exact match #80)
  • Extracts the suppression check into bot/src/no-reply.ts so stream-relay.ts and cron-runner.ts agree on exactly which patterns suppress
  • Same-line patterns (Done. NO_REPLY) and substring prefixes (NO_REPLY_EXTRA) are intentionally NOT matched

Evidence

9 leaked messages across 4 distinct crons in a 2-day window, all the same <summary>\n\nNO_REPLY shape — full samples in #111. Two prompt-side mitigations (per-cron strengthening + platform rule strengthening in #110) failed to change agent behavior; the model's RLHF "report what you did" instinct overrides explicit instructions to emit a bare token.

Test plan

  • Unit tests in bot/src/__tests__/stream-relay.test.ts cover end-of-message NO_REPLY (alone on last line, with whitespace, multi-line content above, single-newline, trailing-newline) and reproduce one of the verbatim leaked samples
  • Unit tests in bot/src/__tests__/cron-runner.test.ts cover the same pattern set for the cron path
  • Same-line Done. NO_REPLY and NO_REPLY_EXTRA substring prefix are NOT suppressed (negative cases pinned)
  • All existing NO_REPLY tests still pass (issue fix: NO_REPLY check should use trim/startsWith instead of exact match #80 backward compatibility preserved)
  • npx tsc --noEmit clean
  • npm test: 1016/1017 pass (1 pre-existing env-specific voice.ts failure unrelated to this change)
  • Manual verification: trigger a workspace-health cron after merge — verify suppression

Closes #111. Agents in pipeline-style cron prompts (workspace-health,
memory-consolidation, backup-git) reliably produce a recap followed by
NO_REPLY at the end. The current /^NO_REPLY\b/ regex only matches at
the start, so the recap was being delivered as a Telegram message
(9 leaked messages across 4 crons in a 2-day window).

Extracts the suppression check into bot/src/no-reply.ts (shared by
stream-relay.ts and cron-runner.ts) so both delivery paths agree on
exactly which patterns suppress.

Accepts:
- NO_REPLY at the start of output (existing — backward compat with #80)
- NO_REPLY alone on the last non-empty line (new)

Does not match same-line patterns like 'Done. NO_REPLY' or substring
prefixes like 'NO_REPLY_EXTRA'.

Test coverage in bot/src/__tests__/{stream-relay,cron-runner}.test.ts
includes the verbatim leaked-output samples from the issue.

Doc update in .claude/rules/platform/communication.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 27, 2026 19:48
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a delivery suppression gap where cron/pipeline prompts often emit summaries ending with NO_REPLY, causing the summary to be delivered instead of suppressed (closes #111). The PR centralizes the suppression logic so both interactive streaming and cron delivery paths apply identical matching rules.

Changes:

  • Extend NO_REPLY suppression to also match when NO_REPLY appears alone on the last non-empty line (while preserving the existing start-of-message suppression behavior from #80).
  • Extract shared suppression logic into bot/src/no-reply.ts and reuse it from both stream-relay.ts and cron-runner.ts.
  • Add unit tests covering end-of-message suppression and negative cases (same-line ... NO_REPLY and NO_REPLY_EXTRA).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
docs/plans/completed/2026-04-27-issue-111-no-reply-end-of-message.md Adds a completed plan/write-up documenting the issue, rationale, and test expectations for the suppression change.
bot/src/no-reply.ts Introduces shouldSuppressNoReply() implementing the shared start-of-message or last-line-only suppression rules.
bot/src/stream-relay.ts Replaces inline regex suppression with the shared shouldSuppressNoReply() check for interactive streaming delivery.
bot/src/cron-runner.ts Replaces inline regex suppression with the shared shouldSuppressNoReply() check for LLM cron output delivery.
bot/src/tests/stream-relay.test.ts Adds test coverage for end-of-message NO_REPLY suppression and explicitly pinned negative cases.
bot/src/tests/cron-runner.test.ts Adds unit tests for shouldSuppressNoReply() to ensure cron-path behavior matches the same suppression patterns.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@fitz123 fitz123 merged commit 234032a into main Apr 28, 2026
5 checks passed
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.

fix: NO_REPLY suppression also needs to match end-of-message pattern

2 participants