@@ -4,6 +4,7 @@ import os from "node:os";
44import nodePath from "node:path" ;
55import { afterEach , beforeEach , describe , expect , it , vi } from "vitest" ;
66import type { DoctorPrompter } from "../commands/doctor-prompter.js" ;
7+ import type { OpenClawConfig } from "../config/types.openclaw.js" ;
78import { CORE_HEALTH_CHECKS } from "./doctor-core-checks.js" ;
89import "./doctor-tool-result-cap-advice.js" ;
910import {
@@ -1331,6 +1332,44 @@ describe("doctor health contributions", () => {
13311332 } ) ;
13321333 } ) ;
13331334
1335+ it ( "keeps default-account routing lint opt-in" , async ( ) => {
1336+ const contribution = requireDoctorContribution ( "doctor:default-account-routing" ) ;
1337+ const check = contribution . healthChecks [ 0 ] as HealthCheck | undefined ;
1338+ expect ( check ) . toMatchObject ( { defaultEnabled : false } ) ;
1339+
1340+ const ctx = {
1341+ cfg : {
1342+ channels : {
1343+ telegram : {
1344+ accounts : {
1345+ alerts : { } ,
1346+ work : { } ,
1347+ } ,
1348+ } ,
1349+ } ,
1350+ bindings : [ { agentId : "ops" , match : { channel : "telegram" } } ] ,
1351+ } as unknown as OpenClawConfig ,
1352+ mode : "lint" as const ,
1353+ runtime : { log : vi . fn ( ) , error : vi . fn ( ) , exit : vi . fn ( ) } ,
1354+ } ;
1355+
1356+ await expect ( runDoctorLintChecks ( ctx , { checks : [ check ! ] } ) ) . resolves . toMatchObject ( {
1357+ checksRun : 0 ,
1358+ checksSkipped : 1 ,
1359+ findings : [ ] ,
1360+ } ) ;
1361+ await expect (
1362+ runDoctorLintChecks ( ctx , { checks : [ check ! ] , includeAllChecks : true } ) ,
1363+ ) . resolves . toMatchObject ( {
1364+ checksRun : 1 ,
1365+ checksSkipped : 0 ,
1366+ findings : [
1367+ expect . objectContaining ( { checkId : "core/doctor/default-account-routing" } ) ,
1368+ expect . objectContaining ( { checkId : "core/doctor/default-account-routing" } ) ,
1369+ ] ,
1370+ } ) ;
1371+ } ) ;
1372+
13341373 it ( "preserves allow-exec Gateway SecretRef resolution in auth health" , async ( ) => {
13351374 const contribution = requireDoctorContribution ( "doctor:gateway-auth" ) ;
13361375 const ctx = {
@@ -2735,6 +2774,65 @@ describe("doctor health contributions", () => {
27352774 ) ;
27362775 } ) ;
27372776
2777+ it . each ( [ false , true ] ) (
2778+ "reports default-account routing warnings during doctor runs (repair=%s)" ,
2779+ async ( shouldRepair ) => {
2780+ const contribution = requireDoctorContribution ( "doctor:default-account-routing" ) ;
2781+ mocks . runDoctorHealthRepairs . mockImplementation ( async ( ctx , options ) => {
2782+ const findings = await options . checks [ 0 ] ! . detect ( ctx ) ;
2783+ return {
2784+ config : ctx . cfg ,
2785+ findings,
2786+ remainingFindings : findings ,
2787+ changes : [ ] ,
2788+ warnings : [ ] ,
2789+ diffs : [ ] ,
2790+ effects : [ ] ,
2791+ checksRun : 1 ,
2792+ checksRepaired : 0 ,
2793+ checksValidated : 1 ,
2794+ } ;
2795+ } ) ;
2796+ const ctx = {
2797+ cfg : {
2798+ channels : {
2799+ telegram : {
2800+ accounts : {
2801+ alerts : { } ,
2802+ work : { } ,
2803+ } ,
2804+ } ,
2805+ } ,
2806+ bindings : [ { agentId : "ops" , match : { channel : "telegram" } } ] ,
2807+ } as unknown as OpenClawConfig ,
2808+ configResult : { cfg : { } } ,
2809+ sourceConfigValid : true ,
2810+ prompter : buildDoctorPrompter ( shouldRepair ) ,
2811+ runtime : { log : vi . fn ( ) , error : vi . fn ( ) , exit : vi . fn ( ) } ,
2812+ options : { } ,
2813+ cfgForPersistence : { } ,
2814+ configPath : "/tmp/fake-openclaw.json" ,
2815+ env : { } ,
2816+ } as unknown as Parameters < ( typeof contribution ) [ "run" ] > [ 0 ] ;
2817+
2818+ await contribution . run ( ctx ) ;
2819+
2820+ expect ( mocks . runDoctorHealthRepairs ) . toHaveBeenCalledWith (
2821+ expect . objectContaining ( { mode : "fix" , dryRun : ! shouldRepair } ) ,
2822+ expect . objectContaining ( {
2823+ checks : contribution . healthChecks ,
2824+ dryRun : ! shouldRepair ,
2825+ } ) ,
2826+ ) ;
2827+ expect ( ctx . runtime . log ) . toHaveBeenCalledWith (
2828+ expect . stringContaining ( "accounts.default is missing and no valid account-scoped binding" ) ,
2829+ ) ;
2830+ expect ( ctx . runtime . log ) . toHaveBeenCalledWith (
2831+ expect . stringContaining ( "multiple accounts are configured but no explicit default is set" ) ,
2832+ ) ;
2833+ } ,
2834+ ) ;
2835+
27382836 it ( "skips doctor config writes under legacy update parents" , ( ) => {
27392837 expect (
27402838 shouldSkipLegacyUpdateDoctorConfigWrite ( {
0 commit comments