OpenClaw’s Cross-Channel Session-Origin Bug Is a Multi-Agent Identity Boundary in Miniature
Conversation continuity is not identity continuity. That is the cleanest way to read OpenClaw issue #95325, a fresh cross-channel session bug where the same user talks to an agent in Slack and then Telegram under session.dmScope: "main". The chat moves. The delivery route updates. But Slack-specific origin metadata can remain stuck to the session like a stale pointer with a friendly face.
The reported reproduction is deterministic. Message an agent in Slack DM. Then message the same agent from Telegram using the same main-scoped direct-message session. OpenClaw correctly updates the obvious delivery fields: provider, surface, from, to, and accountId become Telegram according to the issue. But origin.nativeChannelId can keep holding the Slack DM ID, and threadId can also persist because Telegram DMs do not supply equivalent fields.
The user may not notice because the main message still lands in Telegram. That is what makes the bug interesting. The happy-path bubble works. The control-plane metadata is wrong.
Shared sessions are useful; shared origin fields are dangerous
The root cause is a sparse merge. OpenClaw’s mergeOrigin overwrites fields only when the new inbound event supplies them. Within a single provider, that is reasonable. If Slack sends a thread ID on one event and omits something incidental on the next, preserving known fields can be helpful. Across providers or surfaces, the same behavior turns into metadata bleed. A Slack DM channel ID is not a Telegram DM. A Slack thread ID is not a Telegram message context. Keeping them alive after a provider switch makes the session look more continuous than it actually is.
Two candidate fixes appeared within minutes. PR #95328 clears nativeChannelId, nativeDirectUserId, and threadId when the provider or surface changes, adds 96 lines of regression tests, and demonstrates the previous failure where a Slack value like D111SLACK persisted into Telegram. PR #95329 clears those fields plus accountId on provider change, adds 128 lines of tests, and reports all 363 session tests passing.
The debate over accountId is not bikeshedding. It is the contract. The issue text says accountId correctly becomes Telegram. PR #95329 says it can go stale too. That discrepancy is exactly where maintainers should be proof-driven. The invariant should be simple enough to explain in one sentence: any field that names a provider-specific channel, user, thread, account, or native message context must either be explicitly supplied by the new provider or cleared when the provider boundary changes.
This is one of those bugs that looks small because delivery is unaffected. But secondary operations often rely on origin metadata: reactions, native threading, message references, status cards, inspection surfaces, audit logs, and channel-keyed tool calls. If those point at the previous Slack channel while the active conversation is now Telegram, the system can become confusing at best and wrong at worst. Even if no message leaks, operator trust takes a hit when status says one thing and lived reality says another.
Multi-surface agents fail at the seams
OpenClaw is not alone here. Every multi-channel agent platform wants continuity because users hate starting over. They move between Slack, Telegram, Discord, web chat, mobile apps, CLI sessions, and email. They expect the agent to remember the task, not split reality by transport. That is a reasonable product goal. But continuity has layers. Conversation state can survive a channel switch. Channel authority should not automatically survive with it.
That distinction becomes more important as agents gain native-channel powers. A bot that only replies with text has limited blast radius. A bot that can react, pin, read thread history, download files, resolve member info, inspect sessions, or route follow-ups needs clean identity boundaries. Otherwise, stale metadata becomes ambient authority. The platform does not need a malicious model to misbehave. It only needs an old field to look valid in a new context.
For operators, the action item is to test channel crossings, not just channel support. Slack DM to Telegram DM. Telegram topic to web chat. Discord thread to Slack channel. Mobile app to desktop. For each hop, verify message delivery, origin metadata, reactions, thread linkage, account identity, audit output, status output, and tool authorization. If your smoke test ends at “the message arrived,” you are testing the least subtle part of the system.
For builders, the lesson is to separate durable conversation identity from provider-specific origin identity in the data model. Use explicit reset rules when provider, surface, account, or native context changes. Avoid sparse merges that preserve fields across authority boundaries. Prefer typed origin objects with provider-specific variants over a flat bag of optional fields that silently accumulate history. And add regression tests that assert stale fields are cleared, not merely overwritten when the next provider happens to send a replacement.
There is also an observability angle. Status and inspection surfaces should show enough origin provenance that stale metadata is obvious. If a session is currently Telegram but still carries a Slack native channel ID, that should look suspicious immediately. Control-plane truthfulness matters because operators use those surfaces to decide whether the agent is healthy, where it is replying, and which tools it can safely use.
The editorial take: this is not “OpenClaw forgot to delete a Slack channel ID.” It is a miniature version of the multi-agent identity problem. Conversation continuity is useful. Channel metadata continuity can be wrong. The platforms that get this right will treat session origin as a boundary, not a scrapbook.
Sources: OpenClaw issue #95325, OpenClaw PR #95328, OpenClaw PR #95329