Skip to content

Commit ea60bc0

Browse files
committed
refactor(config): drop stale legacy migrations
1 parent 10527ff commit ea60bc0

9 files changed

Lines changed: 91 additions & 1390 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Docs: https://docs.openclaw.ai
77
### Breaking
88

99
- Providers/Qwen: remove the deprecated `qwen-portal-auth` OAuth integration for `portal.qwen.ai`; migrate to Model Studio with `openclaw onboard --auth-choice modelstudio-api-key`. (#52709) Thanks @pomelo-nwu.
10+
- Config/Doctor: drop automatic config migrations older than two months; very old legacy keys now fail validation instead of being rewritten on load or by `openclaw doctor`.
1011

1112
### Changes
1213

src/commands/doctor.migrates-routing-allowfrom-channels-whatsapp-allowfrom.test.ts

Lines changed: 0 additions & 120 deletions
This file was deleted.

src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts

Lines changed: 33 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import fs from "node:fs/promises";
22
import path from "node:path";
33
import { describe, expect, it, vi } from "vitest";
4-
import { resolveAgentModelFallbackValues, resolveAgentModelPrimaryValue } from "./model-input.js";
54

65
const { loadConfig, migrateLegacyConfig, readConfigFileSnapshot, validateConfigObject } =
76
await vi.importActual<typeof import("./config.js")>("./config.js");
@@ -64,18 +63,15 @@ function expectInvalidIssuePath(config: unknown, expectedPath: string) {
6463
}
6564
}
6665

