From 1d03f5b6b433b062a098bf7899a349d550aafac7 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Mon, 29 Jun 2026 00:08:52 +0800
Subject: [PATCH] docs: update results map QA evidence

---
 C1.source/Sources/Aligner/QuickSwitchSessionController.swift |   72 +++++++++++++++++++++++++++++++-----
 1 files changed, 62 insertions(+), 10 deletions(-)

diff --git a/C1.source/Sources/Aligner/QuickSwitchSessionController.swift b/C1.source/Sources/Aligner/QuickSwitchSessionController.swift
index f6b860a..8122f9a 100644
--- a/C1.source/Sources/Aligner/QuickSwitchSessionController.swift
+++ b/C1.source/Sources/Aligner/QuickSwitchSessionController.swift
@@ -57,6 +57,7 @@
     private var lastActivationWindowID: UInt32?
     private var lastActivationResult: WindowActivationResult?
     private var lastActivationError: String?
+    private var lastActivationDurationMilliseconds: Double?
     private var lastSpaceActivationSpaceID: UInt64?
     private var lastSpaceActivationDidRequestFocus: Bool?
     private var lastSpaceActivationDisplayIdentifier: String?
@@ -70,6 +71,7 @@
     private var lastCloseError: String?
     private var pendingCloseVerification: PendingCloseVerification?
     private var suppressedCloseTargets: [SuppressedCloseTarget] = []
+    private var suppressedActivationWindowIDs = Set<UInt32>()
     private var lastDismissReason: DismissReason?
     private var lastSystemCriticalAction: String?
     private var lastSystemCriticalMonitorSource: String?
@@ -173,6 +175,7 @@
         lastActivationWindowID = nil
         lastActivationResult = nil
         lastActivationError = nil
+        lastActivationDurationMilliseconds = nil
         lastSpaceActivationSpaceID = nil
         lastSpaceActivationDidRequestFocus = nil
         lastSpaceActivationDisplayIdentifier = nil
@@ -186,6 +189,7 @@
         lastCloseError = nil
         pendingCloseVerification = nil
         suppressedCloseTargets = []
+        suppressedActivationWindowIDs = []
         cancelPendingLockedSpaceUnlock()
         lockedSpaceFilterID = nil
         selectionBeforeSpaceFilter = nil
@@ -376,6 +380,7 @@
             "lastActivationWindowID": lastActivationWindowID ?? NSNull(),
             "lastActivationResult": lastActivationResult.map(Self.activationResultString) ?? NSNull(),
             "lastActivationError": lastActivationError ?? NSNull(),
+            "lastActivationDurationMilliseconds": lastActivationDurationMilliseconds ?? NSNull(),
             "lastSpaceActivationSpaceID": lastSpaceActivationSpaceID ?? NSNull(),
             "lastSpaceActivationDidRequestFocus": lastSpaceActivationDidRequestFocus ?? NSNull(),
             "lastSpaceActivationDisplayIdentifier": lastSpaceActivationDisplayIdentifier ?? NSNull(),
@@ -388,6 +393,8 @@
             "lastCloseResult": lastCloseResult.map(Self.closeResultString) ?? NSNull(),
             "lastCloseError": lastCloseError ?? NSNull(),
             "suppressedCloseTargetCount": suppressedCloseTargets.count,
+            "suppressedActivationWindowCount": suppressedActivationWindowIDs.count,
+            "suppressedActivationWindowIDs": Array(suppressedActivationWindowIDs).sorted(),
             "lastDismissReason": lastDismissReason.map(Self.dismissReasonString) ?? NSNull(),
             "overlayLevel": Int(coordinator.currentLevel),
             "overlayMainMenuLevel": Int(CGWindowLevelForKey(.mainMenuWindow)),
@@ -568,9 +575,11 @@
         lastCommitSource = source
         lastActivationWindowID = selection.windowID
         lastActivationError = nil
