Ariver
2026-06-18 b6e11990cc9bd3c838ad6cdd9e53caafff0fd7cb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#!/bin/bash
# Round01 AltTab conflict QA. It starts AltTab when available, verifies Aligner
# still receives Option+Tab, then verifies the same path after AltTab exits.
# It does not rebuild/package, so candidate DMG hashes stay stable.
 
set -euo pipefail
 
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OUTPUT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=build-output-paths.sh
source "$SCRIPT_DIR/build-output-paths.sh"
APP="$BUILD_CURRENT_APP"
REPORT="$BUILD_REPORT_ROOT/round01-alttab-conflict-report.json"
ALTTAB_APP="${ALIGNER_ROUND1_ALTTAB_APP:-/Applications/AltTab.app}"
START_WAIT="${ALIGNER_ROUND1_ALTTAB_START_WAIT:-1.6}"
OPEN_WAIT="${ALIGNER_ROUND1_ALTTAB_OPEN_WAIT:-0.8}"
CLOSE_WAIT="${ALIGNER_ROUND1_ALTTAB_CLOSE_WAIT:-0.8}"
SAMPLER_DURATION="${ALIGNER_ROUND1_ALTTAB_SAMPLE_DURATION:-1.4}"
SAMPLER_INTERVAL="${ALIGNER_ROUND1_ALTTAB_SAMPLE_INTERVAL:-0.03}"
WORK_DIR="${ALIGNER_ROUND1_ALTTAB_WORK_DIR:-$(mktemp -d /tmp/aligner-round01-alttab-conflict.XXXXXX)}"
ORIGINAL_ALTTAB_RUNNING=0
ALIGNER_PID=""
ACTIVE_SAMPLER_PID=""
 
fail() {
  echo "Round01 AltTab conflict QA failed: $*" >&2
  exit 1
}
 
is_alttab_running() {
  pgrep -x AltTab >/dev/null 2>&1
}
 
start_alttab() {
    [ -d "$ALTTAB_APP" ] || fail "AltTab app not found: $ALTTAB_APP"
    open "$ALTTAB_APP"
    for _ in {1..50}; do
    if is_alttab_running; then
      return 0
    fi
    sleep 0.1
  done
  fail "AltTab did not start"
}
 
stop_alttab() {
  if ! is_alttab_running; then
    return
  fi
 
  osascript -e 'tell application "AltTab" to quit' >/dev/null 2>&1 || true
  for _ in {1..30}; do
    if ! is_alttab_running; then
      return 0
    fi
    sleep 0.1
  done
 
  pkill -x AltTab >/dev/null 2>&1 || true
  for _ in {1..30}; do
    if ! is_alttab_running; then
      return 0
    fi
    sleep 0.1
  done
 
  fail "AltTab did not exit"
}
 
post_key_with_system_events() {
  local shortcut="$1"
  case "$shortcut" in
    option-tab)
      osascript -e 'tell application "System Events" to key code 48 using {option down}' >/dev/null
      ;;
    escape)
      osascript -e 'tell application "System Events" to key code 53' >/dev/null
      ;;
    *)
      fail "unsupported System Events shortcut: $shortcut"
      ;;
  esac
}
 
aligner_pids_for_current_app() {
  ps -axo pid=,args= | while read -r pid command; do
    case "$command" in
      "$APP/Contents/MacOS/Aligner"*) echo "$pid" ;;
    esac
  done
}
 
stop_current_aligner() {
  for pid in $(aligner_pids_for_current_app); do
    kill "$pid" 2>/dev/null || true
  done
 
  for _ in {1..30}; do
    [ -z "$(aligner_pids_for_current_app)" ] && return
    sleep 0.1
  done
 
  fail "current Aligner app did not exit before QA"
}
 
run_window_logic_check() {
  swift "$SCRIPT_DIR/window-logic-qa.swift" "$@" 2>&1 | head -c 6000
  local status="${PIPESTATUS[0]}"
  return "$status"
}
 
wait_for_no_quick_switch() {
  local timeout="$1"
  /usr/bin/python3 - "$SCRIPT_DIR" "$timeout" <<'PY'
import subprocess
import sys
import time
 
script_dir = sys.argv[1]
timeout = float(sys.argv[2])
deadline = time.monotonic() + timeout
last_output = ""
 
while time.monotonic() < deadline:
    result = subprocess.run(
        ["swift", f"{script_dir}/window-logic-qa.swift", "--expect-no-quick-switch"],
        text=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
    )
    last_output = result.stdout
    if result.returncode == 0:
        print(last_output[-6000:], end="")
        sys.exit(0)
    time.sleep(0.2)
 
print(last_output[-6000:], end="")
sys.exit(1)
PY
}
 
