Shadcn-UI/UI에서 200개의 PR을 분석해 중복을 찾았습니다: 놀라울 정도로 잘 진행됐습니다.

발행: (2026년 4월 20일 AM 06:41 GMT+9)
11 분 소요
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line exactly as you’ve shown it and preserve all formatting, markdown, and technical terms.

PR Redundancy Audit – shadcn‑ui/ui

Pete의 트윗에서 영감을 받아, OpenClaw와 같은 고트래픽 레포에서 PR이 폭주하는 현상을 다룹니다. AI 에이전트는 코딩에 뛰어나지만, 중복 로직과 유지보수자의 장기 비전과 맞지 않는 PR을 생성하기도 합니다. 이 프로젝트는 PR을 감사하고 해당 태그를 지정합니다.

목표

두 명(또는 그 이상)의 기여자가 동일한 기능적 문제를 완전히 다른 방식으로 해결했는지 식별합니다. 이는 종종 서로 다른 파일에 걸쳐 발생합니다.

시스템은 복사‑붙여넣기된 라인을 찾는 것이 아니라 아키텍처적 목표를 평가합니다. 일치가 발견되면 PR을 다음 세 가지 버킷 중 하나로 분류합니다:

버킷설명
SHADOW동일한 회귀에 대한 정확히 동일한 수정.
SUPERSET더 작은, 구체적인 수정을 포함하는 보다 넓은 아키텍처 수정.
COMPETING동일한 기능적 결과를 달성하기 위해 선택된 두 가지 다른 경로.

아래 모든 예시는 깨진 /blocks 페이지 링크를 수정하는 것을 목표로 합니다.

샘플 PR (동일한 기능 실패, 다른 파일)

PR 번호제목전략수정된 파일
#10156fix: update broken link on /blocks pageSimple URL replacementapps/www/config/docs.ts
#10088fix(docs): absolute path for blocks linkPath normalizationapps/www/lib/utils.ts
#10096chore: rename internal block referencesRefactoring the reference keyapps/www/registry/registry.json

변경 사항이 완전히 별개의 파일(Config vs. Utils vs. Registry)을 건드리긴 하지만, 시스템은 세 개 모두 동일한 기능 실패 – Goal Duplication을 목표로 한다는 것을 식별했습니다.
PR #10088이 근본 원인(파일 이름 변경)을 해결했기 때문에, #10156과 #10096의 문서 수정은 병합되기 전에 중복된 작업이 되었습니다.

감사 결과

  • 200 recent PRs were scanned. → 최근 200개의 PR을 스캔했습니다.
  • 69 valid redundancies were flagged. → 69개의 유효한 중복이 표시되었습니다.
  • Below are some of the most interesting matches. → 아래는 가장 흥미로운 매치 몇 가지입니다.
PR IdentityPrimary MatchCategorisationWhy It Matters
#10404 – ThemeHotkey 가드#10401SHADOWHotkeys에서 event.key 충돌을 방지하기 위한 동일한 null‑check.
#9895 – Docs 복사 버튼#9876SHADOW복사 버튼을 고치기 위한 bash 명령/텍스트 분할이 동일합니다.
#10421 – DataTable 접근성#10402SHADOWData Table에 aria-label을 동시에 추가함.
#10403 – Drawer asChild 수정#10139SHADOW깨진 중첩을 고치기 위해 Drawer 문서에 asChild를 추가함.
#10424 – Monorepo CLI 수정#10258SUPERSETMonorepo CLI에 대한 보다 포괄적인 “한 번에 고치기” 전략.
#10393 – Geist 폰트 불일치#10273SUPERSET#10273보다 더 견고한 폰트 매핑.
#10244 – Calendar 반응형#10235COMPETINGCalendar 너비 반응성을 위한 다른 CSS 전략.
#10386 – ThemeHotkey 버그#10404SHADOW자동 입력 중 정의되지 않은 키 충돌을 방지하기 위한 동일한 로직 수준 수정.
#10383 – FieldSeparator 수정#10201SHADOW두 PR 모두 구분자 상속을 고치기 위해 동일한 속성을 수정함.
#10158 – iOS 날짜 입력#10133COMPETING동일한 iOS 렌더링 버그에 대한 전역 CSS와 컴포넌트 수준 수정의 차이.

구현 개요

