refactor(feishu): consolidate doctor state fixtures (#118238)

This commit is contained in:
Peter Steinberger
2026-08-02 16:02:06 -07:00
committed by GitHub
parent adedc323b6
commit 1786a011df
+225 -422
View File
@@ -13,36 +13,14 @@ import {
appendSessionTranscriptMessageByIdentity,
readSessionTranscriptEvents,
} from "openclaw/plugin-sdk/session-transcript-runtime";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../runtime-api.js";
import { feishuDoctor } from "./doctor.js";
const runFeishuDoctorSequence = feishuDoctor.runConfigSequence!;
type EnvSnapshot = {
HOME?: string;
OPENCLAW_HOME?: string;
OPENCLAW_STATE_DIR?: string;
};
function captureEnv(): EnvSnapshot {
return {
HOME: process.env.HOME,
OPENCLAW_HOME: process.env.OPENCLAW_HOME,
OPENCLAW_STATE_DIR: process.env.OPENCLAW_STATE_DIR,
};
}
function restoreEnv(snapshot: EnvSnapshot) {
for (const key of Object.keys(snapshot) as Array<keyof EnvSnapshot>) {
const value = snapshot[key];
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
}
const defaultAgentId = "main";
const defaultFeishuSessionKey = "agent:main:feishu:direct:ou_user";
const blankUserMessages = ["", "", ""];
function feishuConfig(): OpenClawConfig {
return {
@@ -56,11 +34,7 @@ function feishuConfig(): OpenClawConfig {
}
function stateDir(): string {
const dir = process.env.OPENCLAW_STATE_DIR;
if (!dir) {
throw new Error("OPENCLAW_STATE_DIR is not set");
}
return dir;
return process.env.OPENCLAW_STATE_DIR!;
}
function sessionsDir(agentId = "main"): string {
@@ -75,6 +49,43 @@ function sqliteStorePath(agentId = "main"): string {
return path.join(stateDir(), "agents", agentId, "agent", "openclaw-agent.sqlite");
}
type SeedSessionParams = {
agentId?: string;
contents?: string[];
entry?: Record<string, unknown>;
sessionId: string;
sessionKey?: string;
storePath?: string;
};
async function seedSession(params: SeedSessionParams) {
const agentId = params.agentId ?? defaultAgentId;
const sessionKey = params.sessionKey ?? defaultFeishuSessionKey;
const targetStorePath = params.storePath ?? storePath(agentId);
await upsertSessionEntry({
agentId,
storePath: targetStorePath,
sessionKey,
entry: {
sessionId: params.sessionId,
updatedAt: Date.now(),
...params.entry,
} as SessionEntry,
});
if (params.contents) {
for (const content of params.contents) {
await appendSessionTranscriptMessageByIdentity({
agentId,
sessionId: params.sessionId,
sessionKey,
storePath: targetStorePath,
message: { role: "user", content },
});
}
}
return { agentId, sessionId: params.sessionId, sessionKey, storePath: targetStorePath };
}
function corruptTranscriptEventJson(agentId: string, sessionId: string): void {
const database = new DatabaseSync(sqliteStorePath(agentId));
try {
@@ -86,16 +97,6 @@ function corruptTranscriptEventJson(agentId: string, sessionId: string): void {
}
}
async function writeStore(entries: Record<string, unknown>, agentId = "main"): Promise<string> {
const target = storePath(agentId);
fs.mkdirSync(path.dirname(target), { recursive: true });
fs.writeFileSync(target, JSON.stringify(entries, null, 2));
for (const [sessionKey, entry] of Object.entries(entries as Record<string, SessionEntry>)) {
await upsertSessionEntry({ agentId, storePath: target, sessionKey, entry });
}
return target;
}
function insertRawSessionEntry(sessionKey: string, entry: SessionEntry, agentId = "main"): void {
const database = new DatabaseSync(sqliteStorePath(agentId));
try {
@@ -125,24 +126,6 @@ function writeLegacyTranscript(sessionId: string, lines: unknown[], agentId = "m
return target;
}
async function seedTranscriptMessages(params: {
agentId?: string;
sessionId: string;
sessionKey: string;
storePath: string;
contents: string[];
}): Promise<void> {
for (const content of params.contents) {
await appendSessionTranscriptMessageByIdentity({
agentId: params.agentId ?? "main",
sessionId: params.sessionId,
sessionKey: params.sessionKey,
storePath: params.storePath,
message: { role: "user", content },
});
}
}
function sessionHeader(sessionId: string) {
return {
type: "session",
@@ -170,207 +153,126 @@ function listBackupDirs(): string[] {
: [];
}
function writeFeishuDedupState(contents: string): void {
const target = path.join(stateDir(), "feishu", "dedup", "default.json");
fs.mkdirSync(path.dirname(target), { recursive: true });
fs.writeFileSync(target, contents);
}
async function runDoctor(shouldRepair: boolean, cfg: OpenClawConfig = feishuConfig()) {
return await runFeishuDoctorSequence({ cfg, env: process.env, shouldRepair });
}
describe("Feishu doctor state repair", () => {
let envSnapshot: EnvSnapshot;
let tempHome = "";
beforeEach(() => {
envSnapshot = captureEnv();
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-feishu-doctor-"));
process.env.HOME = tempHome;
process.env.OPENCLAW_HOME = tempHome;
process.env.OPENCLAW_STATE_DIR = path.join(tempHome, ".openclaw");
fs.mkdirSync(process.env.OPENCLAW_STATE_DIR, { recursive: true, mode: 0o700 });
vi.stubEnv("HOME", tempHome);
vi.stubEnv("OPENCLAW_HOME", tempHome);
vi.stubEnv("OPENCLAW_STATE_DIR", path.join(tempHome, ".openclaw"));
fs.mkdirSync(stateDir(), { recursive: true, mode: 0o700 });
});
afterEach(() => {
restoreEnv(envSnapshot);
vi.unstubAllEnvs();
fs.rmSync(tempHome, { recursive: true, force: true });
});
it("stays quiet for healthy Feishu state and transcripts", async () => {
const feishuDedupDir = path.join(stateDir(), "feishu", "dedup");
fs.mkdirSync(feishuDedupDir, { recursive: true });
fs.writeFileSync(path.join(feishuDedupDir, "default.json"), JSON.stringify({ msg1: 1 }));
const sessionKey = "agent:main:feishu:direct:ou_user";
const targetStorePath = await writeStore({
[sessionKey]: {
sessionId: "sess-ok",
updatedAt: Date.now(),
const healthyStateCases = [
{
name: "stays quiet for healthy Feishu state and transcripts",
arrange: async () => {
writeFeishuDedupState(JSON.stringify({ msg1: 1 }));
await seedSession({ sessionId: "sess-ok", contents: ["hello"] });
return feishuConfig();
},
});
await seedTranscriptMessages({
sessionId: "sess-ok",
sessionKey,
storePath: targetStorePath,
contents: ["hello"],
});
},
{
name: "keeps custom-store sessions with canonical transcript events",
arrange: async () => {
const customStorePath = path.join(stateDir(), "custom-sessions", "sessions.json");
await seedSession({
sessionId: "sess-abs",
storePath: customStorePath,
contents: ["hello"],
});
return {
...feishuConfig(),
session: { store: customStorePath },
} as OpenClawConfig;
},
},
{
name: "does not fall back to legacy files for canonical Feishu session rows",
arrange: async () => {
await seedSession({
sessionId: "sess-sqlite",
entry: { sessionFile: "missing-legacy-transcript.jsonl" },
});
return feishuConfig();
},
},
];
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: false,
});
it.each(healthyStateCases)("$name", async ({ arrange }) => {
const result = await runDoctor(false, await arrange());
expect(result).toEqual({ changeNotes: [], warningNotes: [] });
});
it("keeps custom-store sessions with canonical transcript events", async () => {
const customStorePath = path.join(stateDir(), "custom-sessions", "sessions.json");
const sessionKey = "agent:main:feishu:direct:ou_user";
await upsertSessionEntry({
agentId: "main",
storePath: customStorePath,
sessionKey,
entry: {
sessionId: "sess-abs",
updatedAt: Date.now(),
const repairSessionCases = [
{
name: "repairs SQLite-backed Feishu sessions with repeated blank user messages",
arrange: async () =>
await seedSession({
sessionId: "sess-sqlite-blank",
sessionKey: "agent:main:feishu:direct:ou_sqlite_blank",
contents: blankUserMessages,
}),
verifyTranscript: true,
},
{
name: "repairs SQLite-backed Feishu sessions with corrupt transcript rows",
arrange: async () => {
const session = await seedSession({
sessionId: "sess-sqlite-corrupt",
sessionKey: "agent:main:feishu:direct:ou_sqlite_corrupt",
contents: ["bad row follows"],
});
corruptTranscriptEventJson(session.agentId, session.sessionId);
return session;
},
});
await seedTranscriptMessages({
sessionId: "sess-abs",
sessionKey,
storePath: customStorePath,
contents: ["hello"],
});
verifyTranscript: false,
},
];
const result = await runFeishuDoctorSequence({
cfg: {
...feishuConfig(),
session: { store: customStorePath },
} as OpenClawConfig,
env: process.env,
shouldRepair: false,
});
expect(result).toEqual({ changeNotes: [], warningNotes: [] });
});
it("does not fall back to legacy files for canonical Feishu session rows", async () => {
await writeStore({
"agent:main:feishu:direct:ou_user": {
sessionId: "sess-sqlite",
sessionFile: "missing-legacy-transcript.jsonl",
updatedAt: Date.now(),
},
});
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: false,
});
expect(result).toEqual({ changeNotes: [], warningNotes: [] });
});
it("repairs SQLite-backed Feishu sessions with repeated blank user messages", async () => {
const targetStorePath = storePath();
const sessionKey = "agent:main:feishu:direct:ou_sqlite_blank";
const sessionId = "sess-sqlite-blank";
await upsertSessionEntry({
agentId: "main",
storePath: targetStorePath,
sessionKey,
entry: {
sessionId,
updatedAt: Date.now(),
},
});
await seedTranscriptMessages({
sessionId,
sessionKey,
storePath: targetStorePath,
contents: ["", "", ""],
});
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: true,
});
it.each(repairSessionCases)("$name", async ({ arrange, verifyTranscript }) => {
const session = await arrange();
const result = await runDoctor(true);
expect(result.warningNotes).toEqual([]);
expect(result.changeNotes.join("\n")).toContain("Removed 1 Feishu-scoped session entry");
expect(readStoreEntries(targetStorePath)[sessionKey]).toBeUndefined();
await expect(
readSessionTranscriptEvents({
agentId: "main",
sessionId,
sessionKey,
storePath: targetStorePath,
}),
).resolves.toEqual([]);
});
it("repairs SQLite-backed Feishu sessions with corrupt transcript rows", async () => {
const targetStorePath = storePath();
const sessionKey = "agent:main:feishu:direct:ou_sqlite_corrupt";
const sessionId = "sess-sqlite-corrupt";
await upsertSessionEntry({
agentId: "main",
storePath: targetStorePath,
sessionKey,
entry: {
sessionId,
updatedAt: Date.now(),
},
});
await appendSessionTranscriptMessageByIdentity({
agentId: "main",
sessionId,
sessionKey,
storePath: targetStorePath,
message: { role: "user", content: "bad row follows" },
});
corruptTranscriptEventJson("main", sessionId);
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: true,
});
expect(result.warningNotes).toEqual([]);
expect(result.changeNotes.join("\n")).toContain("Removed 1 Feishu-scoped session entry");
expect(readStoreEntries(targetStorePath)[sessionKey]).toBeUndefined();
expect(readStoreEntries(session.storePath)[session.sessionKey]).toBeUndefined();
if (verifyTranscript) {
await expect(readSessionTranscriptEvents(session)).resolves.toEqual([]);
}
});
it("keeps Feishu sessions with separated blank user messages", async () => {
const sessionKey = "agent:main:feishu:direct:ou_user";
const targetStorePath = await writeStore({
[sessionKey]: {
sessionId: "sess-separated-blanks",
updatedAt: Date.now(),
},
});
await seedTranscriptMessages({
await seedSession({
sessionId: "sess-separated-blanks",
sessionKey,
storePath: targetStorePath,
contents: ["", "hello", "", "world", ""],
});
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: false,
});
const result = await runDoctor(false);
expect(result).toEqual({ changeNotes: [], warningNotes: [] });
});
it("warns before repair when Feishu local state is corrupt", async () => {
const feishuDedupDir = path.join(stateDir(), "feishu", "dedup");
fs.mkdirSync(feishuDedupDir, { recursive: true });
fs.writeFileSync(path.join(feishuDedupDir, "default.json"), "{");
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: false,
});
writeFeishuDedupState("{");
const result = await runDoctor(false);
expect(result.changeNotes).toEqual([]);
expect(result.warningNotes.join("\n")).toContain("Feishu local channel state may need repair");
@@ -379,44 +281,21 @@ describe("Feishu doctor state repair", () => {
});
it("rebuilds corrupt Feishu state without deleting healthy Feishu sessions", async () => {
const feishuDedupDir = path.join(stateDir(), "feishu", "dedup");
fs.mkdirSync(feishuDedupDir, { recursive: true });
fs.writeFileSync(path.join(feishuDedupDir, "default.json"), "{");
const sessionKey = "agent:main:feishu:direct:ou_user";
const targetStorePath = await writeStore({
[sessionKey]: {
sessionId: "sess-ok",
updatedAt: Date.now(),
},
});
await seedTranscriptMessages({
writeFeishuDedupState("{");
const session = await seedSession({
sessionId: "sess-ok",
sessionKey,
storePath: targetStorePath,
contents: ["hello"],
});
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: true,
});
const result = await runDoctor(true);
expect(result.warningNotes).toEqual([]);
expect(result.changeNotes.join("\n")).toContain("Rebuilt Feishu runtime state: yes");
expect(result.changeNotes.join("\n")).toContain("Removed 0 Feishu-scoped session entries");
const store = readStoreEntries(targetStorePath);
expect(store[sessionKey]).toBeDefined();
await expect(
readSessionTranscriptEvents({
agentId: "main",
sessionId: "sess-ok",
sessionKey,
storePath: targetStorePath,
}),
).resolves.toHaveLength(2);
const store = readStoreEntries(session.storePath);
expect(store[session.sessionKey]).toBeDefined();
await expect(readSessionTranscriptEvents(session)).resolves.toHaveLength(2);
expect(fs.existsSync(path.join(stateDir(), "feishu"))).toBe(true);
expect(fs.existsSync(path.join(stateDir(), "feishu", "dedup", "default.json"))).toBe(false);
@@ -431,11 +310,8 @@ describe("Feishu doctor state repair", () => {
});
it("removes only unhealthy Feishu direct sessions while preserving state, config, and other sessions", async () => {
const feishuDedupDir = path.join(stateDir(), "feishu", "dedup");
fs.mkdirSync(feishuDedupDir, { recursive: true });
fs.writeFileSync(path.join(feishuDedupDir, "default.json"), JSON.stringify({ msg1: 1 }));
writeFeishuDedupState(JSON.stringify({ msg1: 1 }));
const sessionKey = "agent:main:feishu:direct:ou_user";
const acpTranscriptPath = writeLegacyTranscript("sess-acp-bad", [
sessionHeader("sess-acp-bad"),
userMessage(""),
@@ -443,22 +319,22 @@ describe("Feishu doctor state repair", () => {
userMessage(""),
]);
const targetStorePath = await writeStore({
[sessionKey]: {
sessionId: "sess-bad",
updatedAt: Date.now(),
},
"agent:main:discord:direct:user": {
const session = await seedSession({
sessionId: "sess-bad",
contents: blankUserMessages,
});
const targetStorePath = session.storePath;
fs.mkdirSync(path.dirname(targetStorePath), { recursive: true });
fs.writeFileSync(targetStorePath, "{}");
await upsertSessionEntry({
agentId: defaultAgentId,
storePath: targetStorePath,
sessionKey: "agent:main:discord:direct:user",
entry: {
sessionId: "sess-discord",
updatedAt: Date.now(),
},
});
await seedTranscriptMessages({
sessionId: "sess-bad",
sessionKey,
storePath: targetStorePath,
contents: ["", "", ""],
});
insertRawSessionEntry("agent:codex:acp:binding:feishu:default:abc123", {
sessionId: "sess-acp-bad",
sessionFile: "sess-acp-bad.jsonl",
@@ -468,11 +344,7 @@ describe("Feishu doctor state repair", () => {
}),
});
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: true,
});
const result = await runDoctor(true);
expect(result.warningNotes).toEqual([]);
expect(result.changeNotes.join("\n")).toContain("Feishu local state repaired");
@@ -494,24 +366,16 @@ describe("Feishu doctor state repair", () => {
).toBe(true);
const store = readStoreEntries(targetStorePath);
expect(store[sessionKey]).toBeUndefined();
expect(store[defaultFeishuSessionKey]).toBeUndefined();
expect(store["agent:codex:acp:binding:feishu:default:abc123"]).toBeDefined();
expect(store["agent:main:discord:direct:user"]).toBeDefined();
expect(fs.existsSync(acpTranscriptPath)).toBe(true);
await expect(
readSessionTranscriptEvents({
agentId: "main",
sessionId: "sess-bad",
sessionKey,
storePath: targetStorePath,
}),
).resolves.toEqual([]);
await expect(readSessionTranscriptEvents(session)).resolves.toEqual([]);
});
it("preserves locked harness sessions while repairing ordinary Feishu sessions", async () => {
const targetStorePath = storePath();
const feishuSessionKey = "agent:main:feishu:direct:ou_user";
await upsertSessionEntry({
agentId: "main",
storePath: targetStorePath,
@@ -526,62 +390,71 @@ describe("Feishu doctor state repair", () => {
updatedAt: 1,
},
});
await upsertSessionEntry({
agentId: "main",
storePath: targetStorePath,
sessionKey: feishuSessionKey,
entry: {
sessionId: "sess-feishu-bad",
updatedAt: 1,
},
});
await seedTranscriptMessages({
await seedSession({
sessionId: "sess-feishu-bad",
sessionKey: feishuSessionKey,
storePath: targetStorePath,
contents: ["", "", ""],
entry: { updatedAt: 1 },
contents: blankUserMessages,
});
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: true,
});
const result = await runDoctor(true);
expect(result.warningNotes).toEqual([]);
expect(result.changeNotes.join("\n")).toContain("Removed 1 Feishu-scoped session entry");
const store = readStoreEntries(targetStorePath);
expect(store["agent:main:ordinary-codex-locked"]).toBeDefined();
expect(store[feishuSessionKey]).toBeUndefined();
expect(store[defaultFeishuSessionKey]).toBeUndefined();
});
it("backs up SQLite session stores before removing migrated Feishu sessions", async () => {
const targetStorePath = storePath();
const sessionKey = "agent:main:feishu:direct:ou_migrated";
await upsertSessionEntry({
agentId: "main",
storePath: targetStorePath,
sessionKey,
entry: {
sessionId: "sess-migrated-bad",
updatedAt: Date.now(),
const sessionBackupCases = [
{
name: "backs up SQLite session stores before removing migrated Feishu sessions",
arrange: async () => {
const session = await seedSession({
sessionId: "sess-migrated-bad",
sessionKey: "agent:main:feishu:direct:ou_migrated",
contents: blankUserMessages,
});
return {
cfg: feishuConfig(),
session,
sqlitePath: sqliteStorePath(),
verifyTranscript: false,
};
},
});
await seedTranscriptMessages({
sessionId: "sess-migrated-bad",
sessionKey,
storePath: targetStorePath,
contents: ["", "", ""],
});
},
{
name: "backs up and repairs Feishu sessions in an agent-scoped custom SQLite store",
arrange: async () => {
const agentId = "support";
const customStorePath = path.join(stateDir(), "custom-sessions", "sessions.json");
const session = await seedSession({
agentId,
sessionId: "sess-support-bad",
sessionKey: "agent:support:feishu:direct:ou_migrated",
storePath: customStorePath,
contents: blankUserMessages,
});
return {
cfg: {
...feishuConfig(),
agents: { list: [{ id: agentId, default: true }] },
session: { store: customStorePath },
} as OpenClawConfig,
session,
sqlitePath: path.join(path.dirname(customStorePath), "openclaw-agent.support.sqlite"),
verifyTranscript: true,
};
},
},
];
expect(fs.existsSync(targetStorePath)).toBe(false);
expect(fs.existsSync(sqliteStorePath())).toBe(true);
it.each(sessionBackupCases)("$name", async ({ arrange }) => {
const { cfg, session, sqlitePath, verifyTranscript } = await arrange();
expect(fs.existsSync(session.storePath)).toBe(false);
expect(fs.existsSync(sqlitePath)).toBe(true);
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: true,
});
const result = await runDoctor(true, cfg);
expect(result.warningNotes).toEqual([]);
expect(result.changeNotes.join("\n")).toContain("Removed 1 Feishu-scoped session entry");
@@ -589,118 +462,48 @@ describe("Feishu doctor state repair", () => {
const backups = listBackupDirs();
expect(backups).toHaveLength(1);
const backupDir = path.join(stateDir(), "backups", backups[0] ?? "");
expect(fs.existsSync(path.join(backupDir, "session-stores", "main", "sessions.json"))).toBe(
false,
);
expect(
fs.existsSync(path.join(backupDir, "session-stores", "main", "openclaw-agent.sqlite")),
).toBe(true);
expect(readStoreEntries(targetStorePath)[sessionKey]).toBeUndefined();
});
it("backs up and repairs Feishu sessions in an agent-scoped custom SQLite store", async () => {
const customStorePath = path.join(stateDir(), "custom-sessions", "sessions.json");
const customSqlitePath = path.join(
path.dirname(customStorePath),
"openclaw-agent.support.sqlite",
);
const sessionKey = "agent:support:feishu:direct:ou_migrated";
await upsertSessionEntry({
agentId: "support",
storePath: customStorePath,
sessionKey,
entry: {
sessionId: "sess-support-bad",
updatedAt: Date.now(),
},
});
await seedTranscriptMessages({
agentId: "support",
sessionId: "sess-support-bad",
sessionKey,
storePath: customStorePath,
contents: ["", "", ""],
});
expect(fs.existsSync(customStorePath)).toBe(false);
expect(fs.existsSync(customSqlitePath)).toBe(true);
const result = await runFeishuDoctorSequence({
cfg: {
...feishuConfig(),
agents: { list: [{ id: "support", default: true }] },
session: { store: customStorePath },
} as OpenClawConfig,
env: process.env,
shouldRepair: true,
});
expect(result.warningNotes).toEqual([]);
expect(result.changeNotes.join("\n")).toContain("Removed 1 Feishu-scoped session entry");
const backups = listBackupDirs();
expect(backups).toHaveLength(1);
const backupDir = path.join(stateDir(), "backups", backups[0] ?? "");
expect(fs.existsSync(path.join(backupDir, "session-stores", "support", "sessions.json"))).toBe(
false,
);
fs.existsSync(path.join(backupDir, "session-stores", session.agentId, "sessions.json")),
).toBe(false);
expect(
fs.existsSync(
path.join(backupDir, "session-stores", "support", "openclaw-agent.support.sqlite"),
path.join(backupDir, "session-stores", session.agentId, path.basename(sqlitePath)),
),
).toBe(true);
expect(readStoreEntries(customStorePath, "support")[sessionKey]).toBeUndefined();
await expect(
readSessionTranscriptEvents({
agentId: "support",
sessionId: "sess-support-bad",
sessionKey,
storePath: customStorePath,
}),
).resolves.toEqual([]);
expect(
readStoreEntries(session.storePath, session.agentId)[session.sessionKey],
).toBeUndefined();
if (verifyTranscript) {
await expect(readSessionTranscriptEvents(session)).resolves.toEqual([]);
}
});
it("archives unhealthy default-scope sessions when metadata identifies Feishu", async () => {
const sessionKey = "agent:main:main";
const targetStorePath = await writeStore({
[sessionKey]: {
sessionId: "sess-default-feishu-bad",
updatedAt: Date.now(),
const session = await seedSession({
sessionId: "sess-default-feishu-bad",
sessionKey: "agent:main:main",
entry: {
origin: { provider: "feishu", from: "feishu:ou_user" },
route: { channel: "feishu", target: { to: "ou_user", chatType: "direct" } },
},
"agent:main:main-non-feishu": {
sessionId: "sess-other",
updatedAt: Date.now(),
contents: blankUserMessages,
});
await seedSession({
sessionId: "sess-other",
storePath: session.storePath,
sessionKey: "agent:main:main-non-feishu",
entry: {
origin: { provider: "discord" },
},
});
await seedTranscriptMessages({
sessionId: "sess-default-feishu-bad",
sessionKey,
storePath: targetStorePath,
contents: ["", "", ""],
});
const result = await runFeishuDoctorSequence({
cfg: feishuConfig(),
env: process.env,
shouldRepair: true,
});
const result = await runDoctor(true);
expect(result.warningNotes).toEqual([]);
const store = readStoreEntries(targetStorePath);
expect(store[sessionKey]).toBeUndefined();
const store = readStoreEntries(session.storePath);
expect(store[session.sessionKey]).toBeUndefined();
expect(store["agent:main:main-non-feishu"]).toBeDefined();
await expect(
readSessionTranscriptEvents({
agentId: "main",
sessionId: "sess-default-feishu-bad",
sessionKey,
storePath: targetStorePath,
}),
).resolves.toEqual([]);
await expect(readSessionTranscriptEvents(session)).resolves.toEqual([]);
});
});