0x00

리서치 / 일일 리포트

  • 읽은 자료 1건
  • 정본 반영 1개 파일
  • 레이더 1건
한 줄 요약X가 홈믹서의 1,255줄짜리 랭킹 스코어러를 지웠다. 이제 홈믹서와 vm-ranker는 공유 crate에 있는 같은 코드로 value model을 계산한다.

1홈믹서와 vm-ranker의 랭킹 점수 계산이 공유 crate 하나로 모였다 — X

자료 xai-org/x-algorithm@44d37eb — GitHub 공개 소스코드, 2026-09-24, +2,569/−2,257 (파일 62). 이 노트들은 4세대 공개 뒤의 X 커밋에 차례로 번호를 붙여 부르며, 이 커밋은 4세대+28이다. 어제 나온 4세대+27 커밋 1b3fec20에서 xai_value_model이라는 공유 crate가 등장하기 시작했다. 그 커밋은 vm-ranker 프로세스에 xai_value_model::compute_value_scores()를 인라인으로 붙였고, 오늘은 그 공유 crate가 실제 파일로 공개됐다.

배경 X의 For You 랭킹은 랭킹 모델 Phoenix가 예측한 참여 확률 24개(favorite·reply·retweet·dwell·report ...)를 가중합해 스칼라 점수 하나를 얻는다. 그 점수에 작성자 다양성, OON(out-of-network, 팔로우하지 않은 계정의 포스트) 배수, 새 작성자 부스트를 곱한다. 코드에서 value model이라고 부르는 이 계산은 For You 피드를 조립하는 Rust 서비스 홈믹서(home-mixer)와, 그 뒤에 붙는 별도 gRPC 서비스 vm-ranker 두 곳에서 일어난다. vm-ranker는 DPP(후보끼리 비슷할수록 함께 뽑히기 어렵게 만드는 다양성 기법) 다양성과 rank server 역할을 맡는다. 두 프로세스가 같은 수식을 두 벌 구현하면, 미러가 어긋나는 것을 매번 사람이 잡아야 한다. 어느 프로세스가 어떤 파라미터를 쓰는지, 파라미터 미러가 몇 개인지 세는 관행이 이 커밋으로 정리된다. 이번 커밋은 어제 등장한 공유 crate를 실제 파일 6개로 공개하면서, 홈믹서의 1,255줄짜리 랭킹 스코어러(ranking_scorer.rs)를 전부 지웠다.

새로 알게 된 것A. 홈믹서의 랭킹 스코어러가 사라지고, 공유 crate가 점수 계산을 맡는다

  • 홈믹서의 1,255줄짜리 랭킹 스코어러가 전부 지워졌다 확인 — home-mixer/scorers/ranking_scorer.rs.
    • ranking_scorer.rs는 직전 커밋 tree에서 확인했다.

    • 그 자리를 대신하는 것은 새 파일 home-mixer/scorers/value_model.rs 114줄뿐이다.

    • 이 파일이 하는 일은 세 가지다.

      1. weights_for(query)가 홈믹서 FS 파라미터에서 33개 값을 뽑아 ValueModelWeights를 구성한다.
      2. scoring_inputs(query, weights, candidate)가 후보의 Phoenix 참여 확률과 in-network·mutual-follow·vqv 조건을 CandidateScoringInputs로 바꾼다.
      3. weighted_score(query, weights, candidate)가 공유 crate의 fuse_heads를 그대로 호출한다.
      pub(crate) fn weighted_score(
          query: &ScoredPostsQuery,
          weights: &ValueModelWeights,
          candidate: &PostCandidate,
      ) -> f64 {
          fuse_heads(weights, &scoring_inputs(query, weights, candidate))
      }
      

      — home-mixer/scorers/value_model.rs, 2026-09-24. 홈믹서 랭킹 스코어러가 하는 일이 이 세 줄로 압축됐다. 실제 수식은 공유 crate의 fuse_heads 안에 있다.

  • 새 공유 crate가 파일 6개, 총 807줄로 공개됐다 확인 — xai-value-model/lib.rs (+14).
  • crate가 밖으로 내보내는 심볼은 아래와 같다 확인. lib.rs가 pub use로 재수출한 목록 그대로다.
    • ValueModelWeights(33 필드) · CandidateScoringInputs · QueryScoringContext · PhoenixScores(26 필드) · compute_value_scores · compute_value_scores_with_adjustment · fuse_heads · compute_weighted_score · offset_score · post_fusion_multipliers · apply_cold_start_decisions · diversity_multiplier · author_pool_counts · PostFusionMultiplier · ValueScores · NEGATIVE_SCORES_OFFSET 상수