+        lastActivationDurationMilliseconds = nil
 
         guard let window = window(for: selection, in: viewModel ?? currentViewModel) else {
             lastActivationResult = .windowNotFound
+            suppressActivationWindowID(selection.windowID, reason: "selectionMissing")
             DevelopmentDiagnostics.log("quickSwitch.activation.commit.windowNotFound", [
                 "source": source.rawValue,
                 "appGroupIndex": selection.appGroupIndex,
@@ -587,8 +596,10 @@
         ])
         hide(reason: .userClosed)
 
+        let activationStartedAt = CACurrentMediaTime()
         do {
             lastActivationResult = try windowActivationService.activate(window: window)
+            lastActivationDurationMilliseconds = (CACurrentMediaTime() - activationStartedAt) * 1_000
             DevelopmentDiagnostics.log("quickSwitch.activation.commit.result", [
                 "source": source.rawValue,
                 "windowID": window.id,
@@ -597,9 +608,11 @@
                 "titleHash": DevelopmentDiagnostics.stableFingerprint(window.title),
                 "titleLength": window.title.count,
                 "titleIsEmpty": window.title.isEmpty,
-                "result": lastActivationResult.map(Self.activationResultString)
+                "result": lastActivationResult.map(Self.activationResultString),
+                "durationMilliseconds": lastActivationDurationMilliseconds
             ])
         } catch {
+            lastActivationDurationMilliseconds = (CACurrentMediaTime() - activationStartedAt) * 1_000
             let errorSummary = DevelopmentDiagnostics.errorSummaryString(error)
             lastActivationResult = .failed(errorSummary)
             lastActivationError = errorSummary
@@ -609,10 +622,15 @@
                 "appName": window.app.name,
                 "titleHash": DevelopmentDiagnostics.stableFingerprint(window.title),
                 "titleLength": window.title.count,
-                "titleIsEmpty": window.title.isEmpty
+                "titleIsEmpty": window.title.isEmpty,
+                "durationMilliseconds": lastActivationDurationMilliseconds
             ]
             DevelopmentDiagnostics.errorSummaryFields(error).forEach { fields[$0.key] = $0.value }
             DevelopmentDiagnostics.log("quickSwitch.activation.commit.error", fields)
+        }
+
+        if shouldSuppressAfterActivationResult(lastActivationResult) {
+            suppressActivationWindowID(window.id, reason: lastActivationResult.map(Self.activationResultString) ?? "unknown")
         }
 
         if shouldCloseAfterActivation(lastActivationResult) {
@@ -629,7 +647,7 @@
 
     private func handleSpaceLaneClick(_ spaceID: UInt64, clickCount: Int) {
         if clickCount >= 2 {
-            if pendingLockedSpaceUnlockSpaceID == spaceID {
+            if pendingLockedSpaceUnlockSpaceID == spaceID || lockedSpaceFilterID == spaceID {
                 cancelPendingLockedSpaceUnlock()
                 activateLockedSpace(spaceID)
             } else {
@@ -961,18 +979,37 @@
         ])
     }
 
+    private func suppressActivationWindowID(_ windowID: UInt32, reason: String) {
+        guard windowID != 0 else { return }
+        suppressedActivationWindowIDs.insert(windowID)
+
+        guard let sourceViewModel else { return }
+        let visibleViewModel = projectedViewModel(from: sourceViewModel, preferredSelection: view.effectiveSelectionForProjection())
+        self.currentViewModel = visibleViewModel
+        view.applyProjected(viewModel: visibleViewModel)
+        DevelopmentDiagnostics.log("quickSwitch.activation.suppressWindow", [
+            "windowID": windowID,
+            "reason": reason,
+            "remainingWindowCount": visibleViewModel.windowCount,
+            "suppressedActivationWindowCount": suppressedActivationWindowIDs.count
+        ])
+    }
+
     private func viewModel(
         _ viewModel: QuickSwitchViewModel,
-        excluding suppressedTargets: [SuppressedCloseTarget]
+        excluding suppressedTargets: [SuppressedCloseTarget],
+        suppressedActivationWindowIDs: Set<UInt32> = []
     ) -> QuickSwitchViewModel {
-        guard !suppressedTargets.isEmpty else { return viewModel }
+        guard !suppressedTargets.isEmpty || !suppressedActivationWindowIDs.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
+                let isActivationSuppressed = suppressedActivationWindowIDs.contains(card.window.id)
+                let isCloseSuppressed = suppressedTargets.contains { target in
                     suppressedTarget(target, matches: card)
                 }
+                return !isActivationSuppressed && !isCloseSuppressed
             }
             guard !windows.isEmpty else { return nil }
 
@@ -1021,7 +1058,11 @@
         from sourceViewModel: QuickSwitchViewModel,
         preferredSelection: QuickSwitchSelection? = nil
     ) -> QuickSwitchViewModel {
-        let closeProjectedViewModel = viewModel(sourceViewModel, excluding: suppressedCloseTargets)
+        let closeProjectedViewModel = viewModel(
+            sourceViewModel,
+            excluding: suppressedCloseTargets,
+            suppressedActivationWindowIDs: suppressedActivationWindowIDs
+        )
         return QuickSwitchSpaceFilterPolicy.projectedViewModel(
             from: closeProjectedViewModel,
             lockedSpaceID: lockedSpaceFilterID,
@@ -1078,9 +1119,18 @@
 
     private func shouldCloseAfterActivation(_ result: WindowActivationResult?) -> Bool {
         switch result {
-        case .activated, .restored, .appActivatedOnly:
+        case .activated, .restored:
             return true
-        case .windowNotFound, .unsupported, .activationFailed, .failed, nil:
+        case .appActivatedOnly, .windowNotFound, .unsupported, .activationFailed, .failed, nil:
+            return false
+        }
+    }
+
+    private func shouldSuppressAfterActivationResult(_ result: WindowActivationResult?) -> Bool {
+        switch result {
+        case .windowNotFound, .unsupported, .activationFailed, .failed:
+            return true
+        case .activated, .restored, .appActivatedOnly, nil:
             return false
         }
     }
@@ -1534,6 +1584,7 @@
     let lifecycleCycles: Int?
     let lifecycleInterval: TimeInterval
     let lifecycleVisibleDuration: TimeInterval
+    let simulateDockReopenAfter: TimeInterval?
 
     static func parse(arguments: [String]) -> Round1QuickSwitchLaunchOptions {
         Round1QuickSwitchLaunchOptions(
@@ -1563,7 +1614,8 @@
             waterfallViewMode: waterfallViewModeValue(for: "--round01-waterfall-view-mode", in: arguments),
             lifecycleCycles: intValue(for: "--round01-quick-switch-lifecycle-cycles", in: arguments),
             lifecycleInterval: timeInterval(for: "--round01-quick-switch-lifecycle-interval", in: arguments) ?? 0.02,
-            lifecycleVisibleDuration: timeInterval(for: "--round01-quick-switch-lifecycle-visible-duration", in: arguments) ?? 0.16
+            lifecycleVisibleDuration: timeInterval(for: "--round01-quick-switch-lifecycle-visible-duration", in: arguments) ?? 0.16,
+            simulateDockReopenAfter: timeInterval(for: "--round01-simulate-dock-reopen-after", in: arguments)
         )
     }
 

--
Gitblit v1.9.3