실제 풀 리퀘스트 79개에 AI diff 리뷰어를 적용해 본 결과: 유지보자가 수정한 버그 4건, 모두 처음 29개에서 발견됨
요약
작성자는 AI 기반 도구를 개발하여 공용 풀 리퀘스트 79개에 적용하고 로직 버그를 플래그 지정했습니다. 분석 결과, 유지보자가 수정한 4개의 모든 수정 사항은 수동으로 선택한 소수의 PR에서만 발견되었습니다. 이는 자동화된 diff 검토가 항상 유효하지 않으며, 테스트 환경과 방법론의 중요성을 시사합니다.
핵심 포인트
- AI 도구를 이용해 공용 PR 79개에 로직 버그 플래그를 적용함.
- 수정된 4개의 모든 플래그는 수동으로 선택한 소수의 PR에서만 발견됨.
- 기계적 필터링을 거친 대다수의 PR에서는 유효한 수정 사항이 없었음.
- 도구는 오직 diff만을 분석하며, 리포지토리 전체 코드는 검토하지 못함.
Spacexcx 작성 · 2026년 11월
저는 git diff를 읽고 가능한 로직 버그(logic bugs)를 플래그 지정하는 작은 도구를 만들었습니다. 이 도구는 각 플래그 뒤에 있는 정확한 라인을 인용합니다. 저는 2026년 8월 말부터 10월 말까지 공용 풀 리퀘스트 79개에 이를 적용했고, 모든 플래그를 수동으로 확인했습니다.
결과는 불균형합니다. 작성자들에 의해 채택되고 수정된 플래그는 네 개였으며, 이 네 개 모두 제가 수동으로 선택한 14개의 풀 리퀘스트에서 나왔습니다. 다음 50개(기계적 필터로 선택)에서는 검토를 통과한 것이 전혀 없었습니다.
본 게시물에서는 제가 측정한 내용, 격차의 원인이라고 추측하는 바, 그리고 명확히 구분할 수 없는 내용을 다룹니다.
공개 고지: 이 도구는 AI 기반(Gemini Flash, 무료 등급)입니다. 저는 보고서를 작성하기 전에 모든 플래그를 코드와 비교하여 직접 읽었습니다. 댓글과 이메일은 모두 제가 직접 작성하고 검증하여 보냈으며, 도구는 오직 제 컴퓨터에서 diff만 로컬로 분석했을 뿐 GitHub에 아무것도 게시하지 않았습니다.
요약 (TL;DR)
- 총 79개의 PR을 계산했으며, 총 9개의 플래그가 있었습니다.
- 유지보자에 의해 수정된 플래그는 4개였고, 제가 코드를 읽은 후 폐기한 플래그는 4개였으며, 답장을 받지 못한 것은 1개였습니다.
- 수정된 4개의 모든 플래그는 수동으로 선택한 14개의 열린 PR에서 나왔습니다. 필터링된 50개의 PR에서는 0개가 나왔습니다.
- 알려진 과거 회귀(regression) 사례 5개를 대상으로 한 소규모 블라인드 테스트에서 4개를 포착했습니다 (n=5이므로 일화로 간주하십시오).
- 아직 아무도 이 도구를 설치하지 않았습니다. 커뮤니티 게시물 하나를 시도해 봤는데, 답장 0개, 설치 0개였습니다.
도구의 작동 방식
이 도구는 diff를 Gemini Flash 모델로 전송한 다음, 제가 보기 전에 첫 번째 패스에서 지정된 플래그들을 비평하는 두 번째 단계를 실행합니다. 모든 플래그는 추가되거나 제거된 정확한 라인을 인용해야 하며, 코드는 이 인용을 프로그램적으로 확인합니다. 이 도구는 Markdown이나 문서 파일, lockfile, 변경되지 않은 컨텍스트 라인은 무시합니다. 오직 diff만 보고, 리포지토리의 나머지 부분은 보지 못합니다.
제가 실행한 방법
| Phase | PRs | 선택 방식 | 모델 | 프롬프트 |
|---|---|---|---|---|
| Tuning | 15 | 과거 병합된 Godot PR, 프롬프트 튜닝에 사용됨 | gemini-1.5-flash | v0.1 |
| ... |
카운트에서 제외된 항목: 별점 한도(star ceiling)를 초과하는 프로젝트의 2개 PR(curl 및 sqlmodel, 이들 사이에서 폐기된 플래그 1개 포함)와 8개 파일 제한을 초과하여 스캔되지 않은 Transmission PR 3개.
“수정됨(fixed)”으로 간주되는 것
플래그는 작성자가 이를 인정했거나 코드를 변경했을 때만 수정된 것으로 간주됩니다. 저는 작성자들이 수행한 내용을 보고하고 있습니다. 각각의 항목이 입증된 충돌(crash)이나 악용 가능한 취약점(exploitable)이었다고 주장하는 것은 아닙니다.
결과
| Set | PRs | 플래그 수 | 작성자에 의해 수정됨 | 검토 후 폐기됨 | 미해결 |
|---|---|---|---|---|---|
| Tuning (병합됨) | 15 | 1 | 0 | 1 | 0 |
| ... |
네 가지 수정 사항
- driftbench #15 (PR #26에서 수정): difflib 기반 코드의 길이 0 삽입 op-code 케이스. 작성자가 이를 수정하고 보고 크레딧과 함께 병합했습니다.
- Godot #119097: Joint3D에서 가능한 null 역참조(null dereference). 작성자가 감사 인사를 전하며 이를 수정했습니다.
- Godot #123641: 노드 후손 경로 처리(node descendant path handling)에서의 재귀 문제(recursion problem). 검토 스레드가 해결되었고 코드가 업데이트되었습니다.
- PyTorch #197776: dynamo 메모리 변수 코드에서의 임포트 시간 충돌(import-time crash). 작성자가
memory.py만 건드린 커밋(2b2c4fc)으로 수정했습니다.
잘못되었거나 해결되지 않은 플래그
코드를 읽은 후 네 개의 플래그를 폐기했습니다: 재귀 뮤텍스를 비재귀(non-recursive)로 잘못 취급한 교착 상태 주장(deadlock claim) (이것은 비평 패스에서 포착됨), 동시성 경고(concurrency warning), 부울 복잡도 경고(boolean-complexity warning), 그리고 std::all_of로 리팩토링되었으며 이미 손상된 입력에서만 다르게 작동하는 루프에 대한 제어 흐름 경고(control-flow warning). 또 다른 플래그는 open firmware 툴 PR의 정의되지 않았을 수 있는 이름에 관한 것이었으나 답장을 받지 못했기 때문에 맞는지 알 수 없습니다.
PR 번호와 작성자 이름이 제거된 전체 원본 데이터셋은 다음 저장소에 문서화되어 있습니다: https://github.com/Spacexcx/pr-check
블라인드 테스트 (The blind test)
이 도구를 알려진 과거 회귀 사례 5건(Python 2개, C 3개)에 적용했습니다. 첫 번째 시도에서 4건을 플래그 지정했고, 웹 라이브러리의 호스트 매칭 정규 표현식 문제 1건은 놓쳤습니다. 5가지 케이스만으로는 불확실성이 매우 크고, curl 사례들은 잘 문서화되어 있어 모델이 이미 이를 학습했을 수 있습니다. 따라서 "80% 재현율(recall)"이라고 해석해서는 안 됩니다.
격차 (The gap)
수동으로 선별한 14개 PR 중 4개가 수정 사항을 도출했습니다(29%, 대략적인 95% 신뢰 구간은 12~55%). 필터링된 50개 PR 중에서는 0건이었습니다. 만약 해당 필터 하의 실제 비율이 6% 이상이었다면, 50개에서 0건을 보는 것은 어려울 것이므로 저는 그 비율이 더 낮다고 추측합니다. 만약 네 가지 수정 사항이 전체 64개의 독립적인 PR에 무작위로 분포했다면, 이 네 가지가 모두 14개 PR 그룹에 속할 확률은 약 0.002입니다. 따라서 이 격차는 노이즈일 가능성이 낮습니다. 하지만 이것이 왜 존재하는지는 알려주지 않습니다. 다음은 제가 제시하는 후보 설명들이며, 저는 그중 어느 것도 테스트하지 않았습니다:
- 제 타겟팅. 첫 번째 세트에서는 도구의 결과와 버그가 숨어 있을 만한 지점에 대한 저의 직관을 함께 측정했습니다.
- 저장소 복잡성. Godot과 PyTorch는 공유 상태(shared state)가 많은 거대한 코드베이스입니다.
- 필터. 공개 이메일 주소를 가진 작성자가 만든, 파일 1개에서 8개 사이의 작은 PR들로 구성되어 있으며, CI(지속적 통합, Continuous Integration)가 강력한 저장소에 한정되었습니다. 50개 PR 배치에 있는 모든 PR은 스캔 당시 병합되지 않고 열려 있어 활발하게 검토 중이었습니다.
- 도구의 변화. 증거 확인(evidence check) 및 비평 단계는 수동으로 선별한 단계부터 적용되었지만, 모델과 프롬프트가 단계별로 변경되었고, C/C++ 실행에는 더 가벼운 모델이 사용되었습니다. 저는 이것을 배제할 수 없습니다.
또 다른 데이터 포인트는 반대 방향의 증거를 제시합니다. 튜닝에 사용된 15개 PR 역시 Godot 관련이었으며, 이들에서도 수정 사항은 도출되지 않았습니다. 이들은 이미 병합되었고 제가 이를 기반으로 튜닝했기 때문에 큰 의미를 부여할 수는 없지만, 저장소 크기만으로는 격차를 설명할 수 없다는 것을 시사합니다.
다르게 할 일 (What I'd do differently)”,
동일한 저장소에서 PR(Pull Request)을 무작위로 선택하고, 시작하기 전에 모델과 프롬프트를 고정하며(freeze), 사전에 선택 규칙을 결정하고, 각 PR이 열렸는지(open) 또는 병합되었는지(merged) 기록합니다.
또 다른 결과
제가 이 도트에 대해 개발자 커뮤니티 쇼케이스에 한 번 게시했습니다. 5일 동안 답글이나 설치가 없었으며, 저장소에는 별점 3개가 있습니다. 만약 사이드 프로젝트나 오픈 소스 저장소에서 일주일 동안 사용해보고 싶다면, 무엇이 거슬렸는지 그리고 왜 그것을 유지했거나 제거했는지 듣고 싶습니다. 제거했다는 것 역시 완전히 유용한 답변입니다. 사용자의 diff는 자체 키를 사용하여 Google의 Gemini API로 전송되며, Windows .exe 파일은 서명되지 않았습니다(SmartScreen에서 경고가 뜰 것입니다). 또한 Python 버전도 이용 가능합니다. 저장소: https://github.com/Spacexcx/pr-check
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기