Desktop Material

Responsiveness and resource lifecycle

Desktop Material bounds repeated background work and releases resources at the same lifecycle boundary that created them. The behavior is automatic; it adds no preference, language string, credential format, or provider API.

Behavior

Configuration and persistence

No migration is required. Appearance burst coalescing happens before the existing 250-millisecond owner-local commit debounce; it does not combine different owners or cross a queued get()/history barrier. Every caller in one burst settles from the same mutation result, and the last normalized description is the one recorded for that burst.

Remote-HEAD reuse is local, namespace-validated, target-validated, and limited to background refreshes. Repositories with provider metadata continue to use the provider's declared default branch. Fetch/prune turns a deleted old default into a dangling ref, which Desktop repairs automatically. An explicit fetch also discovers a generic host's renamed default even when the prior branch still exists. Its abort signal bounds the secondary lookup to five seconds and its separate cleanup grace makes ten seconds the hard settlement bound.

Proxy coalescing is process-local and stores no proxy result. It keys only the currently unresolved work by exact URL and resolver implementation; successful and failed work is removed immediately. Authentication environment values are still assembled independently for each Git operation.

Failure modes and recovery

An askpass popup-dispatch failure rejects the affected prompt, normalizes the queue tail, and allows the next request to appear. GitHub sign-in retains its existing logged undefined result on dispatch failure. External removal and stack eviction settle the affected prompt as cancelled; sign-in additionally resets its retained store callback. Replacement also settles the old owner, but does not reset state needed by the new sign-in popup. A failed appearance batch rejects every caller in that batch without poisoning later store operations. Invalid or dangling local remote-HEAD refs use the existing authenticated discovery path and retain its bounded success/error handling. A process-tree terminator failure is observed and logged. If termination or the child-close event remains unresolved after the cleanup grace, Desktop stops awaiting this advisory refresh so the completed fetch can return; the owned termination work keeps a rejection observer for any later failure.

A trampoline command carrying a token which is no longer valid is declined rather than thrown. The server replies on the socket and logs one warning naming the command's identifier, the credential-helper verb, and its parameter count, so only that one request fails. Previously the server threw, which surfaced as an unhandled renderer rejection, showed the generic "a background action stopped unexpectedly" notice, and — because the reply never arrived — left a live Git process waiting on a socket that was never closed while still holding its lock files, which could fail an unrelated commit or push in the same repository.

Electron's proxy resolver exposes no AbortSignal. A resolver which never settles therefore leaves one shared in-flight entry for that exact URL until it settles or the app restarts. This is bounded for repeated calls to the same URL, but distinct permanently stalled URLs can each retain one entry.

Network errors remove only the exact failed request ID. The next request can reuse an Electron request ID without inheriting a stale origin. Markdown teardown is idempotent: pending debounce cancellation and null references are safe even when no iframe finished loading.

Security considerations

The remote lookup and prompt queue preserve exact account selection; no token is added to arguments, environment, persistence, or logs. Same-origin cleanup does not weaken redirect protection: authorization-like headers are still removed when the current URL crosses the initial origin. Releasing a failed entry also prevents a recycled request ID from being compared against another request's stale origin.

A trampoline token is still single-operation and still revoked when its operation finishes; extending it only covers processes that operation actually launched, and a token is never resurrected once disposed. The refusal log line never contains the token, the command's standard input (which carries credentials for store and erase), or an askpass prompt (which can name a key path). Because the per-operation context now lives exactly as long as the token, a late credential request is answered with the originating repository and forced account instead of a default working directory and an unforced account.

Markdown remains sanitized and rendered inside its sandboxed iframe. Lifecycle cleanup only releases listeners and references; it does not broaden link, script, style, or content privileges.

Windows process-tree termination continues to resolve taskkill.exe through the existing realpath, file-type, basename, and containment checks under the configured SystemRoot (or the existing C:\Windows fallback). This repository and its Node/Electron runtime expose no authoritative GetSystemDirectoryW binding, so this correction does not swap that source for another environment guess such as WINDIR. Authenticating the Windows installation directory independently remains a defense-in-depth follow-up for a process whose inherited environment and alternate filesystem tree are already attacker-controlled.

Verification

fetch-authenticated-git-test.ts covers the validated background fast path, bounded user refresh, a renamed default whose old target remains, dangling-target and invalid-namespace fallback, exact account forwarding, an injected never-settling terminator, and a late termination rejection after the cleanup bound. git/environment-test.ts proves two concurrent preparations invoke one resolver and that settled work is evicted. git/clone-test.ts proves clone cancellation still waits for the complete injected termination barrier. The focused Git gate passes 30/30 tests.

trampoline-token-lifecycle-test.ts covers a revoked token surviving until its child process closes, release on a spawn error, no extension for a process which already exited, multiple independent leases with exactly one disposal, no resurrection after disposal, and per-operation context which stays readable while the child is alive and is gone afterwards. It also drives a real trampoline server over a loopback socket to prove an expired token is declined with an empty reply and no handler invocation, that an unknown token is distinguished from an expired one, that a command whose process outlived its operation is still served, that a rejecting handler still replies, and that the log description omits the token, the standard input, and the askpass prompt.

popup-manager-test.ts and trampoline-ui-helper-test.ts cover FIFO settlement for every prompt family, pre-existing sign-in reuse, duplicate/removed/evicted popup settlement, replacement reasons, replacement-safe sign-in state, sign-in reset on ordinary removal, and recovery after dispatch failure. dedicated-setting-store-test.ts covers a 500-call burst, queued-read/history and flush barriers, sequential writes, and failed-batch recovery.

same-origin-filter-test.ts fails a request, reuses its numeric ID, and proves that same-origin authorization survives only after the stale record is released. sandboxed-markdown-lifecycle-test.tsx performs 25 content reloads, dispatches an actual scroll before and after unmount, and checks matching listener removal, debounce cancellation, and released iframe references. build-run-settings-lifecycle-test.tsx and git-ignore-lifecycle-test.tsx resolve controlled filesystem probes only after their settings tabs unmount, then assert that React reports no unmounted state update. The related preference and catalog tests exercise the normal mounted paths as well. build-copy-test.ts controls the build keep-alive scheduler and asserts that it is cleared only after the pending build settles; a source contract also prevents the CLI entry point from bypassing that lifecycle.

App-source candidate aabb111d2c01f38e7535ab077048816a5ad16893 completed the required fixed-Lowlevel-MCP production build in 1178.13 seconds. A final visual audit rejected the first off-screen screenshot because a 780 px editor was clipped by its 390 px anchored shell. The shell now inherits the existing wide-editor contract while retaining the compact 390 px fallback; the rejected image is not published.

Remote CI validated the Playwright ffmpeg cache correction on Windows x64, packaged E2E, and arm64. The remaining x64 failure was one stale source assertion added by a later provider integration. The runtime guard was already centralized before side effects; the corrected test checks that shared boundary and both delegating OpenCode wrappers. Final pushed-SHA CI, Release proof, and a fresh unclipped visual recapture remain pending.