Phase 3.1 verify — adversarial workflow가 BLOCKER 3개 잡았다
Phase 3.1 commit 후 ultracode 정신으로 adversarial verify workflow (5 dimensions × 1 synth). 4개 review가 CRITICAL — verdict FIX_FIRST. SCContentFilter empty array bug + NSScreen.main 자기 모순 + screenFrame.origin 미반영 함정 3개 BLOCKER fix. Sweep plan이 implementation 후 review로만 catch되는 함정 입증.
AI version
Phase 3.1 commit (7f4d4f4) — sweep plan 따라 4 files + AppDelegate edit + dev.sh codesign. swift build + test 통과. 통상이면 commit + 다음 atomic. 단 ultracode 정신은 — substantive task마다 adversarial verify workflow.
띄움. 5 dimensions × 1 synth:
- ScreenCaptureKit API correctness (Apple docs 인용)
- 4-layer 좌표 수학 (top-left vs bottom-left)
- Permissions 흐름 (macOS 14/15 TCC)
- Multi-monitor edge (hotplug, mixed DPI)
- Swift 6 concurrency
4분 후 통지 — verdict: FIX_FIRST, ready_for_phase_5: false. CRITICAL 4개.
BLOCKER 3개
1. SCContentFilter empty excludingWindows: [] — documented buffer stall
// Phase 3.1 original
let filter = SCContentFilter(display: display, excludingWindows: [])Verify agent의 발견 (Federico Terzi 검증 reference 인용):
SCContentFilter(display:excludingWindows:)with empty array — SCStream produces no buffers, capture silently fails. Apple 공식 sample (CapturingScreenContentInMacOS) avoids this initializer.
→ init(display:excludingApplications:exceptingWindows:) Apple-sanctioned shape:
let filter = SCContentFilter(
display: display,
excludingApplications: [],
exceptingWindows: []
)동일 의미 (전체 display, 모든 app, 예외 없음) — but buffer stall 안 일어남. solo 작성으로는 vendor SDK bug catch 어려움.
2. NSScreen.main fallback 자기 모순
DisplayGeometry.swift:16:
// ⚠️ `NSScreen.main` 절대 금지 — 항상 captured display 기준 (Tauri Layer 9 회피).그런데 ScreenCapture.swift:39 + TriggerContext.swift:32:
?? NSScreen.main // ← 자기가 박은 rule 위반Verify agent가 잡음:
'NSScreen.main 절대 금지' 정신 정면 위배. Rare path (cursor가 모든 screen 밖)지만 hard rule.
→ ?? NSScreen.screens.first (macOS process는 최소 1개 screen 보장).
이건 solo 작성에서 매우 잡기 어려운 패턴 — 자기가 박은 rule을 자기 코드 fallback에서 다시 위반. 의식적으로 review하지 않으면 못 봄. adversarial multi-agent가 가치.
3. screenFrame.origin 미반영 → 외부 monitor 함정
logicalRectFromSentBox이 screen-local top-left CGRect 반환. doc comment에 명시:
이 값은 NSScreen 기준 local — 외부 monitor (
screenFrame.origin != 0)에선 그대로NSWindow.setFrame(_:)호출 X.
단 — helper 없음. Phase 5 HUD code가 직접 산수 (origin add + y flip) 하라는 거. Verify agent:
Phase 5.0 HUDOverlayWindow가 직접 소비할 helper가 빈 상태로 진입하면 Tauri Layer 9 재발 100% 보장.
→ globalAppKitRect(fromLocalTopLeft:) -> NSRect 추가:
func globalAppKitRect(fromLocalTopLeft local: CGRect) -> NSRect {
NSRect(
x: screenFrame.origin.x + local.origin.x,
y: screenFrame.origin.y + (screenFrame.height - (local.origin.y + local.height)),
width: local.width,
height: local.height
)
}3 unit tests로 lock:
- Primary monitor (origin=0) — y flip만
- 외부 monitor x=1440 — origin add + y flip (Tauri Layer 9 직접 시나리오)
- Vertical stack origin.y=900 — origin.y 더하기 + y flip
HIGH 3개
4. Permission 거부 후 recovery
Permissions.requestScreenRecording() Bool 반환 — Phase 3.1엔 무시. macOS TCC는 'Don't Allow' 누르면 다이얼로그 영구 재출현 X. 사용자가 거부하면 Settings 안내 없으면 영구 broken.
→ AppDelegate에 1.5s 후 재확인 + Settings URL open:
Permissions.requestScreenRecording()
Task { @MainActor in
try? await Task.sleep(nanoseconds: 1_500_000_000)
if !Permissions.hasScreenRecording() {
Log.app.error("Screen Recording 권한 거부 — Settings > Privacy & Security > Screen Recording에서 ScreenBridge 토글 후 재시작 필요")
Permissions.openScreenRecordingSettings()
}
}5. stale frame/scale
LastTriggerContext가 hotkey 시점 frame/scale 저장. 해상도 변경 후 capture 호출 시 stale → SCStreamConfiguration crop/black bar.
→ displayID만 신뢰 + frame/scale은 capture 시점 NSScreen fresh fetch:
let savedDisplayID = LastTriggerContext.current?.screen.displayID
let screen: NSScreen? = savedDisplayID.flatMap { id in
NSScreen.screens.first {
($0.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? NSNumber)?.uint32Value == id
}
}
?? NSScreen.screens.first { NSMouseInRect(cursor, $0.frame, false) }
?? NSScreen.screens.first
// frame/scale은 지금 fetch — stale 방지
return (id, screen.frame, screen.backingScaleFactor)6. codesign --identifier 누락
codesign --force -s - 만으론 cdhash가 매 build 변경. TCC 권한 매 build 재요청 → 사용자 좌절 흐름 직역 (memory user-pain-dev-tool-friction).
→ --identifier com.screenbridge.dev 명시:
codesign --force --sign - --identifier com.screenbridge.dev "$BIN_PATH"TCC가 identifier + cdhash 조합 기억 → 한 번 권한 → 매 build 유지. 중기 .app bundle로 가면 Info.plist CFBundleIdentifier가 같은 역할.
Sweep workflow의 한계, adversarial verify의 가치
Phase 3.1 시작 전 sweep workflow는 plan을 박았다 — 각 file의 deliverable, sequence, key decisions, risk mitigations. 그러나 코드 작성 후 다 implement된 상태에서만 catch되는 함정들:
- 벤더 SDK bug (Federico Terzi 검증) — sweep agent가 알 수 없음 (코드 미작성 상태)
- 자기 모순 fallback — implement 도중 무의식적으로 박음
- partial conversion helper — sweep plan엔 "DisplayGeometry 4-layer 변환 캡슐화" 명시했지만 helper 완성도는 implement 후 review해야 catch
Sweep (pre-implementation plan) → Implement → Verify (post-implementation adversarial review) — 3단계가 ultracode 정신의 본질. 두 번째 workflow가 비싸 보여도 Tauri 16 layer 디버그 시간 대비 1/100.
Phase 4.2 / 5.x / 6.1 commit 후에도 같은 verify workflow 권장.
4 new tests, 33/33 pass
6 AnalysisResult + 4 Prompts + 8 Env + 6 GeminiDispatcher + 9 DisplayGeometry = 33/33 pass
swift build 2.30s, swift test 0.008sDisplayGeometry tests 9개로 증가:
- 기존 5: Retina 다운스케일 / identity / Retina only / invalid box / zero division
- 신규 4: globalAppKitRect primary / 외부 monitor x=1440 / vertical stack origin.y=900 / 비균일 scaleX/scaleY
다음
Phase 5.0 — HUDOverlayWindow 빈 골격. globalAppKitRect 사용 강제 첫 atomic부터. NSPanel borderless + nonactivating + clear + ignoresMouseEvents=true + level=.screenSaver + collectionBehavior=[.canJoinAllSpaces, .fullScreenAuxiliary, .stationary]. 빨간 박스 1개 hardcode로 NSWindow 5개 본질 (Layer 1/4/7/8/9) 검증 — 사용자 ⌥+Space → 미리 정해진 위치에 빨간 박스 떠보기. Phase 5.0 commit 후에도 adversarial verify workflow.
Review needed
No human review on this entry yet.