11import { describe , expect , it } from "vitest" ;
2+ import type { SessionEntry } from "../config/sessions.js" ;
23import {
34 applySessionRouteStateRepair ,
45 resolveConfiguredDoctorSessionStateRoute ,
@@ -15,6 +16,15 @@ const codexOwner = {
1516 authProfilePrefixes : [ "codex:" , "codex-cli:" , "openai-codex:" ] ,
1617} ;
1718
19+ const anthropicOwner = {
20+ id : "anthropic" ,
21+ label : "Anthropic" ,
22+ providerIds : [ "anthropic" , "claude-cli" ] ,
23+ runtimeIds : [ "claude-cli" ] ,
24+ cliSessionKeys : [ "claude-cli" ] ,
25+ authProfilePrefixes : [ "anthropic:" , "claude-cli:" ] ,
26+ } ;
27+
1828describe ( "doctor session state provider routes" , ( ) => {
1929 it ( "skips plugin route-state scans for unrelated recovery metadata" , ( ) => {
2030 expect (
@@ -103,6 +113,7 @@ describe("doctor session state provider routes", () => {
103113 fallbackNoticeActiveModel : "openai-codex/gpt-5.4" ,
104114 fallbackNoticeReason : "rate-limit" ,
105115 agentHarnessId : "codex" ,
116+ agentRuntimeOverride : "codex-cli" ,
106117 authProfileOverride : "openai-codex:default" ,
107118 authProfileOverrideSource : "auto" ,
108119 authProfileOverrideCompactionCount : 2 ,
@@ -162,6 +173,7 @@ describe("doctor session state provider routes", () => {
162173 expect ( entry . contextTokens ) . toBeUndefined ( ) ;
163174 expect ( entry . systemPromptReport ) . toBeUndefined ( ) ;
164175 expect ( entry . agentHarnessId ) . toBeUndefined ( ) ;
176+ expect ( entry . agentRuntimeOverride ) . toBeUndefined ( ) ;
165177 expect ( entry . authProfileOverride ) . toBeUndefined ( ) ;
166178 expect ( entry . authProfileOverrideSource ) . toBeUndefined ( ) ;
167179 expect ( entry . authProfileOverrideCompactionCount ) . toBeUndefined ( ) ;
@@ -263,4 +275,70 @@ describe("doctor session state provider routes", () => {
263275
264276 expect ( scan ) . toEqual ( { repairs : [ ] , manualReview : [ ] } ) ;
265277 } ) ;
278+
279+ it ( "clears stale runtime override-only pins when the owner is no longer configured" , ( ) => {
280+ const sessionKey = "agent:main:telegram:direct:claude-stale" ;
281+ const entry : SessionEntry & Record < string , unknown > = {
282+ sessionId : "sess-stale-claude-cli" ,
283+ updatedAt : 1 ,
284+ agentRuntimeOverride : "claude-cli" ,
285+ } ;
286+
287+ expect ( storeMayContainPluginSessionRouteState ( { [ sessionKey ] : entry } ) ) . toBe ( true ) ;
288+
289+ const scan = scanSessionRouteStateOwners ( {
290+ owners : [ anthropicOwner ] ,
291+ store : { [ sessionKey ] : entry } ,
292+ routes : {
293+ [ sessionKey ] : {
294+ defaultProvider : "openai" ,
295+ configuredModelRefs : [ "openai/gpt-5.5" ] ,
296+ runtime : "pi" ,
297+ } ,
298+ } ,
299+ } ) ;
300+
301+ expect ( scan ) . toEqual ( {
302+ manualReview : [ ] ,
303+ repairs : [
304+ {
305+ key : sessionKey ,
306+ ownerId : "anthropic" ,
307+ ownerLabel : "Anthropic" ,
308+ cliSessionKeys : [ "claude-cli" ] ,
309+ reasons : [ "pinned runtime" ] ,
310+ } ,
311+ ] ,
312+ } ) ;
313+
314+ expect ( applySessionRouteStateRepair ( { entry, repair : scan . repairs [ 0 ] , now : 456 } ) ) . toBe ( true ) ;
315+ expect ( entry ) . toStrictEqual ( {
316+ sessionId : "sess-stale-claude-cli" ,
317+ updatedAt : 456 ,
318+ } ) ;
319+ } ) ;
320+
321+ it ( "keeps runtime override-only pins when the owner runtime is still configured" , ( ) => {
322+ const sessionKey = "agent:main:telegram:direct:claude-current" ;
323+ const entry : Record < string , unknown > = {
324+ sessionId : "sess-current-claude-cli" ,
325+ updatedAt : 1 ,
326+ agentRuntimeOverride : "claude-cli" ,
327+ } ;
328+
329+ const scan = scanSessionRouteStateOwners ( {
330+ owners : [ anthropicOwner ] ,
331+ store : { [ sessionKey ] : entry } ,
332+ routes : {
333+ [ sessionKey ] : {
334+ defaultProvider : "anthropic" ,
335+ configuredModelRefs : [ "anthropic/claude-sonnet-4-6" ] ,
336+ runtime : "claude-cli" ,
337+ } ,
338+ } ,
339+ } ) ;
340+
341+ expect ( scan ) . toEqual ( { repairs : [ ] , manualReview : [ ] } ) ;
342+ expect ( entry . agentRuntimeOverride ) . toBe ( "claude-cli" ) ;
343+ } ) ;
266344} ) ;
0 commit comments