Ariver
2026-06-10 fe5c1fa0d397938511e6102bbe5562f03f02607f
C1.source/Sources/Aligner/QuickSwitchSessionController.swift
@@ -5,13 +5,21 @@
@MainActor
final class QuickSwitchSessionController {
    static let overlayTitle = "Aligner Quick Switch"
    private static let closeRequestStillPresentMessage = "已发送关闭请求,但窗口仍在列表中。"
    private static let closeTargetNotFoundMessage = "没有找到这个窗口的关闭控件,已刷新列表。"
    private static let closeUnsupportedMessage = "这个窗口没有可用的关闭按钮。"
    private static let closeFailedMessage = "关闭请求没有被系统接受。"
    private static let closeVerificationRetryDelays: [TimeInterval] = [0.35, 0.70, 1.20]
    private let view = QuickSwitchRootView()
    private let snapshotLoader: any QuickSwitchSnapshotLoading
    private let screenshotProvider: any ScreenshotProviderProtocol
    private let windowActivationService: any WindowActivationServiceProtocol
    private let windowCloseService: any WindowCloseServiceProtocol
    private let systemCriticalWindowDetector: any SystemCriticalWindowDetecting
    private let disableScreenshotRefresh: Bool
    private var closeConfirmationRequired: Bool
    private let onCloseConfirmationDisabled: (() -> Void)?
    private let debugOverlayWidth: CGFloat?
    private let debugKeySequence: [String]
    private let debugMouseSequence: [String]
@@ -40,6 +48,14 @@
    private var lastActivationWindowID: UInt32?
    private var lastActivationResult: WindowActivationResult?
    private var lastActivationError: String?
    private var lastCloseTargetKind: String?
    private var lastCloseAppGroupIndex: Int?
    private var lastCloseAppName: String?
    private var lastCloseWindowID: UInt32?
    private var lastCloseResult: WindowCloseResult?
    private var lastCloseError: String?
    private var pendingCloseVerification: PendingCloseVerification?
    private var suppressedCloseTargets: [SuppressedCloseTarget] = []
    private var lastDismissReason: DismissReason?
    private var lastSystemCriticalAction: String?
    private var lastSystemCriticalMonitorSource: String?
@@ -58,6 +74,26 @@
    private var lifecycleResidualVisibleOverlayWindows = 0
    var onSnapshotUpdated: (() -> Void)?
    private struct PendingCloseVerification {
        let request: QuickSwitchCloseRequest
        let generation: Int
        let attempt: Int
    }
    private enum SuppressedCloseTarget: Equatable {
        case app(AlignerApp)
        case window(UInt32)
        init(_ request: QuickSwitchCloseRequest) {
            switch request {
            case .app:
                self = .app(request.app)
            case .window:
                self = .window(request.windowID ?? 0)
            }
        }
    }
    init(
        snapshotLoader: any QuickSwitchSnapshotLoading = LiveQuickSwitchSnapshotLoader(),
        screenshotProvider: any ScreenshotProviderProtocol = ScreenCaptureKitScreenshotProvider(
@@ -66,8 +102,13 @@
        windowActivationService: any WindowActivationServiceProtocol = CGWindowAXWindowService(
            spaceIDsByWindowIDProvider: { _ in [:] }
        ),
        windowCloseService: any WindowCloseServiceProtocol = CGWindowAXWindowService(
            spaceIDsByWindowIDProvider: { _ in [:] }
        ),
        systemCriticalWindowDetector: any SystemCriticalWindowDetecting = CGWindowSystemCriticalWindowDetector(),
        disableScreenshotRefresh: Bool = false,
        closeConfirmationRequired: Bool = true,
        onCloseConfirmationDisabled: (() -> Void)? = nil,
        debugHoveredAppGroupIndex: Int? = nil,
        debugOverlayWidth: CGFloat? = nil,
        debugKeySequence: [String] = [],
@@ -77,8 +118,11 @@
        self.snapshotLoader = snapshotLoader
        self.screenshotProvider = screenshotProvider
        self.windowActivationService = windowActivationService
        self.windowCloseService = windowCloseService
        self.systemCriticalWindowDetector = systemCriticalWindowDetector
        self.disableScreenshotRefresh = disableScreenshotRefresh
        self.closeConfirmationRequired = closeConfirmationRequired
        self.onCloseConfirmationDisabled = onCloseConfirmationDisabled
        self.debugOverlayWidth = debugOverlayWidth
        self.debugKeySequence = debugKeySequence
        self.debugMouseSequence = debugMouseSequence
@@ -107,6 +151,14 @@
        lastActivationWindowID = nil
        lastActivationResult = nil
        lastActivationError = nil
        lastCloseTargetKind = nil
        lastCloseAppGroupIndex = nil
        lastCloseAppName = nil
        lastCloseWindowID = nil
        lastCloseResult = nil
        lastCloseError = nil
        pendingCloseVerification = nil
        suppressedCloseTargets = []
        lastDismissReason = nil
        lastSystemCriticalAction = nil
        lastSystemCriticalMonitorSource = nil
@@ -128,6 +180,15 @@
        view.onCommitSelection = { [weak self] selection, source in
            self?.commitSelection(selection, source: source)
        }
        view.onRequestClose = { [weak self] request in
            self?.requestClose(request)
        }
        view.onCloseConfirmationDisabled = { [weak self] in
            guard let self else { return }
            self.closeConfirmationRequired = false
            self.onCloseConfirmationDisabled?()
        }
        view.setCloseConfirmationRequired(closeConfirmationRequired)
        view.apply(viewModel: nil)
        view.beginPerformanceFirstFrameMeasurement()
        coordinator.openQuickSwitch()
@@ -157,6 +218,8 @@
        snapshotTask = nil
        screenshotTask?.cancel()
        screenshotTask = nil
        pendingCloseVerification = nil
        view.clearCloseFeedback()
        invalidateSystemCriticalMonitoring()
        coordinator.closeQuickSwitch(reason: reason)
        lifecycleResidualOverlayWindows = overlayWindowCount()
@@ -212,6 +275,13 @@
            "lastActivationWindowID": lastActivationWindowID ?? NSNull(),
            "lastActivationResult": lastActivationResult.map(Self.activationResultString) ?? NSNull(),
            "lastActivationError": lastActivationError ?? NSNull(),
            "lastCloseTargetKind": lastCloseTargetKind ?? NSNull(),
            "lastCloseAppGroupIndex": lastCloseAppGroupIndex ?? NSNull(),
            "lastCloseAppName": lastCloseAppName ?? NSNull(),
            "lastCloseWindowID": lastCloseWindowID ?? NSNull(),
            "lastCloseResult": lastCloseResult.map(Self.closeResultString) ?? NSNull(),
            "lastCloseError": lastCloseError ?? NSNull(),
            "suppressedCloseTargetCount": suppressedCloseTargets.count,
            "lastDismissReason": lastDismissReason.map(Self.dismissReasonString) ?? NSNull(),
            "overlayLevel": Int(coordinator.currentLevel),
            "overlayMainMenuLevel": Int(CGWindowLevelForKey(.mainMenuWindow)),
@@ -264,16 +334,26 @@
        updateLifecycleWindowHighWaterMark()
    }
    private func scheduleSnapshotRefresh(for generation: Int) {
    private func scheduleSnapshotRefresh(
        for generation: Int,
        replayDebugCommands: Bool = true,
        delay: TimeInterval = 0
    ) {
        DevelopmentDiagnostics.log("quickSwitch.snapshot.schedule", [
            "generation": generation,
            "visible": isVisible
            "visible": isVisible,
            "replayDebugCommands": replayDebugCommands,
            "delayMilliseconds": Int(delay * 1_000)
        ])
        snapshotTask?.cancel()
        let loader = snapshotLoader
        let showStartTime = showStartTime
        snapshotTask = Task { [weak self] in
            guard let self, !Task.isCancelled else { return }
            if delay > 0 {
                try? await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
                guard !Task.isCancelled else { return }
            }
            let loadTask = Task.detached(priority: .userInitiated) {
                SnapshotLoadResult.load(using: loader, showStartTime: showStartTime)
@@ -285,7 +365,11 @@
            }
            guard !Task.isCancelled else { return }
            self.applySnapshotResult(result, generation: generation)
            self.applySnapshotResult(
                result,
                generation: generation,
                replayDebugCommands: replayDebugCommands
            )
        }
    }
@@ -432,6 +516,224 @@
        onSnapshotUpdated?()
    }
    private func requestClose(_ request: QuickSwitchCloseRequest) {
        DevelopmentDiagnostics.log("quickSwitch.close.request.start", [
            "targetKind": request.kindDescription,
            "appGroupIndex": request.appGroupIndex,
            "appName": request.appName,
            "windowID": request.windowID,
            "titleHash": DevelopmentDiagnostics.stableFingerprint(request.title),
            "titleLength": request.title.count
        ])
        lastCloseTargetKind = request.kindDescription
        lastCloseAppGroupIndex = request.appGroupIndex
        lastCloseAppName = request.appName
        lastCloseWindowID = request.windowID
        lastCloseError = nil
        pendingCloseVerification = nil
        view.showCloseProgress(for: request)
        do {
            let result: WindowCloseResult
            switch request {
            case .app:
                result = try windowCloseService.close(app: request.app)
            case .window:
                guard let window = request.window else {
                    lastCloseResult = .windowNotFound
                    suppressCloseTarget(request)
                    view.clearCloseFeedback()
                    onSnapshotUpdated?()
                    return
                }
                result = try windowCloseService.close(window: window)
            }
            lastCloseResult = result
            DevelopmentDiagnostics.log("quickSwitch.close.request.result", [
                "targetKind": request.kindDescription,
                "appGroupIndex": request.appGroupIndex,
                "appName": request.appName,
                "windowID": request.windowID,
                "result": Self.closeResultString(result)
            ])
            if result == .requested {
                suppressCloseTarget(request)
                DevelopmentDiagnostics.log("quickSwitch.close.request.refreshAfterClose", [
                    "targetKind": request.kindDescription,
                    "appGroupIndex": request.appGroupIndex,
                    "appName": request.appName,
                    "windowID": request.windowID
                ])
                pendingCloseVerification = PendingCloseVerification(
                    request: request,
                    generation: sessionGeneration,
                    attempt: 0
                )
                scheduleSnapshotRefresh(
                    for: sessionGeneration,
                    replayDebugCommands: false,
                    delay: Self.closeVerificationRetryDelays[0]
                )
            } else if result == .windowNotFound {
                suppressCloseTarget(request)
                view.clearCloseFeedback()
                DevelopmentDiagnostics.log("quickSwitch.close.request.staleTargetRemoved", [
                    "targetKind": request.kindDescription,
                    "appGroupIndex": request.appGroupIndex,
                    "appName": request.appName,
                    "windowID": request.windowID
                ])
                scheduleSnapshotRefresh(
                    for: sessionGeneration,
                    replayDebugCommands: false,
                    delay: 0.10
                )
            } else {
                view.showCloseFailure(message: closeFailureMessage(for: result), for: request)
            }
        } catch {
            let errorSummary = DevelopmentDiagnostics.errorSummaryString(error)
            lastCloseResult = .failed(errorSummary)
            lastCloseError = errorSummary
            pendingCloseVerification = nil
            view.showCloseFailure(message: Self.closeFailedMessage, for: request)
            var fields: [String: CustomStringConvertible?] = [
                "targetKind": request.kindDescription,
                "appGroupIndex": request.appGroupIndex,
                "appName": request.appName,
                "windowID": request.windowID,
                "titleHash": DevelopmentDiagnostics.stableFingerprint(request.title),
                "titleLength": request.title.count
            ]
            DevelopmentDiagnostics.errorSummaryFields(error).forEach { fields[$0.key] = $0.value }
            DevelopmentDiagnostics.log("quickSwitch.close.request.error", fields)
        }
        onSnapshotUpdated?()
    }
    private func suppressCloseTarget(_ request: QuickSwitchCloseRequest) {
        let target = SuppressedCloseTarget(request)
        if !suppressedCloseTargets.contains(target) {
            suppressedCloseTargets.append(target)
        }
        guard let currentViewModel else { return }
        let visibleViewModel = viewModel(currentViewModel, excluding: suppressedCloseTargets)
        self.currentViewModel = visibleViewModel
        view.apply(viewModel: visibleViewModel)
        DevelopmentDiagnostics.log("quickSwitch.close.optimisticRemove", [
            "targetKind": request.kindDescription,
            "appGroupIndex": request.appGroupIndex,
            "appName": request.appName,
            "windowID": request.windowID,
            "remainingWindowCount": visibleViewModel.windowCount,
            "suppressedCloseTargetCount": suppressedCloseTargets.count
        ])
    }
    private func viewModel(
        _ viewModel: QuickSwitchViewModel,
        excluding suppressedTargets: [SuppressedCloseTarget]
    ) -> QuickSwitchViewModel {
        guard !suppressedTargets.isEmpty else { return viewModel }
        var nextGlobalIndex = 0
        let columns = viewModel.waterfallColumns.compactMap { column -> QuickSwitchWaterfallColumnViewModel? in
            let windows = column.windows.filter { card in
                !suppressedTargets.contains { target in
                    suppressedTarget(target, matches: card)
                }
            }
            guard !windows.isEmpty else { return nil }
            let reindexedWindows = windows.enumerated().map { windowIndex, card in
                defer { nextGlobalIndex += 1 }
                return QuickSwitchWindowCardViewModel(
                    appGroupIndex: column.appGroupIndex,
                    windowIndex: windowIndex,
                    globalIndex: nextGlobalIndex,
                    window: card.window,
                    primarySpaceID: card.primarySpaceID,
                    primarySpaceLabel: card.primarySpaceLabel
                )
            }
            return QuickSwitchWaterfallColumnViewModel(
                appGroupIndex: column.appGroupIndex,
                app: column.app,
                windows: reindexedWindows
            )
        }
        let columnsByAppGroupIndex = Dictionary(uniqueKeysWithValues: columns.map { ($0.appGroupIndex, $0) })
        let appShelf = viewModel.appShelf.compactMap { item -> QuickSwitchAppShelfItemViewModel? in
            guard let column = columnsByAppGroupIndex[item.appGroupIndex] else { return nil }
            return QuickSwitchAppShelfItemViewModel(
                appGroupIndex: item.appGroupIndex,
                app: item.app,
                windowCount: column.windows.count,
                primarySpaceIDs: orderedPrimarySpaceIDs(in: column.windows),
                hasMinimizedWindows: column.windows.contains { $0.window.isMinimized },
                hasFullscreenWindows: column.windows.contains { $0.window.isFullscreen }
            )
        }
        return QuickSwitchViewModel(
            displays: viewModel.displays,
            appShelf: appShelf,
            waterfallColumns: columns,
            initialSelection: initialSelection(in: columns, fallback: viewModel.initialSelection)
        )
    }
    private func orderedPrimarySpaceIDs(in cards: [QuickSwitchWindowCardViewModel]) -> [UInt64] {
        var seen = Set<UInt64>()
        var result: [UInt64] = []
        for card in cards {
            guard let spaceID = card.primarySpaceID,
                  !seen.contains(spaceID)
            else {
                continue
            }
            seen.insert(spaceID)
            result.append(spaceID)
        }
        return result
    }
    private func suppressedTarget(
        _ target: SuppressedCloseTarget,
        matches card: QuickSwitchWindowCardViewModel
    ) -> Bool {
        switch target {
        case .window(let windowID):
            return card.window.id == windowID
        case .app(let app):
            return appMatches(card.window.app, app)
        }
    }
    private func initialSelection(
        in columns: [QuickSwitchWaterfallColumnViewModel],
        fallback: QuickSwitchSelection?
    ) -> QuickSwitchSelection? {
        if let fallback,
           columns.contains(where: { column in
               column.appGroupIndex == fallback.appGroupIndex
                   && column.windows.contains { $0.window.id == fallback.windowID }
           }) {
            return fallback
        }
        guard let firstCard = columns.first?.windows.first else { return nil }
        return QuickSwitchSelection(
            appGroupIndex: firstCard.appGroupIndex,
            windowIndex: firstCard.windowIndex,
            windowID: firstCard.window.id
        )
    }
    private func shouldCloseAfterActivation(_ result: WindowActivationResult?) -> Bool {
        switch result {
        case .activated, .restored, .appActivatedOnly:
@@ -453,7 +755,11 @@
            .window
    }
    private func applySnapshotResult(_ result: SnapshotLoadResult, generation: Int) {
    private func applySnapshotResult(
        _ result: SnapshotLoadResult,
        generation: Int,
        replayDebugCommands: Bool
    ) {
        guard generation == sessionGeneration, isVisible else {
            DevelopmentDiagnostics.log("quickSwitch.snapshot.drop", [
                "resultGeneration": generation,
@@ -466,15 +772,19 @@
        switch result {
        case .success(let success):
            currentSnapshot = success.snapshot
            currentViewModel = success.viewModel
            let visibleViewModel = viewModel(success.viewModel, excluding: suppressedCloseTargets)
            currentViewModel = visibleViewModel
            lastSnapshotError = nil
            snapshotStartElapsedMilliseconds = success.timing.startElapsedMilliseconds
            snapshotDurationMilliseconds = success.timing.durationMilliseconds
            snapshotRanOnMainThread = success.timing.ranOnMainThread
            view.apply(viewModel: success.viewModel)
            view.apply(viewModel: visibleViewModel)
            view.recordPerformanceFirstFrameIfNeeded()
            view.performDebugKeyboardCommands(debugKeySequence)
            view.performDebugMouseCommands(debugMouseSequence)
            if replayDebugCommands {
                view.performDebugKeyboardCommands(debugKeySequence)
                view.performDebugMouseCommands(debugMouseSequence)
            }
            verifyPendingCloseIfNeeded(in: success.viewModel)
            DevelopmentDiagnostics.log("quickSwitch.snapshot.success", [
                "generation": generation,
                "displayCount": success.viewModel.displays.count,
@@ -487,14 +797,14 @@
            ])
            guard isVisible else { return }
            if disableScreenshotRefresh {
                view.markScreenshotsNotRequested(for: success.viewModel, reason: "disabledByLaunchOption")
                view.markScreenshotsNotRequested(for: visibleViewModel, reason: "disabledByLaunchOption")
                screenshotTask?.cancel()
                screenshotTask = nil
                DevelopmentDiagnostics.log("quickSwitch.screenshot.disabledByLaunchOption", [
                    "generation": generation
                ])
            } else {
                scheduleScreenshotRefresh(for: success.viewModel, generation: generation)
                scheduleScreenshotRefresh(for: visibleViewModel, generation: generation)
            }
        case .failure(let failure):
            currentSnapshot = nil
@@ -506,6 +816,7 @@
            view.apply(viewModel: nil)
            screenshotTask?.cancel()
            screenshotTask = nil
            failPendingCloseVerificationIfNeeded(reason: "snapshotFailure")
            DevelopmentDiagnostics.log("quickSwitch.snapshot.failure", [
                "generation": generation,
                "message": failure.message,
@@ -515,6 +826,104 @@
        }
        onSnapshotUpdated?()
    }
    private func verifyPendingCloseIfNeeded(in viewModel: QuickSwitchViewModel) {
        guard let pendingCloseVerification else { return }
        self.pendingCloseVerification = nil
        let request = pendingCloseVerification.request
        let stillPresent = closeTargetStillPresent(request, in: viewModel)
        DevelopmentDiagnostics.log("quickSwitch.close.verify", [
            "targetKind": request.kindDescription,
            "appGroupIndex": request.appGroupIndex,
            "appName": request.appName,
            "windowID": request.windowID,
            "requestedGeneration": pendingCloseVerification.generation,
            "currentGeneration": sessionGeneration,
            "attempt": pendingCloseVerification.attempt,
            "stillPresent": stillPresent
        ])
        if stillPresent {
            let nextAttempt = pendingCloseVerification.attempt + 1
            if nextAttempt < Self.closeVerificationRetryDelays.count {
                self.pendingCloseVerification = PendingCloseVerification(
                    request: request,
                    generation: sessionGeneration,
                    attempt: nextAttempt
                )
                scheduleSnapshotRefresh(
                    for: sessionGeneration,
                    replayDebugCommands: false,
                    delay: Self.closeVerificationRetryDelays[nextAttempt]
                )
            } else {
                view.showCloseFailure(message: Self.closeRequestStillPresentMessage, for: request)
            }
        } else {
            view.clearCloseFeedback()
        }
    }
    private func failPendingCloseVerificationIfNeeded(reason: String) {
        guard let pendingCloseVerification else { return }
        self.pendingCloseVerification = nil
        let request = pendingCloseVerification.request
        DevelopmentDiagnostics.log("quickSwitch.close.verify.failed", [
            "targetKind": request.kindDescription,
            "appGroupIndex": request.appGroupIndex,
            "appName": request.appName,
            "windowID": request.windowID,
            "requestedGeneration": pendingCloseVerification.generation,
            "currentGeneration": sessionGeneration,
            "reason": reason
        ])
        view.showCloseFailure(message: Self.closeFailedMessage, for: request)
    }
    private func closeFailureMessage(for result: WindowCloseResult) -> String {
        switch result {
        case .requested:
            return Self.closeRequestStillPresentMessage
        case .windowNotFound:
            return Self.closeTargetNotFoundMessage
        case .unsupported:
            return Self.closeUnsupportedMessage
        case .appNotFound, .failed:
            return Self.closeFailedMessage
        }
    }
    private func closeTargetStillPresent(
        _ request: QuickSwitchCloseRequest,
        in viewModel: QuickSwitchViewModel
    ) -> Bool {
        switch request {
        case .window:
            guard let windowID = request.windowID else { return false }
            return viewModel.waterfallColumns
                .flatMap(\.windows)
                .contains { $0.window.id == windowID }
        case .app:
            return viewModel.appShelf.contains { appMatches($0.app, request.app) }
                || viewModel.waterfallColumns.contains { appMatches($0.app, request.app) }
        }
    }
    private func appMatches(_ candidate: AlignerApp, _ target: AlignerApp) -> Bool {
        if let candidatePID = candidate.processIdentifier,
           let targetPID = target.processIdentifier {
            return candidatePID == targetPID
        }
        if !candidate.bundleIdentifier.isEmpty,
           candidate.bundleIdentifier == target.bundleIdentifier {
            return true
        }
        return candidate.name == target.name
    }
    private func scheduleScreenshotRefresh(
@@ -650,6 +1059,21 @@
        }
    }
    private static func closeResultString(_ result: WindowCloseResult) -> String {
        switch result {
        case .requested:
            return "requested"
        case .windowNotFound:
            return "windowNotFound"
        case .appNotFound:
            return "appNotFound"
        case .unsupported:
            return "unsupported"
        case .failed(let message):
            return "failed(\(message))"
        }
    }
    private static func screenshotSourceString(_ source: ScreenshotResolutionSource) -> String {
        switch source {
        case .realScreenshot:
@@ -742,6 +1166,7 @@
    let snapshotLoadDelay: TimeInterval?
    let fixtureAppCount: Int?
    let fixtureWindowsPerApp: Int?
    let fixtureMultiDisplay: Bool
    let fixtureCandidateFiltering: Bool
    let fixtureActivation: Bool
    let debugHoveredAppGroupIndex: Int?
@@ -750,6 +1175,7 @@
    let debugMouseSequence: [String]
    let debugSystemCriticalAfter: TimeInterval?
    let debugWindowActivation: Bool
    let debugWindowClose: Bool
    let disableScreenshotRefresh: Bool
    let lifecycleCycles: Int?
    let lifecycleInterval: TimeInterval
@@ -766,6 +1192,7 @@
            snapshotLoadDelay: timeInterval(for: "--round01-snapshot-load-delay", in: arguments),
            fixtureAppCount: intValue(for: "--round01-fixture-app-count", in: arguments),
            fixtureWindowsPerApp: intValue(for: "--round01-fixture-windows-per-app", in: arguments),
            fixtureMultiDisplay: arguments.contains("--round01-fixture-multi-display"),
            fixtureCandidateFiltering: arguments.contains("--round01-fixture-candidate-filtering"),
            fixtureActivation: arguments.contains("--round01-fixture-window-activation"),
            debugHoveredAppGroupIndex: intValue(for: "--round01-debug-hover-app-index", in: arguments),
@@ -774,6 +1201,7 @@
            debugMouseSequence: stringListValue(for: "--round01-debug-mouse-sequence", in: arguments),
            debugSystemCriticalAfter: timeInterval(for: "--round01-debug-system-critical-after", in: arguments),
            debugWindowActivation: arguments.contains("--round01-debug-window-activation"),
            debugWindowClose: arguments.contains("--round01-debug-window-close"),
            disableScreenshotRefresh: arguments.contains("--round01-disable-screenshot-refresh"),
            lifecycleCycles: intValue(for: "--round01-quick-switch-lifecycle-cycles", in: arguments),
            lifecycleInterval: timeInterval(for: "--round01-quick-switch-lifecycle-interval", in: arguments) ?? 0.02,