Steven
Steven4 분 소요

화면 녹화가 왜 엉뚱한 모니터를 잡는가 (그리고 우리의 수정)

듀얼 모니터 환경에서 GeekBye는 당신이 어느 화면에서 작업하든 주 디스플레이를 녹화하고 스크린샷했습니다. 수정은 작은 함수 하나였습니다 — 그런데 그 첫 버전은 틀렸고, 코드 리뷰가 그 이유를 잡아냈습니다.

화면 녹화
멀티 디스플레이
엔지니어링
GeekBye 릴리스
화면 녹화가 왜 엉뚱한 모니터를 잡는가 (그리고 우리의 수정)

이건 모니터를 두 대 가진 경우에만 존재하는 버그입니다 — 그래서 한동안 조용히 살아 있었죠. 옆 화면에서 작업하다가 GeekBye 녹화를 시작하면, 녹화되는 건 모니터입니다. 메뉴 막대가 있는 쪽. 당신이 보고 있지 않던 쪽.

같은 결함이, 더 조용하고 더 고약한 형태로, GeekBye가 컨텍스트로 AI에 보내는 스크린샷을 덮쳤습니다. 두 번째 모니터에서 스크린샷 단축키를 누르면, AI는 첫 번째 모니터의 그림을 받습니다. 눈에 보이는 표시는 없고 — 어시스턴트는 그냥 엉뚱한 화면에 대해 답하고, 당신은 왜 얘가 헷갈려 하는지 의아해합니다. GeekBye v2.0.10이 둘 다 고쳤습니다.

두 파이프라인, 하나의 게으른 기본값

데스크톱의 화면 캡처는 서로 다른 두 개의 코드 경로이고, 둘 다 독립적으로 주 디스플레이를 선택하고 있었습니다:

  • 영상 녹화는 사용 가능한 화면 소스를 열거해 첫 번째 것 — sources[0] 을 취했습니다. macOS에서 그건 사실상 언제나 주 디스플레이입니다. 선택기도 없고, 당신이 실제로 어디에 있었는지에 대한 로직도 없습니다. 우리 코드 안 주석에는 말 그대로 "첫 번째 화면 소스를 자동 선택" 이라고 적혀 있었습니다.
  • 스크린샷은 macOS screencapture 명령을 -m 플래그와 함께 썼습니다. 그 플래그의 의미는 딱 하나: 주 디스플레이만. 하드코딩이었습니다.

두 경로 모두 정작 중요한 질문을 한 번도 던지지 않았습니다: 사용자는 어느 화면에 있는가?

한 번도 망가진 적 없던 것 하나를, 다들 그렇다고 넘겨짚기에 짚고 넘어갑니다: 같은 모니터에서 macOS Spaces를 전환하는 건 늘 제대로 작동했습니다. 캡처는 디스플레이 단위로 일어나며 — 선택된 디스플레이에 보이는 Space가 무엇이든 그걸 잡습니다. 이 버그는 결코 Spaces에 관한 게 아니었습니다. 늘 엉뚱한 물리 디스플레이를 고르는 문제였습니다.

뻔해 보였던 — 그리고 틀렸던 수정

올바른 신호는 쉬워 보입니다: 사용자가 있는 디스플레이를 캡처하라. 우리 첫 구현은 GeekBye의 오버레이 창을 기준으로 삼았습니다 — 오버레이가 사는 디스플레이를 캡처한다는 것이었죠.

코드 리뷰가 그것을 옳게 죽였습니다. GeekBye의 오버레이는 주 디스플레이 위에, 위치 (0,0)에, 작업 영역 전체를 덮는 창으로 생성됩니다. 당신이 그 알약(pill)을 물리적으로 다른 모니터로 끌어다 놓았을 때만 이동하고 — 그것을 밀어 옮기는 키보드 단축키는 주 디스플레이의 치수로 클램프되기 때문에, 두 번째 모니터로는 아예 옮길 수 없습니다. 오버레이를 기준으로 캡처한다는 것은 곧: 오버레이를 자기 작업 화면으로 끌어다 놓지 않은 모든 사용자에게, 그 "수정"은 곧장 주 디스플레이로 되돌아간다는 뜻이었습니다. 거의 아무도 안 고쳐졌을 겁니다 — 그러면서도 싱글 모니터 개발 머신에서의 빠른 테스트에서는 잘 되는 것처럼 보였고요.

올바른 기준은 커서입니다. 마우스가 있는 곳, 그게 당신이 작업하는 디스플레이입니다 — 그리고 그건 캡처가 시작되는 모든 방식에서 옳습니다: 키보드 단축키는 당신이 가리키는 곳에서 발화하고, Record 버튼을 클릭하면 정의상 당신의 커서는 그 디스플레이에 있습니다. 최종 수정은 두 줄짜리 함수입니다: 커서에 가장 가까운 디스플레이. 영상은 자신의 캡처 소스를 그 디스플레이의 id에 맞추고; 스크린샷은 -m 주 디스플레이 플래그 대신 그 디스플레이의 경계를 screencapture -R (특정 사각형)에 넘깁니다.

우리는 의도적으로 -R (전역 화면 좌표의 명시적 사각형)을 -D (디스플레이 인덱스)보다 택했습니다: OS 디스플레이 인덱스는 프레임워크의 디스플레이 순서와 대응한다는 보장이 없어서, 인덱스로 가면 또 한 번의 추측 게임이 되기 때문입니다. 실제 디스플레이 경계에서 나온 사각형은 모호함이 없습니다 — 그리고 출시 전에, 주 화면 왼쪽에 배치된 디스플레이의 음수 좌표를 포함해, 이 플래그의 동작을 실제 멀티 모니터 장비에서 검증했습니다.

왜 이게 좋은 교보재 버그인가

  1. "화면을 캡처하라"는 하나의 결정을 숨긴다. 디스플레이가 하나면 결정이 없으니, 그 결정은 설계되지 않고 — 기본값으로 넘어갑니다. 멀티 모니터는 모든 암묵적 기본값이 표면으로 드러나는 곳입니다.
  2. 조용히 틀린 것이 눈에 띄게 틀린 것보다 나쁘다. 영상 버그는 사람들을 짜증나게 했습니다. 스크린샷 버그는 AI를, 보이지 않게 오도했습니다. 모델에 컨텍스트를 먹이는 기능을 만들 때, 잘못된 입력은 어디에도 오류 없이 자신만만하게 틀린 출력을 냅니다. 그런 게 가장 악착같이 사냥할 가치가 있는 실패입니다.
  3. 내 기계에서 통과하는 수정이 다른 모두의 기계에서는 실패할 수 있다. 오버레이 기준 버전은 싱글 모니터 테스트에서 작동했습니다. 이 버그의 핵심 자체가 여러 모니터입니다 — 그리고 리뷰어는 초록불 테스트를 믿는 대신 창의 실제 위치에 대해 추론했습니다. 리뷰는 작동하는 코드에 찍는 고무도장이 아닙니다; 그건 코드가 작동하는지에 대한 두 번째 모델입니다.

GeekBye v2.0.10은 녹화와 스크린샷 둘 다에 커서 기반 수정을 출시합니다. 여러 디스플레이를 쓴다면, 캡처는 이제 당신을 따라옵니다.

이 시리즈의 이웃 릴리스는 AI 노트테이커는 왜 회의 중간에 녹음을 멈추는가(v2.0.9)와 AI 전사가 왜 기술 용어를 잘못 알아듣는가(v2.0.11)를 보세요. 통화 중 오버레이가 어떻게 동작하는지는 화면 공유 중에 보이지 않게 유지하는 법을 참고하세요.

관련 글

방화벽이 WebSocket을 막을 때, 실시간 전사는 어떻게 되는가
Steven
Steven4 분 소요

방화벽이 WebSocket을 막을 때, 실시간 전사는 어떻게 되는가

기업 네트워크는 HTTPS는 통과시키면서 WebSocket 업그레이드는 조용히 죽여버리길 좋아합니다. 그게 실시간 전사를 소리 없이 망가뜨립니다. GeekBye v2.0.8은 순수 HTTPS 트랜스포트로 자동 폴백합니다 — 그리고 그걸 출시하는 과정에서, 기능 전체를 무용지물로 만들 뻔한 버그가 드러났습니다.

전사
네트워킹
엔지니어링
우리 앱이 스스로에게 DDoS를 건 날
Steven
Steven4 분 소요

우리 앱이 스스로에게 DDoS를 건 날

기동 시 한꺼번에 풀려난 밀린 업로드 더미가, 모든 GeekBye 클라이언트를 우리 자신의 서버에 대한 작은 서비스 거부 공격으로 바꿔놓았습니다. 그 수정 — 그리고 그것이 우리에게 짓게 만든 연결 생존성 사다리 — 은 v2가 가르쳐준 가장 쓸모 있는 것 중 하나입니다.

신뢰성
네트워킹
엔지니어링
버전 2에 정말로 필요한 것: 정직한 상태를 위한 206개의 커밋
Steven
Steven5 분 소요

버전 2에 정말로 필요한 것: 정직한 상태를 위한 206개의 커밋

GeekBye v2는 기능 릴리스가 아니었습니다. 그것은 단 하나의 생각을 겨냥한 206개의 커밋이었습니다 — 앱은 결코 자신의 상태에 대해 거짓말해서는 안 된다는 것. 그 대가가 무엇인지 여기 적습니다 — 우리가 그 어느 것도 출시하지 못할 뻔하게 만든, 한 줄짜리 잠금 파일 실수까지 포함해서.

신뢰성
엔지니어링
릴리스