Skip to content

[Bug]: Provider status cache is overwritten by the pending snapshot on every boot #34664

Closed

Description

@kamafozilov

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 snapshot

mergeProviderSnapshot(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

  1. Use an enabled, authenticated provider (here: Claude) until it shows ready. Confirm caches/claudeAgent.json has "status": "ready".
  2. Quit and reopen T3 Code.
  3. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions