한 줄 요약X 조사를 시작했다. 리서치 저장소를 새로 만들었고, X가 공개한 소스 3세대를 전부 분석했다.
이 글은 작업 기록이다. 근거 등급과 file:line 인용은 모두 services/x.md와 topics/*.md에 정리했고, 여기서는 되풀이하지 않는다.
읽은 것
X가 공개한 소스 3세대와 2023년 머신러닝 저장소에서 아래 디렉터리를 읽었다.
- 3세대:
xai-org/x-algorithm(2026-01-20aaa167b, 2026-05-15e414c17·0bfc279)의 다음 디렉터리 전체home-mixer/(For You 피드를 조립하는 서비스)thunder/(Thunder, 팔로우한 계정의 최신 포스트를 꺼내 주는 인메모리 인덱스)phoenix/(Phoenix, 트랜스포머 랭킹 모델과 two-tower retrieval 모델)grox/(nearline LLM 주석 파이프라인)candidate-pipeline/
- 2세대:
twitter/the-algorithm@c54bec0(2025-09-03 리프레시)의home-mixer/,tweet-mixer/ - 1세대:
twitter/the-algorithm@72eda9a(2023)의simclusters_v2/,simclusters-ann/,ann/,cr-mixer/ twitter/the-algorithm-ml(2023)의projects/home/recap/,projects/twhin/
오늘 새로 알게 된 것 중 가장 중요한 5가지
- 1세대와 2세대 사이에는 26개월의 공백이 있고, 2세대에서 삭제된 파일은 0건이다. 2023년 파일 집합은 2025년 파일 집합의 진부분집합이다. 따라서 저장소에 파일이 남아 있다고 해서 그 파일이 현역이라는 뜻은 전혀 아니다. 폐기 여부는 README 한 줄이 바뀌는 방식으로만 드러난다.
- "인네트워크 50:50"이라는 규칙은 코드에 존재하지 않는다. 2026 코드에는 배분기 자체가 없다. OON(out-of-network, 팔로우하지 않은 계정의 포스트)은 쿼터가 아니라 점수 배수로 조절된다. 배분 문제가 랭킹 문제로 옮겨 간 셈이다.
- 이 배수는
effective_oon이다.
- 이 배수는
xai-org/x-algorithm은 빌드되지 않는다.Cargo.toml이 0개이고,crate::params와util,clients는 모듈 전체가 빠져 있다. 60개 파일이params를 참조하지만 그 정의는 어디에도 없다. 즉 로직의 형태만 공개하고 값과 연결 관계는 제외했다. 우연이 아니라 일관된 설계다.- README가 지목하는 스코어러 3개는 모듈 트리에서 끊겨 있다. 실제로 연결되어 있는 것은
vec![phoenix_scorer, ranking_scorer, vm_ranker]다.- 죽은 파일 11개를 목록으로 확정했다.
models/와candidate_pipeline/의 이중 레이아웃이 세대를 구분하는 기준이라는 점도 확인했다.
- 가중치 값은 어느 세대에도 1차 출처가 없다.
- 널리 인용되는 "reply 13.5 / report −369" 표는 블로그가 아니라
the-algorithm-ml의 README에서 나왔다. 그 문서는 "2023-04-05 기준, 언제든 바뀔 수 있다"고 스스로 밝힌다. - 2025 Scala는
ModelWeights30개를 전부default = 0.0으로 지웠다. 같은 파일의 나머지 default 203개는 실제 값을 가지고 있으므로, 이것은 코딩 스타일이 아니라 의도적인 삭제로 보아야 한다.
- 널리 인용되는 "reply 13.5 / report −369" 표는 블로그가 아니라
부수적으로 알게 된 것은 다음과 같다.
has_cached_posts라는 캐시 플래그 하나가 모든 소스와 하이드레이터, Phoenix를 한꺼번에 끄는 가장 큰 스위치다.- 이미 본 포스트를 거르기 위한 백업 필터(
PreviouslySeenPostsBackupFilter)는 영구 no-op이다. - VMRanker(후보 순서를 다시 매겨 다양성을 반영하는 원격 서비스)는 실패해도 로그를 남기지 않고 조용히 넘어간다. 그래서 다양성이 사라진 것을 알아채기 어렵다.
grox/에 있는 파이썬 파일 두 개는 리터럴 치환 때문에 import 자체가 되지 않는다.
검증에서 뒤집힌 것 (중요)
초안을 verifier로 다시 검증했더니 결론 하나가 반대로 나왔고, 상수를 인용할 때 지켜야 할 규칙도 하나 새로 배웠다.
- 뒤집힘: "2025 tweet-mixer의 u2i 후보는 상한 절단 뒤에 붙어서 특혜를 받는다"는 결론은 틀렸다. 절단선을 하나만 보고 결론을 내리면 방향이 반대로 나온다.
- tweet-mixer는 2025 세대에서 OON 후보 생성을 맡은 서비스다. u2i는 유저에서 포스트로 후보를 찾는 경로(user→post)다.
DropMaxResults가result만 자르고remainingCandidates는 남기기 때문에, u2i는 리스트 뒤쪽에 놓인다.- 그 뒤의 최종 절단선이 400이라(라이트랭커 상한 500보다 작다), 앞이 다 차면 u2i가 먼저 사라진다.
- 새 규칙: grep으로 찾아낸 숫자를 프로덕션 값으로 그대로 쓰면 안 된다. 주의할 점 세 가지가 모두 실제로 나타났다.
args.int(name, default)의 default: SimClusters(팔로우 그래프를 커뮤니티로 나눠 만든 임베딩)의maxNeighbors는 코드에 400으로 적혀 있다. 그러나 같은 파일이 적어 둔 프로덕션 실행 명령은--maxNeighbors 100이다.maxEpochs도 코드값 3과 프로덕션값 4가 서로 다르다.- 벤치마크와 warmup에 쓰인 리터럴: HNSW(근사 최근접 이웃 검색 인덱스)의
efConstruction=200과maxM=16은experimental/Runner.scala에 있는 실험용 값이다.ef=800은warmup()안에 들어 있다. - 모듈 트리에서 끊긴 파일의 상수: 2026 죽은 스코어러의
p::AUTHOR_DIVERSITY_DECAY가 그 예다.
- 얻은 것: 2026 코드가 공개하지 않은 상수 하나를 2025 코드로 복원했다.
- 2026
offset_score는 2025RerankerUtil.weightedScoresSum을 그대로 옮긴 코드다. 그래서 비공개 상수NEGATIVE_SCORES_OFFSET을 2025의Epsilon = 0.001로 복원했다. - 이 사례는 두 저장소 사이에 코드 중복이 0이라는 통설의 예외다.
- 다른 비공개 상수도 같은 방법으로 복원할 수 있을 것으로 보인다.
- 2026
- 그 밖의 수정: 다른 사실 몇 가지도 바로잡았다.
FailOpenPolicy.Always는 9개 가운데 8개에만 적용되어, ContentExploration만 fail-closed다.- 2025 MMR(관련성과 다양성을 함께 따져 순서를 다시 매기는 기법)은 리스트 앞쪽
(1-diversityRatio)×n개에는 다양성을 전혀 적용하지 않는다. QuoteDeduplicationFilter는 인용문이 아니라 인용당한 원본을 지운다.- tweet-mixer 파이프라인은 35개가 아니라 34개다.
정본 반영
X 정본과 topics 노트를 모두 새로 만들었다.
services/x.md: 3세대 비교표, 지면, 후보 생성(retrieval) 소스 11개, Phoenix 예측 헤드 22개, 필터 17개, 광고 블렌딩, 콜드스타트, 주의 목록 11개topics/sequence-transformer-ranking.md: Phoenix 구조와 마스크topics/llm-in-recsys.md: Grok/Grox 주석 파이프라인topics/multi-task-ranking.md: 세대별 헤드 목록, 가중치 불투명성topics/candidate-allocation.md: 비율, 상한, 인터리브와 "50:50" 반박topics/feed-diversity.md: 감쇠, MMR, DPP(서로 비슷한 항목이 함께 뽑히지 않게 고르는 확률 모형), deduptopics/embedding-retrieval.md: SimClusters, TwHIN, two-tower, ANN 인덱스
다음에 볼 것
- EU DSA 투명성 보고서 — 가중치의 실제 값이 규제 제출 문서에 들어 있는지 확인한다. 오늘은 보지 못했다.
e414c17(2026-05-15) diff — Phoenix 헤드가 19에서 22로 늘어난 시점이 여기인지 확인한다.- Meta 조사 착수(Instagram, Facebook, Threads) — 엔지니어링 블로그부터 읽는다. X와 달리 코드가 공개되어 있지 않으니 근거 등급을 관리하는 일이 더 중요해진다.