새로 알게 된 것B. 홈믹서의 랭킹 계산 파라미터 22개가 지워졌고, value model 가중치는 홈믹서와 vm-ranker 두 미러에 함께 남았다

  • 홈믹서 파라미터 파일에서 136줄이 지워졌다 확인 — home-mixer/params/param.rs (+2/−136).
    • 지워진 파라미터: EnableAuthorDiversity·AuthorDiversityDecay·AuthorDiversityFloor·OonWeightFactor·MultiplierPreOffset·EnableOonRescoreForInNetworkRepliesRetweets·TopicOonWeightFactor·NewUserAgeThresholdSecs·NewUserOonWeightFactor·EnableMultiplicativePostUnexplored·MultiplicativePostUnexploredAlpha·PostUnexploredWeightInNetworkOnly·EnableCdwellOnImpr·ContActiveSecs5mResidualNormWeight·WeightPerturbationSigma·WeightPerturbationSalt·EnableVMRanker·VMRankerDppTheta·VMRankerDppMaxSelectedRank·VMRankerSendValueModelInputs·VMRankerComputeValueModel·CachedPostsReuseWeightedScore
    • 파일 헤더의 sync 시각도 2026-09-22T17:39:32Z → 2026-09-23T16:28:43Z로 바뀌었다.
  • 지워진 값은 두 갈래로 옮겨 갔다 확인.
    • value model 가중치와 게이팅 파라미터는 ValueModelWeights 구조체 필드로 모였다. 가중치 값은 vm-ranker가 관리하는 vm-ranker/params.rs(어제 신설, 56 파라미터)와 홈믹서 param.rs:295-296 이하의 FavoriteWeight·ReplyWeight 등 두 곳에 함께 정의돼 있다.
    • 홈믹서의 weights_for()는 홈믹서 쪽 값을 읽는다(위 A).
    • DPP 파라미터(VMRankerDppTheta·VMRankerDppMaxSelectedRank)는 vm-ranker 프로세스 내부의 RankingConfig로 흡수됐다.

새로 알게 된 것C. vm-ranker 호출이 실패해도 홈믹서는 로컬에서 계산한 점수로 서빙한다

  • vm-ranker RPC가 실패하면 홈믹서는 이제 로컬로 계산한 가중합을 그대로 서빙한다 확인 — home-mixer/scorers/vm_ranker.rs (+84/−76).
    • 기존 코드는 실패를 후보별 Err로 전파했다.
    • 홈믹서의 vm_ranker.rs는 "요청 조립"에서 "local-first, RPC-refine"으로 구조가 바뀌었다.
    • 새 함수 local_scores()가 먼저 후보마다 value_model::weighted_score()로 로컬 가중합을 계산한다. 여기에 AuthorColdStart::apply_with_decisions()로 콜드스타트 lift·author_policy_zeroed 결정을 붙인다.
    • 그다음 vm-ranker gRPC로 refinement 요청을 보낸다.

새로 알게 된 것D. Phoenix retrieval이 콜드 풀과 인기 후보를 데이터 로딩 시점에 나눈다

  • Phoenix retrieval(Phoenix로 OON 후보를 찾는 후보 소스)에 인기 후보 슬라이스가 새로 생겼다 확인 — phoenix/xrex/data/retrieval_dataset.py (+103/−8).
    • 새 슬라이스의 이름은 HOME_HOT이다. RetrievalDataset enum의 HOME_COLD = 13 옆에 HOME_HOT = 14로 등록됐다.
    • 두 슬라이스는 같은 1fav_1day.parquet 소스에서 뽑고, 신규 phoenix/xrex/data/cold_pool_filter.py (+78)의 두 마스크로 갈린다.
      • cold_pool_mask(post_ids, meta_path, max_favs=8, max_views=500)
      • fresh_post_mask(post_ids, max_age_seconds): Twitter Snowflake epoch를 이용해 게시 시각을 트윗 id에서 직접 계산한다.
    • HOME_COLD는 cold_keep = cold_pool_mask & fresh_post_mask이고, HOME_HOT은 그 여집합이다.
    • 콜드 풀이 이제 학습·서빙 단계에서 데이터 로딩 시점에 잘리고, 나머지 인기 후보만 별도 index로 관리된다.
    • default_cold_pool_metadata_path()는 ${PHOENIX_INDEX_BASE:-/data/phoenix_index/prod}/post_author_pairs_metadata/metadata_1day.parquet이다.
  • Phoenix 번들을 export할 때 target별 인덱스 메타데이터가 함께 붙는다 확인 — phoenix/xrex/train/recsys_bundle_export.py (+170/−46).
    • RetrievalExport dataclass에 4 필드가 추가됐다.
      • dataset_capacities
      • rows_from: target별로 어느 소스 dataset의 rows를 참조할지 정한다.
      • max_age_seconds: target별 최대 나이다.
      • optional_targets
    • HOME_COLD와 HOME_HOT이 같은 소스(HOME)의 rows를 나눠 쓰는 구조는 정확히 이 rows_from으로 표현된다.
    • 매니페스트가 POST_SCALES_KEY·DATASET_RANGES_KEY 두 상수를 노출한다.
    • 새 게이팅은 enable_int8_post_table·enable_bloom_filter·enable_topic_filter 세 개다. 이 게이팅으로 int8 post table(per-post absolute-max scale)을 export에 포함할지 결정한다.

새로 알게 된 것E. 리트윗을 판정할 때 원본 트윗의 판정을 합친다

  • VF(visibility-filtering, 포스트마다 이 뷰어에게 보여도 되는지 판정하는 서비스)에 리트윗 판정과 원본 트윗 판정을 합치는 로직이 들어갔다 확인 — visibility-filtering/models/verdict.rs (+60).
    • 새 함수는 Verdict::merge_retweet_verdict(retweet, source)다. 병합 규칙은 네 가지다.

      1. source가 Withheld면 무조건 source를 채택한다. 원 트윗이 감춰졌으면 리트윗도 감춘다.
      2. retweet이 Withheld면 retweet을 유지한다. 리트윗 자체가 감춰지는 규칙이 이겼을 때다.
      3. retweet이 Shown{media: None, engagement: None}(제약 없음)이면 source를 상속한다.
      4. 그 외에는 retweet을 유지한다.
      pub fn merge_retweet_verdict(retweet: Verdict, source: &Verdict) -> Verdict {
          match (&retweet, source) {
              (_, Verdict::Withheld(_)) => source.clone(),
              (Verdict::Withheld(_), _) => retweet,
              (
                  Verdict::Shown {
                      media: None,
                      engagement: None,
                  },
                  _,
              ) => source.clone(),
              _ => retweet,
          }
      }
      

      — visibility-filtering/models/verdict.rs, 2026-09-24

    • 이 병합을 실제로 실행하는 흐름은 visibility-filtering/evaluate_tweets.rs (+157/−18)가 구현했다.

      • 1차 평가 결과에서 source_tweet_id.is_some()인 evaluated 리트윗들을 모은다.
      • 그 source id들을 HashSet.contains()로 in_batch(같은 배치에 이미 있는 것)와 fetched로 나눈다. fetched는 재조회가 필요한 것이다.
      • fetched 목록에 대해 filter_tweets.run(...)을 두 번째로 호출해 source verdict를 얻는다.
      • 리트윗마다 source verdict를 조회해 merge_retweet_verdict를 적용한다.
    • 새 메트릭은 evaluate_tweets_retweet_sources{outcome=in_batch|fetched}다.

  • 병합을 뒷받침하는 변경으로, visibility-filtering/hydration/mod.rs (+244/−18)의 hydration 결과 튜플에 pure_cores: TweetHydrationBatch<PureCore>가 추가됐다.
    • PureCore는 리트윗 원본 id(source_tweet_id)를 담는 얇은 코어 정보다.
    • PureCoreFallbackCache는 처음 실패한 id를 다음 요청에서 재시도할 수 있게 캐시한다.
    • RawCandidate에 source_tweet_id: Option<TweetId> 필드가 붙어(4세대+22 이후 도입) hydration에서 채워진다.

새로 알게 된 것F. grox의 정책 판정에 연령 게이팅용 유해 텍스트 카테고리가 생겼다

  • grox(Grok 기반 nearline 주석 파이프라인)의 정책 판정 단계인 PTOS에 연령 게이팅용 유해 텍스트 카테고리가 새로 생겼다 확인 — grox/flows/ptos/state.py (+6).
    • PTOS는 정책을 기준으로 위반 카테고리를 판정하는 단계다.
    • 새 카테고리 AgeGatingHarmfulText는 SafetyPolicyCategory.AgeGatingHarmfulText enum으로 붙었다.
    • 그 아래 5개 서브타입이 SafetyPolicyType에 등록됐다: AgeGatingHarmfulTextAdultContent·EatingDisorder·HarmfulSubstance·DangerousStunt·GraphicDescription.
    • grox/flows/ptos/classifier.py (+5)에서 이 카테고리는 USE_GEMMA_CATEGORIES 세트에 등록돼, first-pass 판정을 Gemma-4-26b에서 한다. 오늘 시점에 이 세트에 든 다른 카테고리는 Spam·IllegalAndRegulatedBehaviors뿐이다.
    • 프롬프트는 prompts.py (+5)의 age_gating_harmful_text_policy_prompt()가 별도 템플릿 age_gating_harmful_text_policy.j2를 렌더해 만든다. 템플릿 본문은 이 커밋 tree에 포함되지 않았다.
    • 즉 성인 콘텐츠 성격의 텍스트가 있더라도 삭제가 아니라 연령 게이팅으로 넘기는 정책 축이 신설됐다.

새로 알게 된 것G. 답글 스팸과 답글 랭킹 태스크를 가르는 팔로워 경계가 25만으로 올랐다

  • grox 답글 처리에서 GROK_GEMMA_FOLLOWER_SPLIT 팔로워 임계가 225,000에서 250,000으로 올랐다 확인 — grox/flows/reply_spam/constants.py.
    • 상수 이름은 GROK_GEMMA_FOLLOWER_SPLIT이다.
    • 코드에서 이 상수는 태스크 자격을 가른다 확인 — task_filter.py. root나 답글 대상 계정의 팔로워가 이 값을 넘는 대화는 답글 랭킹 태스크로, 둘 다 이 값 이하인 대화는 답글 스팸 태스크로 간다.
    • 상수 이름은 Grok과 Gemma의 경계를 뜻하지만, 스팸 판정 모델을 고르는 임계는 따로 있는 GEMMA_REPLY_SPAM_MIN_FOLLOWERS = 150_000이다 확인 — 같은 constants.py.
    • 4세대 공개 이래 약 42일간 이어진 상향 시리즈(15k → 30k → 40k → 60k → 80k → 100k → 120k → 150k → 180k → 200k → 225k → 250k)의 연장선이다 확인 — task_filter.py와 constants.py의 커밋별 값.
    • 임계가 오를수록 답글 스팸 태스크가 맡는 대화 범위가 넓어진다.

새로 알게 된 것그 밖의 변경

  • 홈믹서의 스코어링 통계가 상위 후보 가운데 SimClusters(클러스터 유사도로 OON 후보를 찾는 후보 소스)에서 온 후보가 몇 개인지 센다 확인 — home-mixer/side_effects/scored_stats_side_effect.rs (+35/−4).
    • 새 메트릭 계열은 Phoenix.RetrievalContribution.SimclustersTopK다. top-k 버킷은 [50, 100, 200, 400, 600, 800]이고, Phoenix의 [10, 100, 200, 500, 1000]과 별도 축을 쓴다.
    • 신규 Phoenix.RetrievalContribution.ScoredTopK는 selected와 non-selected 후보 전체를 대상으로 top-k 소스 분포를 잰다. 선택되기 전에 어느 소스가 스코어링 top-k에 들었는지 관찰하는 것이다.
    • 4세대+26에서 도입된 retrieval_candidates_kafka_side_effect.rs(원자료 샘플링)와 짝을 이루는 aggregate metric 축이다.
  • VF의 clock_cache.rs(412줄)가 제거됐다 확인.
    • 2026-09-10 커밋(4세대+19)에 "미배선" 상태로 도입됐던 프리미티브가 14일 만에 지워진 것이다.
    • 연결되지 않은 프리미티브의 유지 부담을 지고 싶지 않다는 신호다. 재도입이 필요하면 그때 다시 넣을 것이다 추정.

정본 반영 services/x.md의 세대 표에 4세대+28 행을 추가하고, 최종 갱신 날짜를 올렸다. 랭킹 절의 "가중치 미러의 caveat 다섯 가지"와 "미러링 범위" 두 곳에는 홈믹서 미러에서 랭킹 계산 파라미터 22개가 빠진 것을 적었다. value model 가중치는 홈믹서 param.rs와 vm-ranker/params.rs 두 미러에 함께 남아 있다 확인 — 위 B. 후보 생성 절에는 Phoenix HOME_COLD/HOME_HOT 이원화를, 재순위·다양성·필터 절에는 VF 리트윗 source 병합이 연결된 것을 반영했다.

의미 이 커밋의 아키텍처 신호는 두 가지다.

  • 첫째, X의 랭킹 계산이 라이브러리 하나로 수렴했다.
    • 이전에는 홈믹서와 vm-ranker가 같은 수식(Phoenix 확률 × 가중치의 합)을 두 벌 구현하고 있었고, 그래서 파라미터도 두 벌 미러링됐다.
    • 어제까지도 두 프로세스 사이의 정합성이 어떻게 유지되는지가 열린 질문이었다.
    • 오늘 커밋으로 홈믹서의 사본은 사라졌고, 계산은 crate 안에서만 산다.
    • 파라미터도 홈믹서 param.rs 미러가 얇아졌다(랭킹 계산 파라미터 22개 삭제). 다만 value model 가중치는 홈믹서와 vm-ranker/params.rs 두 미러에 함께 남았다.
  • 둘째, 홈믹서가 vm-ranker RPC 실패에 대해 저하 모드(degraded mode)를 갖는다.
    • 이전에는 vm-ranker가 죽으면 후보별로 Err를 후속 코드에 던졌고, 이제는 로컬로 계산한 가중합을 그대로 서빙한다.
    • 공유 crate가 홈믹서 안에 실물로 있기 때문에 가능해진 저하 모드다.
  • 그 밖에 오늘 반영된 것은 두 가지다.
    • Phoenix retrieval이 인기(hot) 슬라이스인 HOME_HOT을 별도 index로 분리해 cold와 뒤섞이지 않게 됐다.
    • VF에서는 지난 두 달간 진행해 온 rule engine 재작성에서 마지막으로 남은 미완 연결이 마무리됐다. 리트윗의 visibility가 원본 트윗의 visibility를 실제로 따라가게 하는 병합이다.

