Repository navigation
Description
Area
apps/server — ProviderRegistry boot
Summary
On startup, ProviderRegistry hydrates each provider from the status cache (caches/<instanceId>.json), then immediately overwrites it with the pending initial snapshot. The cache never takes effect: every launch starts from installed: false, status: "warning", auth: unknown until the first probe finishes. The pending snapshot is also written back to the cache.
The visible symptom is the startup banner from #24527. #31732 changes the pending status to checking, which hides the banner, but the overwrite stays. The registry still reports a provider as not installed and unauthenticated for the first 1–3s of every launch, even though the correct state is on disk.
Cause
In the ProviderRegistry layer:
const fallbackProviders = yield* loadProviders(bootSources) // pending snapshots
const cachedProviders = /* hydrateCachedProvider(cache, fallback) */
const providersRef = yield* Ref.make(cachedProviders) // correct: status "ready"
// ...
yield* upsertProviders(fallbackProviders, { publish: false }) // overwrites it
yield* syncLiveSources // publishes the pending snapshotmergeProviderSnapshot(previous, next) takes status, auth, installed, version and message from next, so the hydrated values are dropped. Because persist isn't disabled, persistProvider also writes the pending snapshot to the cache file.
Steps to reproduce
- Use an enabled, authenticated provider (here: Claude) until it shows
ready. Confirmcaches/claudeAgent.jsonhas"status": "ready". - Quit and reopen T3 Code.
- A provider status warning ("Claude provider status has not been checked in this session yet.") shows until the probe completes.
Expected behavior
Boot state comes from the cache. The pending snapshot is used only for instances without a valid cache entry, and is never persisted.
Actual behavior
Server trace from one launch (seconds since process start):
| t | span |
|---|---|
| 6.946 | ClaudeProvider.makePendingClaudeProvider |
| 6.948 | checkClaudeProviderStatus starts (1154 ms) |
| 6.961 | providerStatusCache.readProviderStatusCache ×10 (cache: ready) |
| 6.967 | upsertProviders → ProviderRegistry.persistProvider ×10 (pending snapshots written) |
| 8.10 | probe completes → ready |
Possible fix
Seed upsertProviders with fallbackProviders only for instances that weren't hydrated. Alternatively, have mergeProviderSnapshot keep the previous probe fields when next is the pending snapshot. Either way, don't persist pending snapshots.
Version or commit
0.1.10-nightly.20261111.4544
Environment
macOS 27.2, desktop app, Claude provider
Activity