Skip to content

fix(routing): world say/whisper silence adjacent prose in every mode - #136

Merged
antra-tess merged 1 commit into
mainfrom
fix/world-say-silencing
Sep 2, 2026
Merged

fix(routing): world say/whisper silence adjacent prose in every mode#136
antra-tess merged 1 commit into
mainfrom
fix/world-say-silencing

Conversation

@antra-tess

Copy link
Copy Markdown
Collaborator

Incident

Mica's report af-world-say-prose-leak-20260901.md (SHA-256 9507f309…): in locus prose mode, a round of ordinary text + explicit Eidoverse say published twice — world seq 15146 = the say tool input, seq 15147 = the adjacent ordinary text, byte-for-byte (Cairn provider row 230). Not a same_round_think_text_policy bypass; no think() was called and provider-native thinking stayed private.

Root cause (confirmed)

src/framework.ts consulted HYBRID_PUBLICATION_TOOLS (say, whisper) only when agent.proseRouting === 'hybrid', at both silencing sites (live round + trailing scan). Introduced by c83fadb3 (2026-08-14, hybrid envelopes). Discord sends in SILENCING_TOOLS silenced in every mode; world verbs did not.

Fix

Fold the world verbs into one isSilencingTool(name) predicate used at both sites. An explicit world utterance now behaves exactly like a channel send in every mode: sticky silencing from that round on, suppression visible in the [delivered] receipt. No behavior change for Discord send/reply/DM, skip_reply, think() privacy, text-only turns, non-publishing tool rounds, explicit mode (silencing never applied there), or disabled mode.

Receipts (worktree off origin/main d9fb35b, node_modules shared)

  • typecheck clean
  • focused (present-while-acting, explicit-prose-routing, same-round-think-policy, prose-stream-router): 74/74
  • full: 0 fail on both runs (629/633 and 656/660 — totals vary run to run under --test-force-exit; base d9fb35b was 631/635, also 0 fail)
  • mutation control: removing WORLD_PUBLICATION_TOOLS from the predicate fails both new locus tests and the existing hybrid say test; the move negative control still passes

Nonblocking notes

  • emote is also a world publication verb; left out of the set, matching the report's scope. Whether an emote should silence narration is a doctrine call.
  • bareToolName strips the MCPL prefix, so any server exposing a bare say/whisper tool (e.g. tavern-mcpl) now silences too. Consistent with hybrid's existing behavior.
  • Deploy is separate: Mac residents load AF via the forking-knowledge-miner symlink to the local checkout, so this lands only on pull + restart.

🤖 Generated with Claude Code

https://claude.ai/code/session_017op4YjCZABYS9vWBXxeRwH

An explicit Eidoverse `say` / `whisper` is the resident's chosen public
utterance for that round, but the world-verb set was consulted only in
hybrid prose mode. In locus mode a round of ordinary text + `say`
published twice: the say text, then the adjacent prose auto-routed to the
same world locus (Cairn 2026-09-01, world seq 15146/15147 byte-for-byte;
Mica's incident artifact af-world-say-prose-leak-20260901.md).

Fold the world verbs into one `isSilencingTool` predicate used at both
silencing sites (live round + trailing scan), so they behave exactly like
channel sends: sticky from that round on, suppression visible in the
[delivered] receipt. Discord send/reply/DM, skip_reply, think() privacy,
text-only turns and non-publishing tool rounds are unchanged.

Tests: locus-mode say and whisper (nothing auto-routed, receipt reports
2 suppressed), plus a `move` negative control. Mutation control (world
verbs removed from the predicate) fails both new tests and the existing
hybrid say test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017op4YjCZABYS9vWBXxeRwH
@antra-tess
antra-tess merged commit 12f0ee6 into main Sep 2, 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.

1 participant