논문과 블로그 훑기

오늘 새로 본 논문 14건 가운데 관찰 요건을 통과한 것은 1건이고, 원문을 확인한 뒤 레이더에 넣었다. arXiv cs.IR 신규 목록은 30건이었다(파싱한 <entry> 개수 30, 2026-09-21~09-23 제출). 그중 어제 이후 신규는 2026-09-23에 제출된 14건이다. 이 14건을 세 요건으로 훑었다: 플랫폼 기업 저자, 프로덕션 A/B 진술, 메커니즘·스케일 신규성.

  • 통과한 논문은 Comcast Technology AI 저자들의 When LLM-Based User Profiling Adds Value in Production Streaming Recommendation이다 확인 arXiv 2609.27183, 2026-09-23.
    • HTML 판에서 저자 4명 가운데 3명의 소속이 Comcast Technology AI임을 확인했다. 세 사람은 Neeraj Sharma·Sardar Hamidian·Shaghayegh Agah이고, 소속 위치는 Sunnyvale·Washington DC다.
    • 1저자 Milad Sabouri는 DePaul University와 Comcast Technology AI에 함께 소속돼 있다.
    • Comcast는 Peacock 스트리밍과 Xfinity의 소유주다.
    • 논문 내용은 콘텐츠 기반 사용자 프로파일 4종을 프로덕션 데이터셋에서 factorial로 비교한 것이다. 4종은 (aggregate vs LLM-generated) × (temporal disentanglement on/off)의 조합이다.
    • 프로파일 종류는 두 가지다.
      1. aggregate: 유저의 최근/과거 아이템 임베딩을 평균한다.
      2. LLM: 유저 이력을 LLM에 넣어 자연어 요약을 얻고, 그것을 텍스트 인코더로 벡터화한다.
    • LLM 방식은 aggregate보다 훨씬 비싸므로, 논문은 "그 비용이 언제 정당화되는가"를 묻는다.
    • 온라인 A/B 결과는 없다. 오프라인 accuracy와 beyond-accuracy(다양성 등)만 보고했다.
    • 프로덕션 데이터셋이 어느 Comcast 제품의 것인지는 명시하지 않았다.
    • radar.md에 넣었다. Comcast/Peacock가 이 저장소 관찰 리스트에 이전에 없었기 때문에, 프로덕션 스택의 첫 신호로 기록해 둔다.

나머지 13건은 관찰 대상에서 탈락했다.

  • MultiVENT-Raw(비디오 검색 벤치마크·학술)
  • Beyond a Scalar(watch-time DSI, Shanghai Jiao Tong University·Rice·학술, KuaiRec/WeChat21 벤치마크 사용이나 플랫폼 저자 없음)
  • Entangle(퀀텀 GitHub 협업·주제 무관)
  • Dual-Hypergraph Indexing(RAG·학술)
  • Turkish LLM eval(도메인 한정)
  • LLM workflow structural diff(SE 툴)
  • Flexible Rec System(그룹 추천·학술)
  • VDR TTA(문서 검색·학술)
  • SLP verifiable LLM inference(LLM 인프라·주제 무관)
  • RoPA Vietnam(데이터 보호 자동화·주제 무관)
  • Large Knowledge Model(과학 지식 그래프·주제 무관)
  • LatWeave(다단 QA·학술)
  • BoundaryMORPH(RAG reranking·학술)

산업 블로그 훑기는 월요일에만 한다. 오늘(금요일)은 대상이 아니다.

Meta engineering blog의 최신 글은 2026-09-21의 두 건(Rebalancer 오픈소스·Petal 해저 케이블)이고, 둘 다 인프라이므로 건너뛴다. Netflix Tech Blog의 최신 글은 2026-09-18의 "Leave the Class Path in the Rearview Mirror"(JVM 인프라)이고, 이것도 건너뛴다.

레이더

레이더에 새로 올린 항목은 Comcast 논문 1건이다.

다음에 볼 것