From 4209cf3509cbb5c25d1902e470cf637b2b8fe63c Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Mon, 30 Mar 2026 23:29:24 -0400 Subject: [PATCH] fix(matrix): keep DM invite promotion stable --- CHANGELOG.md | 2 +- extensions/matrix/src/matrix/monitor/direct.test.ts | 2 ++ extensions/matrix/src/matrix/monitor/direct.ts | 1 - extensions/matrix/src/matrix/monitor/events.test.ts | 4 ++-- extensions/matrix/src/matrix/monitor/events.ts | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47a03922e2f..85f21a6820c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -140,7 +140,7 @@ Docs: https://docs.openclaw.ai - xAI/Responses: normalize image-bearing tool results for xAI responses payloads, including OpenResponses-style `input_image.source` parts, so image tool replays no longer 422 on the follow-up turn. (#58017) Thanks @neeravmakwana. - Cron/isolated sessions: carry the full live-session provider, model, and auth-profile selection across retry restarts so cron jobs with model overrides no longer fail or loop on mid-run model-switch requests. (#57972) Thanks @issaba1. - Matrix/direct rooms: stop trusting remote `is_direct`, honor explicit local `is_direct: false` for discovered DM candidates, and avoid extra member-state lookups for shared rooms so DM routing and repair stay aligned. (#57124) Thanks @w-sss. -- Matrix/DM threads: only promote fresh invite rooms when Matrix marks the invite as direct, keep failed local DM repairs stable across later replies, and keep thread-isolated Matrix sessions reporting the correct route policy. +- Matrix/DM threads: keep strict unnamed fresh-invite rooms promotable even when Matrix omits the optional direct hint, preserve repair-failed local DM promotions across later member churn, and keep thread-isolated Matrix sessions reporting the correct route policy. (#58099) Thanks @gumadeiras. - Agents/sandbox: make remote FS bridge reads pin the parent path and open the file atomically in the helper so read access cannot race path resolution. Thanks @AntAISecurityLab and @vincentkoc. - Tools/web_fetch: add an explicit trusted env-proxy path for proxy-only installs while keeping strict SSRF fetches on the pinned direct path, so trusted proxy routing does not weaken strict destination binding. (#50650) Thanks @kkav004. - Exec/env: block Python package index override variables from request-scoped host exec environment sanitization so package fetches cannot be redirected through a caller-supplied index. Thanks @nexrin and @vincentkoc. diff --git a/extensions/matrix/src/matrix/monitor/direct.test.ts b/extensions/matrix/src/matrix/monitor/direct.test.ts index 4a92c651dfb..9fb1e50ba52 100644 --- a/extensions/matrix/src/matrix/monitor/direct.test.ts +++ b/extensions/matrix/src/matrix/monitor/direct.test.ts @@ -341,6 +341,8 @@ describe("createDirectRoomTracker", () => { }), ).resolves.toBe(true); + tracker.invalidateRoom("!room:example.org"); + vi.setSystemTime(new Date("2026-03-30T23:01:00Z")); await expect( diff --git a/extensions/matrix/src/matrix/monitor/direct.ts b/extensions/matrix/src/matrix/monitor/direct.ts index 5e9ee3fc7f8..19b2745b969 100644 --- a/extensions/matrix/src/matrix/monitor/direct.ts +++ b/extensions/matrix/src/matrix/monitor/direct.ts @@ -154,7 +154,6 @@ export function createDirectRoomTracker(client: MatrixClient, opts: DirectRoomTr directMemberFlagCache.delete(key); } } - locallyPromotedDirectRooms.delete(roomId); lastDmUpdateMs = 0; log(`matrix: invalidated dm cache room=${roomId}`); }, diff --git a/extensions/matrix/src/matrix/monitor/events.test.ts b/extensions/matrix/src/matrix/monitor/events.test.ts index f034687af79..bce2862ac5e 100644 --- a/extensions/matrix/src/matrix/monitor/events.test.ts +++ b/extensions/matrix/src/matrix/monitor/events.test.ts @@ -306,7 +306,7 @@ describe("registerMatrixMonitorEvents verification routing", () => { expect(rememberInvite).not.toHaveBeenCalled(); }); - it("does not remember invite provenance when Matrix does not mark the invite as direct", async () => { + it("remembers invite provenance even when Matrix omits the direct invite hint", async () => { const { invalidateRoom, rememberInvite, roomInviteListener } = createHarness(); if (!roomInviteListener) { throw new Error("room.invite listener was not registered"); @@ -324,7 +324,7 @@ describe("registerMatrixMonitorEvents verification routing", () => { }); expect(invalidateRoom).toHaveBeenCalledWith("!room:example.org"); - expect(rememberInvite).not.toHaveBeenCalled(); + expect(rememberInvite).toHaveBeenCalledWith("!room:example.org", "@alice:example.org"); }); it("does not synthesize invite provenance from room joins", async () => { diff --git a/extensions/matrix/src/matrix/monitor/events.ts b/extensions/matrix/src/matrix/monitor/events.ts index c81b3807c5f..1d69053d786 100644 --- a/extensions/matrix/src/matrix/monitor/events.ts +++ b/extensions/matrix/src/matrix/monitor/events.ts @@ -131,7 +131,7 @@ export function registerMatrixMonitorEvents(params: { const senderIsInvitee = typeof event?.sender === "string" && invitee && event.sender.trim() === invitee; const isDirect = (event?.content as { is_direct?: boolean } | undefined)?.is_direct === true; - if (isDirect && typeof event?.sender === "string" && event.sender.trim() && !senderIsInvitee) { + if (typeof event?.sender === "string" && event.sender.trim() && !senderIsInvitee) { directTracker?.rememberInvite?.(roomId, event.sender); } logVerboseMessage(