Skip to content

Commit 0a031e7

Browse files
committed
test: add real behavior proof for #95325 channel switch
1 parent fb86df4 commit 0a031e7

1 file changed

Lines changed: 93 additions & 0 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Real behavior proof for #95325: drives the production deriveSessionMetaPatch
2+
// to verify stale per-channel origin fields are reset on a channel switch.
3+
//
4+
// Run: node --import tsx scripts/repro/issue-95325-channel-switch.mts
5+
import { deriveSessionMetaPatch } from "../../src/config/sessions/metadata.ts";
6+
import type { MsgContext } from "../../src/auto-reply/templating.ts";
7+
import type { SessionEntry } from "../../src/config/sessions/types.ts";
8+
9+
function slackDmCtx(): MsgContext {
10+
return {
11+
Provider: "slack",
12+
OriginatingChannel: "slack",
13+
Surface: "slack",
14+
ChatType: "direct",
15+
From: "slack-user-id",
16+
NativeChannelId: "Dslackdm",
17+
NativeDirectUserId: "Uslackuser",
18+
AccountId: "slack-account",
19+
} as MsgContext;
20+
}
21+
22+
function telegramDmCtx(): MsgContext {
23+
// Telegram DMs carry no nativeChannelId / nativeDirectUserId.
24+
return {
25+
Provider: "telegram",
26+
OriginatingChannel: "telegram",
27+
Surface: "telegram",
28+
ChatType: "direct",
29+
From: "telegram-user-id",
30+
AccountId: "telegram-account",
31+
} as MsgContext;
32+
}
33+
34+
function fail(message: string): never {
35+
console.error(`FAIL: ${message}`);
36+
process.exitCode = 1;
37+
throw new Error(message);
38+
}
39+
40+
let existing: SessionEntry | undefined = undefined;
41+
42+
// Turn 1: Slack DM seeds the shared session with Slack native identity.
43+
const slackPatch = deriveSessionMetaPatch({
44+
ctx: slackDmCtx(),
45+
sessionKey: "dm:shared",
46+
existing,
47+
});
48+
existing = { ...(existing ?? ({} as SessionEntry)), ...(slackPatch ?? {}) } as SessionEntry;
49+
50+
if (existing.origin?.nativeChannelId !== "Dslackdm") {
51+
fail(`after Slack turn nativeChannelId should be Dslackdm, got ${existing.origin?.nativeChannelId}`);
52+
}
53+
console.log("PASS: Slack turn seeds origin.nativeChannelId = Dslackdm");
54+
55+
// Turn 2: Same user DMs on Telegram. Telegram supplies no nativeChannelId.
56+
const tgPatch = deriveSessionMetaPatch({
57+
ctx: telegramDmCtx(),
58+
sessionKey: "dm:shared",
59+
existing,
60+
});
61+
62+
const switchedOrigin = tgPatch?.origin;
63+
console.log("Telegram-switch origin:", JSON.stringify(switchedOrigin));
64+
65+
if (switchedOrigin?.provider !== "telegram") {
66+
fail(`provider should switch to telegram, got ${switchedOrigin?.provider}`);
67+
}
68+
if (switchedOrigin?.nativeChannelId !== undefined) {
69+
fail(
70+
`nativeChannelId should be reset after switch, got stale ${switchedOrigin.nativeChannelId}`,
71+
);
72+
}
73+
if (switchedOrigin?.nativeDirectUserId !== undefined) {
74+
fail(
75+
`nativeDirectUserId should be reset after switch, got stale ${switchedOrigin.nativeDirectUserId}`,
76+
);
77+
}
78+
console.log("PASS: channel switch to telegram reset stale nativeChannelId / nativeDirectUserId");
79+
80+
// Turn 3: Switch back to Slack — new nativeChannelId is adopted.
81+
const slackBackPatch = deriveSessionMetaPatch({
82+
ctx: slackDmCtx(),
83+
sessionKey: "dm:shared",
84+
existing: { ...(existing as SessionEntry), ...(tgPatch ?? {}) } as SessionEntry,
85+
});
86+
if (slackBackPatch?.origin?.nativeChannelId !== "Dslackdm") {
87+
fail(
88+
`nativeChannelId should re-adopt Slack value on switch back, got ${slackBackPatch?.origin?.nativeChannelId}`,
89+
);
90+
}
91+
console.log("PASS: switch back to Slack re-adopts nativeChannelId = Dslackdm");
92+
93+
console.log("\nALL CHECKS PASSED — stale per-channel origin fields reset on channel switch.");

0 commit comments

Comments
 (0)