배경 X 추천 알고리즘의 4세대 공개(2026-08-13, 47c1bcd)는 초대형 공개였다. 3세대까지 블랙박스였던 가중치와 안전 파이프라인, labeling 서브레포 15개, Phoenix(X For You의 랭킹·검색 모델) 학습 코드, SimClusters 부활을 한꺼번에 드러냈다. 그 뒤로 후속 공개가 하루, 사흘, 하루 간격으로 이어졌다.
4세대+1(2026-08-14, c65aa17)은 가중치 해석 규칙과 브라질 선거 필터, Thompson sampling, Phoenix bool 3종, BDSM enforcement note를 부분적으로 공개했다. 규모는 파일 21개, +2,271/−32이고, 상세는 daily/2026-08-16.md에 있다.
4세대+2(2026-08-17, b089ce6)는 광고 브랜드 안전 V2 판정 함수와 성인 컨텐츠 Grok 4.5 심판 계층을 넣었고, Phoenix retrieval 인덱싱 게이트를 없앴다. V2 판정 쪽에는 compute_verdict_v2와 strip_v1_grok_written, PROMPT_OWNED_RULES 7개가 들어 있었다. 규모는 파일 34개, +751/−162이고, 상세는 daily/2026-08-19.md에 있다.
오늘의 자료는 그다음 공개(2026-08-18, 11a71f8)다. 어제 정본(서비스마다 현재 이해를 담는 문서)에 자세히 반영한 마이그레이션 헬퍼가 이 커밋에서 완전히 삭제됐다. 삭제된 것은 strip_v1_grok_written과 PROMPT_OWNED_RULES 7개 rule id다. 이 저장소가 다루는 유일한 "매일 커밋" 오픈소스 서비스에서 이런 일이 벌어진 것은 처음이다. 어제 daily에 남긴 "다음 커밋에서 어떤 param이 어떻게 바뀌는지가 곧 A/B 결과의 지연 지표가 된다"는 관찰이 하루 만에 실제 근거를 얻었다.
이 커밋에는 어제 반영한 사실 하나를 하루 만에 뒤집는 dual-write 재설계가 들어 있다. dual-write는 마이그레이션 중에 옛 형식과 새 형식으로 같은 데이터를 함께 기록하는 방식이다. 이번 커밋은 파이프라인·인덱싱·grox(Grok 기반 콘텐츠 분류 서비스) 세 층도 함께 정리했고, 이 재설계를 포함한 다섯 방향이 정본에 영향을 준다.
새로 알게 된 것A. 광고 브랜드 안전 V2는 이제 V2 라벨이 있을 때만 V2로 판정한다
광고 브랜드 안전 V2에서 dual-write 라벨을 다루는 방식이 하루 만에 다시 설계됐다. 4세대+2 원안에서는 V2 판정 로직이 V1 라벨을 볼 때, 특정 botmaker(X의 규칙 엔진) rule id 7개에 속한 dual-write 라벨만 걸러 낸 뒤 V2 라벨 세트로 판정했다. 이 7개를 담은 상수가 PROMPT_OWNED_RULES다. 오늘 커밋은 이 헬퍼(strip_v1_grok_written)와 Cow import까지 모두 지웠다. 대신 새 상수 V2_WRITTEN_LABELS(V2 라벨 4개)를 판정 조건으로 삼는다.
판정 함수 compute_verdict_v2는 초입에서 라벨 집합에 이 4개 중 하나라도 있는지 검사한다.
하나도 없으면 곧장 compute_verdict(v1)으로 폴백한다.
하나라도 있으면 순수 V2 라벨 세트로 판정한다. NSFA_HIGH_PRECISION과 NSFA_LIMITED_INVENTORY를 제거한 세트다.
V2_WRITTEN_LABELS 4개 중 하나가 있어야 V2로 판정하고, 없으면 V1으로 폴백한다
V2 라벨 세트
Medium 16개(NSFA_HIGH_PRECISION 포함), Low 3개(NSFA_LIMITED_INVENTORY 포함)
Medium 15개(NSFA_HIGH_PRECISION 제거), Low 2개(NSFA_LIMITED_INVENTORY 제거)
검증 테스트
v2_mirrors_v1_across_tier_matrix로 V1과 V2가 6가지 라벨 조합에서 정확히 일치하는지 확인했다
그 테스트의 필터를 라벨 세트 변경에 맞게 확장했고, 새 테스트 v2_defers_to_v1_when_v2_has_not_ruled를 추가했다
이번 재설계는 방향이 훨씬 명확하다. dual-write 마이그레이션의 정공법인 "V2가 판정했으면 V2가 지배하고, 아니면 V1 안전망을 유지한다"를 그대로 택했기 때문이다. 어제 반영한 rule id 7개 필터 방식은 하루짜리 실험이었던 셈이다.
새로 알게 된 것B. Following 피드에 전용 노출 판정 하이드레이터가 생겼다
Following 피드를 만드는 reverse-chron(시간 역순) 파이프라인이 전용 노출 판정 하이드레이터로 분기됐다. 노출 판정을 맡는 VF(visibility-filtering)는 포스트를 지금 뷰어에게 보여도 되는지 판정하는 서비스다. 하이드레이터는 후보 포스트에 필요한 필드 값을 채우는 단계다.
신규 파일 home-mixer/candidate_hydrators/vf_following_candidate_hydrator.rs(95줄)가 연결됐고, reverse_chron_posts_pipeline.rs는 기존 VFCandidateHydrator 대신 이 새 하이드레이터를 쓴다. 새 하이드레이터의 시그니처는 기존과 거의 같다. 다만 반환하는 PostCandidate에 visibility_reason과 drop_ancillary_posts 두 필드만 값을 채우고, 나머지는 ..Default::default()로 초기화한다. 즉 Following 파이프라인은 VF 하이드레이션 산출물을 이 두 필드로 줄이고, 나머지 후보 필드는 다른 하이드레이터가 채우는 구조다. should_drop_ancillary 헬퍼는 기존 파일에서 pub(crate)로 공개되어 새 파일에서 재사용된다.
SafetyLevel::TimelineHome은 그대로 유지된다. Following과 For You가 안전 레벨은 공유한다는 뜻이고, TimelineHomeRecommendations가 아니라는 점도 다시 확인했다.
should_drop_ancillary 헬퍼는 기존 vf_candidate_hydrator.rs에서 pub(crate)로 승격되어 두 하이드레이터가 함께 쓴다.
반환값이 다르다. 기존 하이드레이터는 후보의 모든 필드를 채워서 반환하지만, 새 하이드레이터는 두 필드(visibility_reason과 drop_ancillary_posts)만 채우고 나머지는 default로 둔다. 즉 Following 파이프라인에서는 다른 하이드레이터가 나머지 필드를 이미 채워 둔 상태에서 VF 결과만 추가한다는 뜻으로 읽힌다 추정.
의미 For You와 Following 파이프라인이 이제 하이드레이션 단계에서 명시적으로 갈리기 시작했다. Following은 인네트워크(팔로우한 계정의 포스트) 전용이라서 필요한 후보 필드 세트가 다르고, 그에 맞춰 하이드레이터를 나눈 것으로 보인다.
새로 알게 된 것C. 재순위 요청에 semantic ID 필드 7개가 새로 실렸다
재순위를 담당하는 VMRanker에 보내는 요청에 SID(semantic ID, 아이템을 여러 층의 이산 코드로 표현한 ID) 필드 7개가 새로 연결됐다. 3세대부터 4세대+2까지 SID는 Phoenix retrieval의 window 이름(video_14day·video_48h·nsfw_video_48h/168h/14day)에만 등장했다. 이번 변경은 VMRanker 쪽에서도 SID를 명시적으로 소비하기 시작한 첫 흔적이다. 3-level 코드북(coarse → fine)이 존재한다는 아키텍처 사실도 이 연결로 새로 확정됐다.
home-mixer/scorers/vm_ranker.rs의 build_request는 각 source의 k, pool_rank, pool_rank_gap 옆에 새 필드를 함께 실어 보내기 시작했다. 새 필드는 sid_known, 3-level 계층 SID codeword인 sid_k1/k2/k3, 각 레벨의 이웃 gap인 sid_gap1/gap2/gap3이다.
의미 Phoenix retrieval의 upstream 이벤트 스트림이 세 방향으로 개편됐다.
콘텐츠 이해 스키마를 v1에서 v3로 올렸다.
X 메인 Kafka 클러스터에서 Phoenix 전용 격리 클러스터로 옮겼다.
매핑에서 postId를 Kafka key로 승격해서, 파티셔닝과 중복 제거, 역인덱스 조회를 순수하게 key 기반으로 처리할 수 있게 했다.
import를 hydra/sharedConfig로 옮긴 것은 Phoenix 계열이 hydra 인프라 아래로 편입되고 있다는 신호다. 이 변경은 2026-08-17 커밋(4세대+2)의 "인덱싱 게이트 제거"와 방향이 같다. 인덱싱 처리량이 커지니 별도 Kafka 클러스터가 필요해졌다고 보면 앞뒤가 맞는다 추정.
새로 알게 된 것E. grox의 스팸 판정이 답글 랭킹 흐름 하나로 합쳐졌고, 팔로워 임계는 40k에서 60k로 올랐다
grox의 reply_spam이 별도 흐름을 지우고 단일 통합 흐름으로 압축됐다. 이전에는 두 생성기가 나란히 있었다. PostStreamTaskGenerator는 전체 post 스트림에서 스팸을 감지하고, ReplyRankingTaskGenerator는 답글을 랭킹한다.
남은 상수는 REPLY_RANKING, REPLY_RANKING_RECOVERY, TOPIC_UNIFIED_POSTS_V3, TOPIC_REPLY_RANKING_RECOVERY 네 개다.
의미 grox의 스팸 판정 파이프라인에서 두 가지가 바뀌었다. 스팸 판정 대상 계정을 60k 이하로 넓혔고, 흐름을 답글 랭킹과 통합해 단일 흐름으로 압축했다. 같은 커밋에 들어 있는 Phoenix unified_posts_v3 마이그레이션과 함께 놓고 보면, grox와 Phoenix 양쪽이 v3 콘텐츠 이해 스트림으로 동시에 이동했다는 관찰이 가능하다. follower 임계를 2026-08-14부터 나흘 사이에 세 번째로 올린 것은, 스팸 판정을 더 큰 계정의 스레드까지 넓히는 방향으로 계속 이동하고 있다는 신호다.
새로 알게 된 것F. 콜드스타트 계측이 특정 ID 대신 모든 후보를 센다
콜드스타트 계측이 단순해졌다. 바뀐 곳은 author_cold_start.rs의 count_tracked_ids이고, tracked 필터가 사라졌다.
let source = c.served_type.map(|t| t as i32).unwrap_or(0);
- if tracked.contains(&c.tweet_id) {
- *counts.entry((c.tweet_id, source)).or_insert(0) += 1;
- }
- if tracked.contains(&c.author_id) {
- *counts.entry((c.author_id, source)).or_insert(0) += 1;
- }
+ *counts.entry((c.tweet_id, source)).or_insert(0) += 1;
tracked 리스트 필터를 제거하고 author_id 카운트도 삭제해서, 이제 모든 후보의 tweet_id를 항상 카운트한다.
즉 home_mixer.cold_start_tracked_ids_total{id, source} 계측의 성격이 바뀌었다. 이제는 특정 tracked ID의 등장 횟수가 아니라, 콜드스타트 파이프라인이 소스별로 후보를 몇 개 흘려보내는지의 전수 관측이다.
ColdStartTrackedIds param 자체는 그대로 남아 있지만, 이 함수를 쓰는 곳과의 연결이 바뀐 셈이다. 관찰 훅의 목적이 "특정 계정 A/B"에서 "소스별 전체 트래픽"으로 이동했다.
새로 알게 된 것그 밖의 변경
이 커밋에는 마이너 변경 4건도 함께 들어 있다.
grox 성인 콘텐츠 cross-validation의 로깅이 개선됐다 확인. 어제 반영한 심판 태스크에서 Metrics.counter(metric)의 outcome attribute가 "hard"|"soft" 두 가지 라벨에서 판정 결과인 policyType.value 원본으로 바뀌었다. 심판이 성인 카테고리를 더 세분화해서 반환하더라도 손실 없이 계측할 수 있다.
한 줄 요약 절: 최종 갱신은 2026-08-19 → 2026-08-20, 요약 문단에는 4세대+3 서술을 추가했다.
공개 소스 4세대 테이블: 4세대+3 행(11a71f8)을 추가했다.
광고 절(brand_safety V2): 4세대+2와 4세대+3 두 세대를 나눠 서술하는 형태로 넓혔다. strip_v1_grok_written 삭제와 V2_WRITTEN_LABELS 게이트 재설계를 자세히 적고, 새 테스트 v2_defers_to_v1_when_v2_has_not_ruled의 결정적 케이스를 인용했다.
랭킹 절(VMRanker와 DPP): SID 필드 7개를 정리한 표를 추가하고, 3-level 계층 코드북 사실을 반영했다.
콜드스타트 절: count_tracked_ids 단순화를 반영했다.
Phoenix 학습·인덱스 절: postCreationEventForwarder V3 마이그레이션 상세 표를 넣었다.
열린 질문 절: "4세대+3 공개로 해소된 것 / 뒤집힌 것 (2026-08-20)"을 신설했다. ⚠ 주장 변경 (하루 만에) 항목으로, 어제 반영한 PROMPT_OWNED_RULES 라인이 뒤집혔음을 명시했다.
출처 절: 4세대+3 관련 파일 6개 링크를 추가했다.
의미 ⚠ 주장 변경 (하루 만에): 어제 정본에 자세히 반영한 광고 브랜드 안전 V2의 마이그레이션 로직이 오늘 완전히 사라졌다. 사라진 것은 strip_v1_grok_written 헬퍼와 PROMPT_OWNED_RULES = [1400, 1410, 1420, 1500, 1510, 1610, 1700] 7개 rule id다.
어제 daily에 심층 분석이 필요하다고 남겼던 "PROMPT_OWNED_RULES 7개 rule id ↔ botmaker-rules/ 실 규칙 파일 매핑" 질문은 저절로 해소된 것이 아니라 질문 자체가 없어졌다. 그 상수가 코드에서 지워졌기 때문이다.
이 일은 정본에 두 가지 관찰 근거를 남긴다.
X의 4세대 릴리즈 주기가 "매일 커밋하고 하루 만의 재설계도 흔하다"는 관찰로 확정됐다. 4세대(8-13) → 4세대+1(8-14) → 4세대+2(8-17) → 4세대+3(8-18)은 닷새 사이(8-13~8-18)에 나온 4번의 공개다. 그중 마지막 두 개(어제와 오늘)는 어제 넣은 dual-write 로직을 오늘 완전히 대체한 하루짜리 실험이다. 4세대에서 docs/BIDIRECTIONAL_BOOST_CHANGE.md가 도입한 "코드 diff로 파라미터 변경을 문서화하겠다"는 관행이, 닷새 만에 실제 사례를 두 번 만들어 냈다.
정본이 새 dual-write 로직을 반영할 때는 "이 로직 자체가 다음 커밋에서 바뀔 수 있다"는 점을 서술에 함께 담는 것이 맞다. 어제 daily의 strip_v1_grok_written 서술은 상세한 근거와 rule id 나열, 미공개 항목 목록까지 완벽했다. 하지만 "이 로직이 안정판이 될 것"이라는 함의를 은연중에 담고 있었다. 오늘 이후로는 새 dual-write 연결을 볼 때 "이번 커밋의 특정 헬퍼가 다음 세대에서 지워질 수 있다"는 관찰을 항상 함께 적는다.
새 판정 조건인 V2_WRITTEN_LABELS 라벨 4개의 유래가 새 심층 분석 대상이다. GROK_SFA_V2·GROK_NSFA_V2·GROK_NSFA_LIMITED_V2·GROK_NSFA_EXPANDED_V2 네 개는 어제 라벨 세트에 들어간 3개(GROK_NSFA_V2·GROK_NSFA_EXPANDED_V2·GROK_NSFA_LIMITED_V2)에 GROK_SFA_V2를 더한 구성이다. GROK_SFA_V2는 새 라벨이 아니라, 4세대+2부터 compute_verdict_v2가 Grok 채점 여부를 가릴 때 쓰던 라벨이다 확인 — brand_safety.rs:120-130@b089ce6. 아직 확인하지 못한 것은 다음 세 가지다.
GROK_SFA_V2가 "safe for ads V2"라는 명시적 positive 라벨을 뜻하는지
Grok 프롬프트 재훈련이 어제와 오늘 사이에 배포된 것인지
아니면 V2 라벨러가 자산의 다른 파이프라인에서 온 것인지
검증에서 뒤집힌 것
⚠ 4세대+2의 dual-write 로직 서술이 뒤집혔다. 어제 daily/2026-08-19의 상세 인용도 여기에 포함된다. strip_v1_grok_written과 PROMPT_OWNED_RULES 7개 rule id 라인이 오늘 코드에서 삭제됐다.
정본에서는 4세대+2 서술을 지우지 않았다. 대신 "하루 만에 재설계됨"이라는 주석을 붙여서 세대를 비교하는 근거로 남겼고, 열린 질문 절과 4세대 테이블 두 곳에 명시했다.
이렇게 하면 CLAUDE.md의 "정본은 결론만 담아 압축한다" 원칙을 조금 어기는 것처럼 보인다. 그래도 하루짜리 dual-write 실험 자체가 X의 릴리즈 주기를 관찰하는 데 결정적인 근거이므로, 세대 비교용으로 남겨 둔다.
레이더와 확인 범위
레이더에 새로 올린 항목은 없다. 오늘 확인한 곳과 결과는 다음과 같다.
확인한 곳
결과
비고
arXiv cs.IR 신규 제출
30건 triage, 통과 0건
UniDot 2608.16797은 KDD Cup 2026 runner-up 결과라서 프로덕션 배포와 A/B 진술이 없고, 저자 소속도 공개되지 않았다
Meta 엔지니어링 블로그
0건
마지막 관련 글 2026-08-05, 정본에 이미 반영했다
Netflix 테크 블로그
0건
마지막 글 2026-08-07, 알고리즘과 무관하다
산업 블로그 스윕
건너뜀
월요일에만 하고, 오늘은 목요일이다
arXiv에서 triage한 30건 가운데 프로덕션이나 A/B 진술이 있어서 새로 통과한 항목은 0건이다. UniDot(arXiv 2608.16797, 2026-08-17)은 industrial recommender 통합 아키텍처를 다루지만 레이더 수용 기준에 미달한다. KDD Cup 2026 runner-up 결과 진술만 있고, 프로덕션 배포와 저자 소속, A/B 지표 어느 것도 공개되지 않았기 때문이다.
다음에 볼 것
다음 X 커밋에서 V2 dual-write 판정 방식이 다시 바뀌는지 본다. 새 판정 조건인 V2_WRITTEN_LABELS 라벨 4개가 어떤 파이프라인 변경과 짝을 이루는지도 본다 — 지금까지의 주기대로라면 오늘이나 내일 후속 공개가 나올 가능성이 높다.
다음 X 커밋에서 SID 필드를 쓰는 곳이 늘어나는지 본다 — VMRanker가 SID gap을 DPP 커널의 유사도 성분으로 쓰는지, 다른 스코어러(예: ranking_scorer.rs)에도 SID 필드가 들어가는지 확인한다.
다음 X 커밋에서 Phoenix Kafka v3 마이그레이션의 후속을 본다 — v1 forwarder를 언제 내리는지, v2가 존재하는지, 다른 stream_forwarder들도 v3로 옮기는지 확인한다.
Meta 블로그(ai.meta.com/blog와 engineering.fb.com)의 다음 랭킹·retrieval 계열 글을 확인한다 — 마지막 관련 글은 2026-08-05다.
Netflix 블로그에서 GenRec 후속이나 real-time graph part 4를 확인한다 — 마지막 관련 글은 2026-08-07이다.