fix(tui,mcp): startup freeze 3-layer + usage probe trigger/matching/render chain - #2542
Merged
Merged
Conversation
Freeze (live-captured 2026-09-18, drain 20s -> 4.4s -> 250ms): - subscriptions/listen ack wait 10s -> 2s (SubscriptionsAckTimeout): silent servers (Pen.app stdio pair) never answer -32601, each stalled the connect path the full 10s and gated 'connected' state late - deadline-exceeded now downgrades permanently (subStateUnsupported), reconnects do not re-pay the ack wait - subs upgrade moved OFF the plugin write lock (postConnect): Connect held m.mu across the ack wait while refreshCommands -> SnapshotMCP -> Info() takes the same lock's read side - every UI command refresh stalled behind ack deadlines; two serialized 10s stalls = the 20s freeze; 8s-timeout HTTP servers queued behind them died (railway/ zread/cf now connect) Sidebar usage attribution (user report: sidebar never updates): - attribution now compares in the RESOLVED probe-id domain (svc.Resolve of the session's current endpoint URL), not the config vendor-name domain; session-runtime vendor/endpoint (persisted per session, config file only feeds new sessions) was renamed configs' silent-empty-sidebar root cause. Unit tests pin URL-domain attribution, error-clears-stale, and name-domain fallback. Instrumentation: - mcpServersMsg handler segment timing (toMCPInfos/refreshCommands/ pendingOAuth) and slow-view-render section attribution logs Bench: internal/chat render/scroll/stream micro-benchmarks. Co-Authored-By: ggcode <noreply@ggcode.dev> Co-Authored-By: ggcode <noreply@ggcode.dev>
Root cause of "usage never shows" (user: trigger logic rewritten a dozen times, never right): fetchAllUsageCmd had exactly two callers - manual openUsagePanel and the panel's r key. Unless the user manually opened the usage panel, no probe ever fired, no usageInfoUpdatedMsg ever arrived, and the sidebar stayed empty regardless of attribution/parse correctness. All previous fixes patched the result end; the trigger end never existed. - First probe fires at input-drain end (UI interactive, ~250ms after start); subsequent rounds re-arm from handleUsageInfoUpdated every 60s (Service success/negative/429 caches de-duplicate upstream HTTP; zai's 5h rolling window recovers minute-by-minute, so 60s is the first cadence that tracks the meter) - explainUsageSidebar: every no-probe branch renders a one-line reason in the sidebar (vendor X not in config / endpoint not found / no api key / no usage probe for host / probing...) - silent-empty sidebars are now diagnosable from the UI alone; probe failure shows the error, success clears the line - branch unit tests (vendor-missing / unclaimed-host / keyless / probeable) Co-Authored-By: ggcode <noreply@ggcode.dev> Co-Authored-By: ggcode <noreply@ggcode.dev>
Design corrections per user review (2026-09-18):
- Probes now match the FULL endpoint URL, not the bare host:
open.bigmodel.cn is SHARED between metered /api/paas/v4 and coding
/api/coding/paas/v4 - only the plan entrance carries window quotas,
so ZaiProbe claims /coding* and /api/anthropic paths; metered bases
resolve to no probe (sidebar explains: no usage probe for host).
- currentEndpointForUsage now resolves through the SAME runtime
resolver as chat (ResolveEndpointSelection): vendor-level key
fallback + ${VAR} expansion applied. Previously it read the raw
config field, so zai/cn-coding-openai (key at vendor level only)
read as keyless and no probe ever fired - while chat worked fine.
- No attribution layer: probes fire only for the session's current
endpoint, so any result that arrives renders directly. The probe-id
comparison, vendor-name fallback, and msg.baseURL round-trip are
deleted.
- Sidebar shows the exact blocking reason (resolution error verbatim /
no api key / no usage probe for host) when nothing can render.
Tests updated to the URL semantics: metered bases unclaimed, coding
paths claimed, test fixtures carry models and coding paths.
Co-Authored-By: ggcode <noreply@ggcode.dev>
Co-Authored-By: ggcode <noreply@ggcode.dev>
Regression anchor for the 2026-09-18 break: zai/cn-coding-openai carries its api key ONLY at vendor level. Constructs that exact config shape and asserts (1) the probe is authorized, (2) fetchAllUsageCmd dispatches one probe call, (3) Fetch receives the VENDOR-level key and the coding-plan URL. Without this, the usage chain reading raw config fields (keyless) while chat resolved fine can silently return. Co-Authored-By: ggcode <noreply@ggcode.dev> Co-Authored-By: ggcode <noreply@ggcode.dev>
The fetch closure did 'return tea.Batch(cmds...)' - a Cmd VALUE (function) returned where a Msg is required. bubbletea dispatched the function object to Update, no handler matched, and every probe result vanished: the usage panel stuck on 获取中 and the sidebar on probing forever, while the probes themselves ran fine. Deliver the first result as the Cmd's real Msg; extra results go through program.Send. Guard test: TestFetchCmdReturnsRealMsg asserts cmd() returns usageInfoUpdatedMsg and that it flips the panel out of fetching. Co-Authored-By: ggcode <noreply@ggcode.dev>
topcheer
pushed a commit
that referenced
this pull request
Sep 19, 2026
3 PRs this cycle: #2533 memory recall-time conflict arbitration, #2535 runeval offline scorecard (/runreport), #2542 startup freeze 3-layer + usage probe trigger/URL-matching/key-resolution/render chain (fetch Cmd-as-Msg drop fix). verify-ci passed (GOFLAGS=-p=1). Co-Authored-By: ggcode <noreply@ggcode.dev>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Five-part fix chain, all verified by unit tests + live evidence:
Regression anchors
Test plan