@@ -76,6 +76,8 @@ export namespace Server {
7676 // because a cache built before a background registration finished cannot be told apart from one
7777 // built after it, in any directory or either registry.
7878 let appliedBaseCredential : string | undefined
79+ // Serializes the register route's check-and-reload, so concurrent calls reload at most once.
80+ let baseReloadQueue : Promise < unknown > = Promise . resolve ( )
7981 // altimate_change end
8082
8183 export const Default = lazy ( ( ) => createApp ( { } ) )
@@ -781,15 +783,6 @@ export namespace Server {
781783 )
782784 }
783785
784- // altimate_change — Codex review finding: `FreeTier.register()` returns success whether
785- // it minted/rotated a credential OR just found an existing valid one (the idempotent
786- // fast path — see its "already registered" branch in free/client.ts). Everything below
787- // is instance-wide teardown that only matters when the credential on disk actually
788- // changed; comparing it before/after `gate.register()` (rather than changing
789- // `register()`'s own return shape, which every other caller — the picker, and a dozen
790- // existing tests — depends on as a plain `Credentials`) reports that without touching
791- // that contract.
792- const before = await FreeTier . credentials ( ) . catch ( ( ) => undefined )
793786 const gate = FreeTierConsent . createRegistrationGate ( {
794787 register : ( ) => FreeTier . register ( { origin : "server" } ) ,
795788 onUnexpectedError : ( error ) => log . error ( "Altimate Base registration failed" , { error } ) ,
@@ -815,45 +808,47 @@ export namespace Server {
815808 // A failure in either leaves the credential written but provider lists possibly stale, so
816809 // it is reported rather than swallowed: the client needs to know its picker may be wrong.
817810 //
818- // Skipped entirely when nothing changed: an idempotent register (already valid
819- // credentials for this gateway) has nothing for a provider loader to re-read, so tearing
820- // down every session, LSP, PTY, MCP connection and file watcher in the process would be
821- // pure disruption for zero benefit.
811+ // Skipped when this process has already reloaded for the credential now on disk: an
812+ // idempotent register (the "already registered" fast path) then has nothing for a
813+ // provider loader to re-read, and tearing down every session, LSP, PTY, MCP connection
814+ // and file watcher again would be pure disruption. An unchanged file alone is not enough:
815+ // a startup registration that finished in the background leaves caches built before it
816+ // without Base, in any directory and in either registry.
817+ //
818+ // The check and the reload run one at a time, so two concurrent calls cannot both pass
819+ // the check and dispose the same live resources twice; the second sees the first's mark.
822820 if ( outcome . ok ) {
823- const after = await FreeTier . credentials ( ) . catch ( ( ) => undefined )
824- // Identity covers everything that decides whether a loader sees Base: an expired or
825- // rejected credential loads as absent, and a logout elsewhere rotates the nonce, so the
826- // same key and URL reissued after either still has to reload.
827- const identity = ( value : typeof after ) =>
828- value
829- ? [ value . baseURL , value . apiKey , value . expiresAt ?? "" , value . rejected ? "rejected" : "" , value . logoutNonce ?? "" ] . join ( "\n" )
821+ const reload = baseReloadQueue . then ( async ( ) => {
822+ const current = await FreeTier . credentials ( ) . catch ( ( ) => undefined )
823+ // Identity covers everything that decides whether a loader sees Base: an expired or
824+ // rejected credential loads as absent, and a logout elsewhere rotates the nonce, so the
825+ // same key and URL reissued after either still has to reload.
826+ const fingerprint = current
827+ ? [ current . baseURL , current . apiKey , current . expiresAt ?? "" , current . rejected ? "rejected" : "" , current . logoutNonce ?? "" ] . join ( "\n" )
830828 : undefined
831- const fingerprint = identity ( after )
832- const changed = identity ( before ) !== fingerprint
833- // An unchanged file is not enough to skip: a startup registration that finished in the
834- // background leaves caches built before it without Base, in any directory and in either
835- // registry. Skip only when this process has already reloaded for this exact credential.
836- if ( ! changed && fingerprint !== undefined && fingerprint === appliedBaseCredential ) {
837- return c . json ( outcome )
838- }
839- const disposed = await Promise . all ( [
840- Instance . disposeAll ( ) . then (
841- ( ) => true ,
842- ( error ) => {
843- log . error ( "Altimate Base registered but legacy instance disposal failed" , { error } )
844- return false
845- } ,
846- ) ,
847- AppRuntime . runPromise ( InstanceStore . Service . use ( ( store ) => store . disposeAll ( ) ) ) . then (
848- ( ) => true ,
849- ( error ) => {
850- log . error ( "Altimate Base registered but InstanceStore disposal failed" , { error } )
851- return false
852- } ,
853- ) ,
854- ] ) . then ( ( results ) => results . every ( Boolean ) )
855- if ( disposed ) appliedBaseCredential = fingerprint
856- return c . json ( disposed ? outcome : { ...outcome , staleProviders : true as const } )
829+ if ( fingerprint !== undefined && fingerprint === appliedBaseCredential ) return true
830+ const disposed = await Promise . all ( [
831+ Instance . disposeAll ( ) . then (
832+ ( ) => true ,
833+ ( error ) => {
834+ log . error ( "Altimate Base registered but legacy instance disposal failed" , { error } )
835+ return false
836+ } ,
837+ ) ,
838+ AppRuntime . runPromise ( InstanceStore . Service . use ( ( store ) => store . disposeAll ( ) ) ) . then (
839+ ( ) => true ,
840+ ( error ) => {
841+ log . error ( "Altimate Base registered but InstanceStore disposal failed" , { error } )
842+ return false
843+ } ,
844+ ) ,
845+ ] ) . then ( ( results ) => results . every ( Boolean ) )
846+ if ( disposed ) appliedBaseCredential = fingerprint
847+ return disposed
848+ } )
849+ baseReloadQueue = reload . catch ( ( ) => undefined )
850+ const reloaded = await reload
851+ return c . json ( reloaded ? outcome : { ...outcome , staleProviders : true as const } )
857852 }
858853 return c . json ( outcome )
859854 } ,
0 commit comments