Skip to content

fix(gateway): prefer current route delivery context#69010

Open
cgdusek wants to merge 2 commits into
openclaw:mainfrom
cgdusek:codex/fix-current-route-68378
Open

fix(gateway): prefer current route delivery context#69010
cgdusek wants to merge 2 commits into
openclaw:mainfrom
cgdusek:codex/fix-current-route-68378

Conversation

@cgdusek

@cgdusek cgdusek commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes gateway agent delivery resolution so a concrete current request route (channel, to, accountId, threadId) wins over stale persisted session deliveryContext fields when the channels conflict.
  • Clears stale route fields on channel switches when the new request does not provide replacement to/accountId/threadId values, avoiding mixed-channel routes.
  • Preserves existing session-route behavior for normal follow-ups, channel=last, and same-channel existing-session routes.
  • Compares same-channel targets through the channel parser so equivalent encodings do not clear stored threads.
  • Populates runContext.currentChannelId from the resolved delivery target so downstream message-tool fallback inference sees the active route.
  • Adds regression tests for the Bug: Gateway sends Discord session messages to Feishu channel (critical message routing bug) #68378 shape, channel-only stale-route clearing, same-channel partial updates, and canonical equivalent targets.

Linked Issue/PR

Root Cause / Diagnosis

src/gateway/server-methods/agent.ts built requestDeliveryHint from the active gateway request, but then merged it with the stored session deliveryContext in a way that made persisted fields authoritative. That let stale persisted fields, such as Feishu channel/to, override a current Discord request before the agent command and session update were assembled. The same path also did not pass the resolved target into runContext.currentChannelId, so tool fallback routing could miss the current route even when resolvedTo was known.

A second edge case appears when the request changes only channel: route-field fallback must not pair a new channel with stale lastTo/lastAccountId/lastThreadId from the old channel.

A third edge case appears when the request and session refer to the same target with different channel-owned encodings, such as Slack C1 and channel:C1: raw string comparison can falsely treat that as a target change and clear the stored thread.

Fix

  • Detect when a concrete request channel conflicts with the stored session delivery channel.
  • In that cross-channel conflict case, let the current request delivery hint win and use persisted delivery metadata only as fallback for fields provided by the current route.
  • Clear stale last-route fields when the current channel conflicts and no replacement field is available.
  • For same-channel route conflicts, preserve unchanged target/account/thread fields unless the concrete target itself changes.
  • Compare request/session targets using the channel parser before treating to as a target change, preserving stored threads for equivalent target spellings.
  • For non-conflict cases, keep existing session delivery precedence so channel=last, normal follow-ups, and existing subagent routes behave as before.
  • Pass resolvedTo into runContext.currentChannelId alongside the existing channel/account/thread context.
  • Lock the behavior with regression tests that start from stale Feishu metadata, assert Discord wins or stale route fields are cleared, preserve partial same-channel updates, and keep Slack threads when C1 and channel:C1 are equivalent.

Duplicate Sweep

Searched GitHub issues/PRs for combinations of #68378, Discord/Feishu wrong-channel delivery, stale deliveryContext, gateway agent delivery, currentChannelId, and multi-channel session routing. Closest results:

Conclusion: no duplicate or already-satisfactory PR found for #68378.

Attribution

Testing

Fresh origin/main base: 64089fd15ed4ba8296612b1a622d11b5662c8b96

  • pnpm test -- src/gateway/server-methods/agent.test.ts -t "uses the current request route"
  • pnpm test -- src/gateway/server-methods/agent.test.ts
  • pnpm test -- src/gateway/server-methods/agent.test.ts -t "preserves the stored thread when the request target is canonically equivalent"
  • pnpm test -- src/gateway/server-methods/agent.test.ts src/gateway/server.agent.gateway-server-agent-a.test.ts src/gateway/server.agent.gateway-server-agent-b.test.ts src/gateway/server.agent.subagent-delivery-context.test.ts