run_aligner_trigger_case() {
  local label="$1"
  local aligner_log="$WORK_DIR/aligner-$label.log"
  local sampler_stdout="$WORK_DIR/alttab-visible-$label.stdout"
  local sampler_report="$WORK_DIR/alttab-visible-$label.report"
  local sampler_pid=""
 
  rm -f "$REPORT"
 
  "$APP/Contents/MacOS/Aligner" \
    --round0-skip-permissions \
    --round01-quick-switch-report="$REPORT" >"$aligner_log" 2>&1 &
  ALIGNER_PID=$!
 
  sleep "$START_WAIT"
  if ! kill -0 "$ALIGNER_PID" 2>/dev/null; then
    tail -c 6000 "$aligner_log" >&2 || true
    fail "Aligner exited before $label trigger"
  fi
 
  swift "$SCRIPT_DIR/round1-move-mouse-to-screen-center.swift" 0 2>&1 | head -c 6000
  if is_alttab_running; then
    swift "$SCRIPT_DIR/round1-visible-owner-window-sampler.swift" \
      "AltTab" "$SAMPLER_DURATION" "$SAMPLER_INTERVAL" "$sampler_report" >"$sampler_stdout" 2>&1 &
    sampler_pid=$!
    ACTIVE_SAMPLER_PID="$sampler_pid"
    sleep 0.05
  fi
 
  post_key_with_system_events option-tab
  sleep "$OPEN_WAIT"
 
  echo "==> $label"
  echo "AltTab running: $(is_alttab_running && echo yes || echo no)"
  run_window_logic_check \
    --expect-quick-switch \
    --expect-single-aligner-overlay \
    --expect-overlay-on-mouse-screen \
    --expect-overlay-uses-screen-frame
 
  if [ -n "$sampler_pid" ]; then
    if ! wait "$sampler_pid"; then
      ACTIVE_SAMPLER_PID=""
      tail -c 6000 "$sampler_stdout" >&2 || true
      tail -c 6000 "$sampler_report" >&2 || true
      fail "visible AltTab window appeared during $label"
    fi
    ACTIVE_SAMPLER_PID=""
    tail -c 6000 "$sampler_stdout"
  fi
 
  post_key_with_system_events escape
  sleep "$CLOSE_WAIT"
  wait_for_no_quick_switch 5.0
 
  kill "$ALIGNER_PID" 2>/dev/null || true
  wait "$ALIGNER_PID" 2>/dev/null || true
  ALIGNER_PID=""
}
 
cleanup_runtime_only() {
  post_key_with_system_events escape 2>/dev/null || true
  if [ -n "$ACTIVE_SAMPLER_PID" ] && kill -0 "$ACTIVE_SAMPLER_PID" 2>/dev/null; then
    kill "$ACTIVE_SAMPLER_PID" 2>/dev/null || true
    wait "$ACTIVE_SAMPLER_PID" 2>/dev/null || true
  fi
  ACTIVE_SAMPLER_PID=""
  if [ -n "${ALIGNER_PID:-}" ] && kill -0 "$ALIGNER_PID" 2>/dev/null; then
    kill "$ALIGNER_PID" 2>/dev/null || true
    wait "$ALIGNER_PID" 2>/dev/null || true
  fi
  ALIGNER_PID=""
}
 
restore_original_alttab_state() {
  if [ "$ORIGINAL_ALTTAB_RUNNING" -eq 1 ]; then
    start_alttab
  else
    stop_alttab
  fi
}
 
assert_original_alttab_state() {
  local final_running=0
  if is_alttab_running; then
    final_running=1
  fi
 
  echo "Original AltTab running: $([ "$ORIGINAL_ALTTAB_RUNNING" -eq 1 ] && echo yes || echo no)"
  echo "Final AltTab running: $([ "$final_running" -eq 1 ] && echo yes || echo no)"
 
  if [ "$final_running" -ne "$ORIGINAL_ALTTAB_RUNNING" ]; then
    fail "AltTab final state did not match original state"
  fi
}
 
cleanup() {
  cleanup_runtime_only
  restore_original_alttab_state >/dev/null 2>&1 || true
}
 
trap cleanup EXIT
 
[ -x "$APP/Contents/MacOS/Aligner" ] || fail "missing built app: $APP"
 
if is_alttab_running; then
  ORIGINAL_ALTTAB_RUNNING=1
fi
 
stop_current_aligner
start_alttab
run_aligner_trigger_case "alttab-running"
 
stop_alttab
run_aligner_trigger_case "alttab-stopped"
 
cleanup_runtime_only
restore_original_alttab_state
assert_original_alttab_state
 
trap - EXIT
 
echo "Log directory: $WORK_DIR"
echo "Round01 AltTab conflict QA passed"