Skip to content

feat(mcpl): transport-declared context-only messages (suppressWake) - #180

Open
ian-de-marcellus wants to merge 3 commits into
anima-research:mainfrom
ian-de-marcellus:feat/transport-context-only
Open

ian-de-marcellus wants to merge 3 commits into
anima-research:mainfrom
ian-de-marcellus:feat/transport-context-only

Conversation

@ian-de-marcellus

@ian-de-marcellus ian-de-marcellus commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Problem

In a large setup the EventGate is the right place to decide what wakes a resident. Residents see many channels, get woken by DMs and pings, and read the rest at their leisure.

Small setups work differently. A resident that lives in a handful of channels naturally runs a gate that wakes on essentially every message (or on custom rules for one busy room). There, the transport often knows something the gate can't: a message isn't a turn. For example:

  • Continuation chunks. A person splits a long thought across Discord's length limit. Each chunk arrives as its own message, and each wakes the resident: several inferences for one thought, each answering a fragment.
  • Batched delivery. A connector that holds a burst and delivers it at once should wake on the last message, not on every one.
  • Replays. Messages restored after a delivery failure (discord-mcpl fix(mcpl): normalize featureSets array → Record + omit temperature when unset #38) belong in context but shouldn't trigger a burst of turns.

Upstream's answer today is a gate rule on a tag. That needs every small setup to write matching rules, and because policies are first-match-wins, a permissive rule placed earlier ("wake on anything addressed") silently wins over the "don't wake on continuations" rule.

Fix

A transport can declare a message context-only:

  • channels/incoming: metadata.suppressWake: true
  • push events: origin.suppressWake: true

It is stored and routed exactly as before but never triggers inference. The check runs before the optional gate, so gate rule order can't undo it. It only ever removes a wake: transports that never set it, and large setups whose gates already skip ambient traffic, are unaffected.

Tests

test/mcpl-gate-roundtrip.test.ts:

  • channels/incoming: with a permissive gate, a message marked suppressWake is stored with triggerInference: false, and the flag stays in its metadata.
  • push events: a context-only event is stored without inference and the gate is never consulted; the same event without the flag still wakes under the same permissive gate (control).

Full suite: 957 pass, 0 fail (4 skipped). Changelog fragment included.

In production on a small five-resident setup for continuation chunks and batched rooms; discord-mcpl #38 emits the hint for replays.

🤖 Generated with Claude Code

ian-de-marcellus and others added 3 commits September 24, 2026 16:13
A transport can mark an incoming message or push event as context-only with
metadata/origin suppressWake: true. It is checked before the optional
inference gate, so a permissive gate cannot turn it into a wake. discord-mcpl
uses it for continuation chunks and for non-tail messages of a batched room.

Ported from local uncommitted work onto current main.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e gate

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5 Tier: apex

[Medium risk] Adds context-only message suppression to inference triggering.

The PR is not ready to merge because context-only events can still wake through modules and suppressed push events violate the response contract.

Findings

  1. P1 Module wakes bypass suppression ▶
  2. P1 Suppressed events receive inference IDs ▶
Fix with agent prompt
### Issue 1
src/mcpl/channel-registry.ts:888-889
When a module requests inference for a context-only channel message, this check sets `triggerInference` to false, but the framework still dispatches the event to the module and queues its wake request without checking that flag. The same applies to suppressed push events. The agent can therefore wake despite the transport's context-only hint.

### Issue 2
src/mcpl/push-handler.ts:239
When `origin.suppressWake` is true, this code disables inference, but the push handler still returns an `inferenceId` in its success response. The response contract says that field is present only when inference was triggered, so the transport receives an identifier for a turn that will not occur.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR adds transport-declared context-only handling for channel messages and push events, with tests and a changelog fragment.

  • The new suppression does not cover inference requested by modules.
  • Suppressed push events still return an inference ID, and the new tests do not exercise downstream storage or wake processing.

Reviews (1) · Last reviewed commit: "test(mcpl): push-event lane honors conte..."

Comment on lines +888 to +889
let triggerInference = message.metadata?.suppressWake !== true;
if (triggerInference && this.shouldTriggerInference) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Module wakes bypass suppression When a module requests inference for a context-only channel message, this check sets triggerInference to false, but the framework still dispatches the event to the module and queues its wake request without checking that flag. The same applies to suppressed push events. The agent can therefore wake despite the transport's context-only hint.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mcpl/channel-registry.ts
Line: 888-889

Comment:
**Module wakes bypass suppression** When a module requests inference for a context-only channel message, this check sets `triggerInference` to false, but the framework still dispatches the event to the module and queues its wake request without checking that flag. The same applies to suppressed push events. The agent can therefore wake despite the transport's context-only hint.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread src/mcpl/push-handler.ts
if (this.shouldTriggerInference) {
// Same context-only contract as channels/incoming: a transport may mark
// an event (e.g. a continuation chunk) as context-only.
let triggerInference = params.origin?.suppressWake !== true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Suppressed events receive inference IDs When origin.suppressWake is true, this code disables inference, but the push handler still returns an inferenceId in its success response. The response contract says that field is present only when inference was triggered, so the transport receives an identifier for a turn that will not occur.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mcpl/push-handler.ts
Line: 239

Comment:
**Suppressed events receive inference IDs** When `origin.suppressWake` is true, this code disables inference, but the push handler still returns an `inferenceId` in its success response. The response contract says that field is present only when inference was triggered, so the transport receives an identifier for a turn that will not occur.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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.

1 participant