67-
function expectRoutingAllowFromLegacySnapshot(
66+
function expectSnapshotInvalidRootKey(
6867
ctx: { snapshot: ConfigSnapshot; parsed: unknown },
69-
expectedAllowFrom: string[],
68+
key: string,
7069
) {
71-
expect(ctx.snapshot.valid).toBe(true);
72-
expect(ctx.snapshot.legacyIssues.some((issue) => issue.path === "routing.allowFrom")).toBe(true);
73-
const parsed = ctx.parsed as {
74-
routing?: { allowFrom?: string[] };
75-
channels?: unknown;
76-
};
77-
expect(parsed.routing?.allowFrom).toEqual(expectedAllowFrom);
78-
expect(parsed.channels).toBeUndefined();
70+
expect(ctx.snapshot.valid).toBe(false);
71+
expect(ctx.snapshot.legacyIssues).toEqual([]);
72+
expect(ctx.snapshot.issues[0]?.path).toBe("");
73+
expect(ctx.snapshot.issues[0]?.message).toContain(`"${key}"`);
74+
expect((ctx.parsed as Record<string, unknown>)[key]).toBeTruthy();
7975
}
8076

8177
describe("legacy config detection", () => {
@@ -207,30 +203,25 @@ describe("legacy config detection", () => {
207203
});
208204
expect(res.ok).toBe(false);
209205
if (!res.ok) {
210-
expect(res.issues.some((i) => i.path === "agent.model")).toBe(true);
206+
expect(res.issues[0]?.path).toBe("");
207+
expect(res.issues[0]?.message).toContain('"agent"');
211208
}
212209
});
213-
it("migrates telegram.requireMention to channels.telegram.groups.*.requireMention", async () => {
210+
it("does not rewrite removed telegram.requireMention migrations", async () => {
214211
const res = migrateLegacyConfig({
215212
telegram: { requireMention: false },
216213
});
217-
expect(res.changes).toContain(
218-
'Moved telegram.requireMention → channels.telegram.groups."*".requireMention.',
219-
);
220-
expect(res.config?.channels?.telegram?.groups?.["*"]?.requireMention).toBe(false);
221-
expect(
222-
(res.config?.channels?.telegram as { requireMention?: boolean } | undefined)?.requireMention,
223-
).toBeUndefined();
214+
expect(res.changes).toEqual([]);
215+
expect(res.config).toBeNull();
224216
});
225-
it("migrates messages.tts.enabled to messages.tts.auto", async () => {
217+
it("does not rewrite removed messages.tts.enabled migrations", async () => {
226218
const res = migrateLegacyConfig({
227219
messages: { tts: { enabled: true } },
228220
});
229-
expect(res.changes).toContain("Moved messages.tts.enabled → messages.tts.auto (always).");
230-
expect(res.config?.messages?.tts?.auto).toBe("always");
231-
expect(res.config?.messages?.tts?.enabled).toBeUndefined();
221+
expect(res.changes).toEqual([]);
222+
expect(res.config).toBeNull();
232223
});
233-
it("migrates legacy model config to agent.models + model lists", async () => {
224+
it("does not rewrite removed legacy model config migrations", async () => {
234225
const res = migrateLegacyConfig({
235226
agent: {
236227
model: "anthropic/claude-opus-4-5",
@@ -241,28 +232,12 @@ describe("legacy config detection", () => {
241232
modelAliases: { Opus: "anthropic/claude-opus-4-5" },
242233
},
243234
});
244-
245-
expect(resolveAgentModelPrimaryValue(res.config?.agents?.defaults?.model)).toBe(
246-
"anthropic/claude-opus-4-5",
247-
);
248-
expect(resolveAgentModelFallbackValues(res.config?.agents?.defaults?.model)).toEqual([
249-
"openai/gpt-4.1-mini",
250-
]);
251-
expect(resolveAgentModelPrimaryValue(res.config?.agents?.defaults?.imageModel)).toBe(
252-
"openai/gpt-4.1-mini",
253-
);
254-
expect(resolveAgentModelFallbackValues(res.config?.agents?.defaults?.imageModel)).toEqual([
255-
"anthropic/claude-opus-4-5",
256-
]);
257-
expect(res.config?.agents?.defaults?.models?.["anthropic/claude-opus-4-5"]).toMatchObject({
258-
alias: "Opus",
259-
});
260-
expect(res.config?.agents?.defaults?.models?.["openai/gpt-4.1-mini"]).toBeTruthy();
261-
expect((res.config as { agent?: unknown } | undefined)?.agent).toBeUndefined();
235+
expect(res.changes).toEqual([]);
236+
expect(res.config).toBeNull();
262237
});
263-
it("flags legacy config in snapshot", async () => {
238+
it("rejects removed routing.allowFrom in snapshot", async () => {
264239
await withSnapshotForConfig({ routing: { allowFrom: ["+15555550123"] } }, async (ctx) => {
265-
expectRoutingAllowFromLegacySnapshot(ctx, ["+15555550123"]);
240+
expectSnapshotInvalidRootKey(ctx, "routing");
266241
});
267242
});
268243
it("flags top-level memorySearch as legacy in snapshot", async () => {
@@ -283,17 +258,9 @@ describe("legacy config detection", () => {
283258
},
284259
);
285260
});
286-
it("flags legacy provider sections in snapshot", async () => {
261+
it("rejects removed legacy provider sections in snapshot", async () => {
287262
await withSnapshotForConfig({ whatsapp: { allowFrom: ["+1555"] } }, async (ctx) => {
288-
expect(ctx.snapshot.valid).toBe(true);
289-
expect(ctx.snapshot.legacyIssues.some((issue) => issue.path === "whatsapp")).toBe(true);
290-
291-
const parsed = ctx.parsed as {
292-
channels?: unknown;
293-
whatsapp?: unknown;
294-
};
295-
expect(parsed.channels).toBeUndefined();
296-
expect(parsed.whatsapp).toBeTruthy();
263+
expectSnapshotInvalidRootKey(ctx, "whatsapp");
297264
});
298265
});
299266
it("does not auto-migrate claude-cli auth profile mode on load", async () => {
@@ -326,9 +293,18 @@ describe("legacy config detection", () => {
326293
expect(parsed.auth?.profiles?.["anthropic:claude-cli"]?.mode).toBe("token");
327294
});
328295
});
329-
it("flags routing.allowFrom in snapshot", async () => {
296+
it("still flags memorySearch in snapshot under the shorter support window", async () => {
297+
await withSnapshotForConfig(
298+
{ memorySearch: { provider: "local", fallback: "none" } },
299+
async (ctx) => {
300+
expect(ctx.snapshot.valid).toBe(true);
301+
expect(ctx.snapshot.legacyIssues.some((issue) => issue.path === "memorySearch")).toBe(true);
302+
},
303+
);
304+
});
305+
it("rejects removed routing.allowFrom in snapshot with other values", async () => {
330306
await withSnapshotForConfig({ routing: { allowFrom: ["+1666"] } }, async (ctx) => {
331-
expectRoutingAllowFromLegacySnapshot(ctx, ["+1666"]);
307+
expectSnapshotInvalidRootKey(ctx, "routing");
332308
});
333309
});
334310
it("rejects bindings[].match.provider on load", async () => {

0 commit comments

Comments
 (0)