Root cause of 'connected Claude, still shows Kimi / unknown model': every
fetch-plan decision consulted only the primary (Kimi) session and API keys
— never the stored subscription-OAuth sessions:
- on_auth_changed's wipe guard: a claude-pro-max-only login satisfied
'no session, no keys' → catalog wiped, early return BEFORE the fetch
and BEFORE notify_models_updated. The TUI kept an empty picker and the
prompt bar rendered 'unknown'. Guard decision extracted into the pure
should_wipe_catalog_on_auth_change (matrix-tested); a stored OAuth
session now vetoes the wipe, so the fetch runs, the first real catalog
reselects the default model (first entry = the connected provider's),
and kigi/models/update reaches the client.
- Startup prefetch: the arming gate ignored stored OAuth sessions and the
prefetch thread passed an empty token map — a claude-only user booted
onto the bundled Kimi table until a later refresh. The gate now takes
has_stored_oauth and the thread resolves each stored session's bearer
(refresh-on-expiry) via a current-thread runtime.
- Cache origins: from_config's startup cache load and cache_origin()
computed the fetch-plan origin with an empty token map, so a
claude-inclusive cached catalog never matched at startup. Both now use
presence-only stubs (stored_oauth_token_stubs — names only, no bearers)
proven equal to the real-token origin by test.
New probes in models_fetch: stored_oauth_platforms / stored_oauth_token_
stubs (sync auth.json scope scan; no AuthManager, no secrets).
Verified: kigi-shell 5260 tests green, clippy clean.