1. 백필 스크립트 (역사적 감사)

  1. Paginate PRs 를 Octokit으로 수행하고, 핵심 브랜치(main, master)를 대상으로 합니다.
  2. Compress & filter 로 대용량 diff를 무료 티어 한도 내에 유지합니다:
    • 알려진 대용량 파일(SVG, lockfile, docs)을 제거합니다.
    • 주석 및 변경되지 않은 import 구문을 삭제합니다.
    • 그래도 1500 문자를 초과하면, 수정된 hunks(+/- 라인)만 남깁니다.
  3. 각 정제된 PR을 Gemini 임베딩 모델로 Vectorise 하고 Upstash Vector에 저장합니다.

2. 실시간 봇 (라이브 트리아지)

  1. 새로운 PR이 도착하면, 벡터 스토어에 query 하여 가장 유사한 8개의 후보를 가져옵니다.
  2. 해당 후보들을 LLM reasoning loop에 전달해 의도를 판단하고 버킷(SHADOW / SUPERSET / COMPETING)으로 할당합니다.

3. Rate Limit 처리

  • Router 가 자동으로 제공자(Gemini, Llama, OpenRouter 등) 간 전환합니다.
  • 503/429 오류에 대해 3‑retry logic 과 지수 백오프를 적용합니다.

교훈

문제관찰완화 방안
Vector Gap같은 문제를 매우 다른 방식으로 해결하는 PR이 벡터 검색에 나타나지 않아 LLM에 도달하지 못하는 경우가 있습니다.검색 회수를 확대하기 위해 백업 “semantic‑keyword” 인덱스(예: 도메인‑특정 용어 추출)를 추가했습니다.
Structural Bias초기 모델은 형태가 비슷해 보였기 때문에 관련 없는 JSON 추가를 중복으로 표시했습니다.임베딩을 구축할 때 순수 구문보다 리터럴 값(ID, URL)을 우선시했습니다.
Model Quota고급 AI 할당량을 소진하고 더 작은 8B 모델로 전환했으며, 이로 인해 편향이 증가했습니다.유사도 점수가 이미 높은 경우에만 저렴한 제공자를 선호하도록 예산 인식 스케줄러를 구현했습니다.
False Positives벡터 유사도만으로 많은 잘못된 매치가 발생했습니다.LLM 추론 단계에서 최종 분류 전에 목표 정렬 검사를 수행하도록 했습니다.

주요 내용

  • Historical clustering of redundant PRs는 모든 탐지 엔진에 대한 훌륭한 스트레스 테스트입니다.
  • two‑stage pipeline (vector similarity → LLM reasoning)은 속도와 정확성의 균형을 맞춥니다.
  • Rate‑limit‑aware design (budget‑free tier)은 오픈‑소스 도구에 필수적입니다.
  • 정교한 도구를 사용하더라도 human review는 최종 판단자로 남아 있습니다—특히 엣지‑케이스 “COMPETING” 수정의 경우.

코드를 보거나 다른 저장소에서 감사를 실행하고 싶다면, 이슈를 열거나 PR을 제출해 주세요!

Problem

완전히 새로운 레지스트리 항목도 JSON‑구조 수준에서 비슷해 보인다는 이유만으로 중복으로 표시하기 시작했습니다. 시스템은 실제 URL 값을 무시하고 있었으며, 구조보다 내용을 평가할 만큼 충분히 똑똑하지 못했습니다.

넓은 스윕에 약함

대규모 PR을 살펴볼 때, 시스템이 실제로 존재하지 않는 관계를 보는 경우가 있었습니다. 두 개의 큰 PR이 같은 패키지를 우연히 건드리면, 논리적으로는 전혀 관련이 없더라도 시스템이 그들 사이에 연결이 있다고 환상할 수 있었습니다.

솔루션

백필 엔진은 이제 다음 단계의 분석 핵심, 즉 실시간 GitHub Bot입니다. 우리가 구축한 히스토리 메모리를 활용하여, 봇은 새 PR이 열리는 즉시 분석하고, 이미 존재하는 중복 수정이 있는 경우 유지관리자에게 알립니다.

향후 작업

저는 또한 Maintainer Dashboard를 탐색하여 이러한 의미 클러스터를 시각화하고, 프로젝트 유지 관리자가 기여자들이 무심코 겹치는 부분을 고수준에서 파악할 수 있도록 하고 있습니다.

행동 촉구

레포지토리에서 직접 사용해보고 싶은 유지보수자이거나 기여하고 싶은 개발자라면, 연락 주세요—대화하고 싶어요.

0 조회
Back to Blog

관련 글

더 보기 »