The final command covers the CI shard failures observed after the first draft and now passes locally with 71 tests.

Scoped lint note: pnpm lint -- src/gateway/server-methods/agent.ts src/gateway/server-methods/agent.test.ts is currently blocked before linting these files by the existing src/agents/skills/* plugin SDK boundary type errors already present on origin/main.

Review Follow-up

  • Addressed and resolved Codex review thread about clearing stale route fields on channel-switch merges in 5825aede6c7568f8cec2af2653d4851bf3296d78.
  • Addressed and resolved Codex review thread about preserving unchanged same-channel route fields in d8f4d09a343f30d82df2bdeea9541a707923a72d.
  • Addressed and resolved Codex review thread about canonical target comparison in af7506771a0fd734024ecc2b51b23b7945f27b21.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

The change narrows routing behavior to prefer the active request route only when it conflicts with stale persisted delivery metadata, and preserves stored thread context for equivalent same-channel target spellings.

@greptile-apps

greptile-apps Bot commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a routing bug in the gateway agent handler where stale persisted session deliveryContext could override the current request's channel/to/accountId fields. The fix reverses the argument order of mergeDeliveryContext so the live request hint is primary (line 657–660 of agent.ts), and adds currentChannelId: resolvedTo to runContext. A regression test covering the Discord-over-stale-Feishu shape is included.

Confidence Score: 5/5

Safe to merge — the fix is a single targeted merge-order change with a solid regression test and no security implications.

The root cause analysis is accurate, the reversal of mergeDeliveryContext(requestDeliveryHint, deliveryFields.deliveryContext) correctly makes the live request primary, mergeDeliveryContext already handles cross-channel field isolation via the channelsConflict guard, and the currentChannelId: resolvedTo addition is straightforward. The regression test exercises the exact bug shape reported. No P0/P1 issues found.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(gateway): prefer current route deliv..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a557b56825

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/gateway/server-methods/agent.ts Outdated
@cgdusek
cgdusek force-pushed the codex/fix-current-route-68378 branch 3 times, most recently from 5825aed to e9c89b3 Compare April 19, 2026 16:48
@cgdusek

cgdusek commented Apr 19, 2026

Copy link
Copy Markdown
Contributor Author

Aisle / review follow-up:

  • The gateway route-precedence bug is addressed in af7506771a0fd734024ecc2b51b23b7945f27b21: deliver: true target/account/thread mismatches are treated as concrete route conflicts, so the current request route wins for output delivery instead of being overridden by stale session fields.
  • Same-channel partial route updates preserve unchanged stored route fields. A thread-only request keeps the stored to/accountId while updating threadId.
  • Equivalent same-channel targets are now compared through the channel parser before to is treated as changed. The regression covers Slack C1 vs channel:C1 and verifies the stored thread is preserved instead of being cleared.
  • Channel-only switches stay narrow: a request that changes channel but provides no concrete to target no longer mutates the persisted session route. The current turn still uses the request channel for immediate routing, but the store keeps the prior delivery route instead of clearing lastTo/accountId/lastThreadId or pairing stale fields with the new channel.
  • The remaining session-key ownership concern in the Aisle report is broader than this PR. agent remains inside the authenticated operator.write/operator.admin gateway trust boundary (authorizeGatewayMethod + method-scopes.ts); unauthenticated or read-only callers cannot invoke it. Per-session ownership/capability binding for deterministic session keys would need a separate cross-surface hardening design across session-mutating methods, not a route-precedence patch here.

Verification:

pnpm test -- src/gateway/server-methods/agent.test.ts -t "preserves the stored thread when the request target is canonically equivalent"

pnpm test -- src/gateway/server-methods/agent.test.ts src/gateway/server.agent.gateway-server-agent-a.test.ts src/gateway/server.agent.gateway-server-agent-b.test.ts src/gateway/server.agent.subagent-delivery-context.test.ts

Notes on broader local gates: local pnpm build, pnpm tsgo:core, and scoped pnpm lint -- src/gateway/server-methods/agent.ts src/gateway/server-methods/agent.test.ts are currently blocked before this touched code by existing src/agents/skills/* plugin SDK boundary type errors already present on origin/main; local pnpm build also remains blocked by the existing @aws/bedrock-token-generator non-exact dependency staging issue already present on origin/main.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9c89b3c43

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/gateway/server-methods/agent.ts Outdated
@cgdusek
cgdusek force-pushed the codex/fix-current-route-68378 branch 2 times, most recently from e6911ce to d8f4d09 Compare April 19, 2026 16:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8f4d09a34

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/gateway/server-methods/agent.ts
@cgdusek
cgdusek force-pushed the codex/fix-current-route-68378 branch from d8f4d09 to af75067 Compare April 19, 2026 17:15
@ysongyang

Copy link
Copy Markdown

同样遇到此问题,等待修复,请尽快合并。

@vincentkoc

Copy link
Copy Markdown
Member

ProjectClownfish pushed a narrow repair to this branch so the original contributor path can stay canonical.

Source PR: #69010
Validation: pnpm check:changed
Contributor credit is preserved in the branch history and PR context.

@vincentkoc
vincentkoc force-pushed the codex/fix-current-route-68378 branch from af75067 to 21a07b1 Compare April 28, 2026 18:47
@aisle-research-bot

aisle-research-bot Bot commented Apr 28, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Mixed accountId/to when replacing session delivery route can misdeliver messages
1. 🟡 Mixed accountId/to when replacing session delivery route can misdeliver messages
Property Value
Severity Medium
CWE CWE-284
Location src/gateway/server-methods/agent.ts:937-950

Description

When deliverRouteConflictsWithSession and requestTargetDiffers are true, the code builds a new delivery context by mixing request and session fields with independent fallbacks:

  • to is taken from requestDeliveryHint?.to ?? sessionDelivery?.to
  • accountId is taken from requestDeliveryHint?.accountId ?? sessionDelivery?.accountId
  • threadId is taken only from the request (no fallback)

This can create an inconsistent route where a new to is paired with an old accountId (or vice versa) whenever the request supplies only a subset of route fields while changing targets. If accountId selects which configured channel account/credential is used, the gateway may send a message to the wrong destination/account combination, leading to unintended cross-account delivery and potential information disclosure/impersonation.

Vulnerable code:

normalizeDeliveryContext({
  channel: requestDeliveryHint?.channel ?? sessionDelivery?.channel,
  to: requestDeliveryHint?.to ?? sessionDelivery?.to,
  accountId: requestDeliveryHint?.accountId ?? sessionDelivery?.accountId,
  threadId: requestDeliveryHint?.threadId,
})

Recommendation

Require route fields to be updated atomically when changing the target (or explicitly clear coupled fields) to avoid pairing to with a stale accountId/threadId.

For example, when requestTargetDiffers is true:

  • If the request specifies to, require it to also specify accountId (and/or threadId as appropriate for the channel), or
  • When to changes, do not fall back to the session accountId/threadId—instead clear them so routing code must resolve the correct account/thread explicitly.

One possible safe approach:

if (requestTargetDiffers) {
  if (requestDeliveryHint?.to == null) {// cannot change target without explicit to
    return error;
  }// either require accountId explicitly or clear it
  const effective = normalizeDeliveryContext({
    channel: requestDeliveryHint.channel ?? sessionDelivery?.channel,
    to: requestDeliveryHint.to,
    accountId: requestDeliveryHint.accountId, // no fallback
    threadId: requestDeliveryHint.threadId,   // no fallback
  });
}

Also consider validating that {channel,to,accountId,threadId} combinations are consistent for the channel plugin before persisting them to the session.


Analyzed PR: #69010 at commit 21a07b1

Last updated on: 2026-04-28T18:49:49Z

@clawsweeper

clawsweeper Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Keep open: this PR still targets a real wrong-channel gateway routing bug, but it is not merge-ready because the branch is stale against current main, still has an account/target mixing path, and lacks after-fix real behavior proof.

Root-cause cluster
Relationship: canonical
Canonical: #69010
Summary: This PR is the canonical open tracker for the linked Discord-to-Feishu stale delivery-context report; related routing items are adjacent or partial, not replacements for this branch in its current state.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Canonical path: Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review.

So I’m closing this here because the remaining work is already tracked in the canonical issue.

Review details

Best possible solution:

Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review.

Do we have a high-confidence way to reproduce the issue?

Yes, from source and linked logs rather than a fresh local run: the linked issue shows Discord traffic delivered via Feishu, and the PR/current-main code paths show how stale session delivery context and turn-source routing decide the destination. I did not run a live Discord/Feishu reproduction in this read-only review.

Is this the best way to solve the issue?

No, not in its current form. The bug belongs in the gateway/outbound route owner path, but this branch must be rebased onto current main and must avoid pairing a fresh target with stale account metadata.

Security review:

Security review needs attention: The diff still has a concrete same-channel account/target mixing risk that can misdeliver messages across configured channel accounts.

  • [medium] Fresh target can inherit stale account credentials — src/gateway/server-methods/agent.ts:946
    The requestTargetDiffers branch falls back from request account to session account while using the request target, which can send through the wrong account in multi-account channel setups.
    Confidence: 0.88

AGENTS.md: found and applied where relevant.

What I checked:

  • stale F-rated PR: PR was opened 2026-04-19T15:49:50Z, is older than 60 days, and the latest review rated it F.
  • proof blocker: real behavior proof is mock_only and proof tier is F, so this branch is not merge-ready without contributor follow-up.
  • no human follow-up: live comments and timeline hydrated by apply contain no non-automation activity after the ClawSweeper review.

Likely related people:

  • Dallin Romney: Current main blame for the gateway delivery-plan call and turn-source session target resolver points to the current-main commit carrying this route-planning surface. (role: recent area contributor; confidence: medium; commits: 8604dbdc93fb; files: src/gateway/server-methods/agent.ts, src/infra/outbound/targets-session.ts, src/agents/command/run-context.ts)
  • vincentkoc: Pushed the maintainer-side narrow repair commit to this PR and has recent target-parsing history around the helper that this stale branch now needs to rebase onto. (role: recent adjacent contributor; confidence: high; commits: 21a07b17fd60, eed595bba9ac; files: src/gateway/server-methods/agent.ts, src/channels/plugins/target-parsing-loaded.ts)
  • steipete: Shortlog over the central gateway/outbound delivery files shows the largest historical contribution count, useful for routing if the current-main ownership trail is too shallow. (role: historical area contributor; confidence: low; files: src/gateway/server-methods/agent.ts, src/infra/outbound/agent-delivery.ts, src/infra/outbound/targets-session.ts)

Codex review notes: model internal, reasoning high; reviewed against 8ed6c78b7891.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 20, 2026
@clawsweeper

clawsweeper Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 20, 2026
@clawsweeper clawsweeper Bot added P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels May 20, 2026
@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Jun 6, 2026
@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the stale Marked as stale due to inactivity label Jun 7, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels Jun 7, 2026
@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. and removed merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jun 29, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 29, 2026
@clawsweeper clawsweeper Bot added merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. and removed merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 30, 2026
@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Jul 18, 2026
@clawsweeper

clawsweeper Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper status: review started.

I am starting a fresh review of this pull request: fix(gateway): prefer current route delivery context This is item 1/1 in the current shard. Shard 15/22.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clawsweeper Tracked by ClawSweeper automation gateway Gateway runtime merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: M stale Marked as stale due to inactivity status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Gateway sends Discord session messages to Feishu channel (critical message routing bug)

3 participants