fix(bar): keep is_default on cache-fallback rows

The collector cached each row before the default profile was resolved, so the
cache-fallback path (getCachedNativeAccountRows) served the default account with
is_default:false -- the UI then lost default ordering/tagging when /summary
served from cache. Write the resolved default flag back onto the cached copy so
the fallback stays consistent with a fresh collection.
This commit is contained in:
Tam Nhu Tran committed 2026-06-24 00:03:20 -04:00
1 parent f57eed8c34
commit 7b610f0e82
2 files changed
+50 -2

No files matched your search

+22 -2
View File
@@ -669,6 +669,26 @@ function markDefault(row: BarSummaryRow, isDefault: boolean): BarSummaryRow {
return { ...row, is_default: isDefault };
}
/**
* Tag the row with is_default AND write the flag back onto the cached copy. The
* collector caches a row before the default profile is known (the default is
* resolved in the enumerator), so without this the cache-fallback path
* (getCachedNativeAccountRows) would serve the default account with
* is_default:false and the UI would stop ordering/tagging it as the default.
*/
function markDefaultAndSyncCache(
map: Map<string, ProviderState>,
profile: string,
row: BarSummaryRow,
isDefault: boolean
): BarSummaryRow {
const state = map.get(profile);
if (state?.cachedRow) {
state.cachedRow = { ...state.cachedRow, is_default: isDefault };
}
return markDefault(row, isDefault);
}
async function collectClaudeRowForProfile(
profile: string,
deps: NativeQuotaDeps,
@@ -1453,7 +1473,7 @@ async function getNativeAccountRowsMultiProfile(
const isDefault = p === claudeDefault;
tasks.push(
collectClaudeRowForProfile(p, deps, force)
.then((r) => (r ? markDefault(r, isDefault) : null))
.then((r) => (r ? markDefaultAndSyncCache(claudeProfileStates, p, r, isDefault) : null))
.catch(() => null)
);
}
@@ -1462,7 +1482,7 @@ async function getNativeAccountRowsMultiProfile(
const isDefault = p === codexDefault;
tasks.push(
collectCodexRowForProfile(p, deps, force)
.then((r) => (r ? markDefault(r, isDefault) : null))
.then((r) => (r ? markDefaultAndSyncCache(codexProfileStates, p, r, isDefault) : null))
.catch(() => null)
);
}
@@ -1306,4 +1306,32 @@ describe('review focus areas: reauth caching + codex local fallback', () => {
expect(localCalls).toBe(1);
expect(def?.quotaStatus).not.toBe('unsupported');
});
it('cache-fallback rows keep is_default for the default profile', async () => {
resetNativeQuotaState();
const clock = { now: 6_000_000 };
const deps = makeMultiProfileDeps({
clock,
claudeProfiles: ['work', 'ck'],
codexProfiles: ['default', 'ck'],
claudeDefault: 'work',
codexDefault: 'default',
credsForProfile: () => maxCreds(),
claudeFetch: async () => successQuota(),
codexNativeAuth: (p) => ({ accessToken: `t-${p}`, accountId: `id-${p}` }),
codexNetworkFetch: async () => codexSuccessQuota(),
});
await getNativeAccountRows(deps); // populate the per-profile caches
// The cache-fallback path must preserve is_default so the UI still orders and
// tags the default account when /summary serves from cache.
const cached = getCachedNativeAccountRows();
expect(cached.find((r) => r.surface === 'ccs' && r.profile === 'work')?.is_default).toBe(true);
expect(cached.find((r) => r.surface === 'ccsx' && r.profile === 'default')?.is_default).toBe(
true
);
expect(cached.find((r) => r.surface === 'ccs' && r.profile === 'ck')?.is_default).toBe(false);
expect(cached.find((r) => r.surface === 'ccsx' && r.profile === 'ck')?.is_default).toBe(false);
});
});