Files
BrewUI/Sources/BrewServicesTestSupport/NoopBrewOperationReconciler.swift
Graeme ArthurandClaude Opus 5 a4ae61400f Reconcile inventory inside operation lifecycle
`BrewCommandCenter` reported `.idle` the moment `brew` exited, but
"done" to the UI means "the installed inventory reflects it". Every
surface bridged that gap with its own latch, so each new way the world
could fail to catch up needed its own release channel. Two bugs fell
through: a batch `brew upgrade a b` that failed overall never refreshed
the packages it did upgrade, leaving them marked outdated; and a refresh
that itself failed released nothing, so Installed rows could spin
"Uninstalling..." indefinitely and Discover's install chrome did the
same.

`BrewOperationPhase` gains `.reconciling(kind)`, so a mutating operation
runs running -> reconciling -> idle | failed. `SerialBrewCommandCenter`
takes a `BrewOperationReconciling` at construction and awaits it before
publishing the terminal phase; the installed repository is that
reconciler. No surface now sees a finished operation while the inventory
still describes the world as it was, busy chrome becomes a pure function
of the phase, and every latch is deleted. Read-only work settles
directly; a failed command reconciles too.

Overlapping fetches chain rather than race, and the phase observer seeds
the newly selected subject so the Installed detail pane, which reuses
one view model, cannot keep the previous package's chrome.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-26 17:33:20 +10:00

16 lines
422 B
Swift

//
// NoopBrewOperationReconciler.swift
// BrewServicesTestSupport
//
import BrewCore
import Foundation
/// Reconciler for tests whose subject is not the settling window. Production always reconciles against
/// the installed inventory, so ``SerialBrewCommandCenter`` requires one.
public final class NoopBrewOperationReconciler: BrewOperationReconciling {
public init() {}
public func reconcile() async {}
}