0x00

리서치 / 일일 리포트

  • 읽은 자료 3건
  • 정본 반영 2개 파일
  • 레이더 2건
한 줄 요약X 홈 피드의 cold-start 파라미터 6개가 바뀌었다. cold-start retrieval 후보 상한이 0에서 200으로 올라 이 경로가 켜졌고, 포스트 나이 상한은 48시간에서 2시간으로 줄었다.

오늘 함께 본 다른 변화는 다음과 같다.

  • 같은 X 커밋에서 트윗 필터 파이프라인(VF)이 리트윗 원본을 두 번째 조회 호출 없이 한 번의 호출 안에서 함께 채우게 됐다.
  • 같은 커밋에서 retrieval two-tower(유저와 후보를 따로 인코딩하는 구조) 설정이 preset 6개짜리 카탈로그로 registry에 올랐다.
  • 광고 conversion 헤드의 학습 마스크는 데이터 로더로 옮겨지면서 web과 app 두 축으로 나뉘었다.

1홈 피드 cold-start 파라미터 6개가 바뀌고 VF 조회 구조가 다시 쓰였다 — X

자료 xai-org/x-algorithm@77d431a — xai-org/x-algorithm 공개 저장소, 2026-09-30 03:53:42Z(UTC), 커밋. 줄 수는 +3,306/−1,489, 바뀐 파일은 69개다. 이 노트들은 4세대 공개 뒤의 X 커밋에 차례로 번호를 붙여 부르며, 이 커밋은 4세대+32다. 어제 커밋 4세대+31 a707cc2의 하루 뒤에 나왔다.

배경 visibility-filtering(VF, X의 트윗 필터 파이프라인)의 hydration 계층은 2026-09-25부터 09-29까지 나흘 사이에 세 번 뒤집혔다. hydration은 판정에 필요한 원본 데이터를 backend 서비스에서 배치로 조회해 채우는 단계다.

  • 4세대+29(2026-09-25, bf7db1b)가 Hydrator enum을 7 → 17 variant로 확장하며, 데이터 기반 plan/execute/sources 3-파일을 신설했다.
  • 4세대+30(2026-09-26, 4c5cfe8)이 그 안의 상태를 store.rs로, 실행을 execute.rs로 분리했다.
  • 어제 4세대+31(2026-09-29, a707cc2)이 retweet.rs를 별도 모듈로 추출하면서, in-batch 소스와 fetched 소스를 두 번-hydrate 패턴으로 병합했다. 두 번-hydrate 패턴은 요청 배치를 hydrate한 뒤 리트윗 소스만 두 번째 hydrate 호출로 따로 채우는 방식이다.

이번 커밋(4세대+32)은 이 두 번-hydrate 패턴을 한 번-hydrate와 in-flight 확장 패턴으로 단순화했다. in-flight 확장은 조회가 진행되는 도중에 먼저 도착한 결과를 보고 요청 목록을 늘리는 방식이다. 또 Store의 8개 Option<HydrationBatch> 필드를 새 Fetcher<V> trait 어레이로 다시 써서, 같은 hydrator를 다시 불러도 이미 클레임된 키는 재요청하지 않게 했다.

동시에 두 축이 별도로 진화했다. Phoenix(X For You의 랭킹 모델 스택, 학습 코드는 4세대에서 공개)의 xrecsys_two_tower.py가 registry에 정식 카탈로그로 편입됐다. 이와 함께 SID(semantic ID) 기반 candidate tower와 sequence packing이 6개 preset으로 잠겼다. SID는 포스트 임베딩 대신 codebook 여러 층으로 hash한 이산 코드다. sequence packing은 여러 유저 시퀀스를 한 배치 행에 이어 붙이는 방식이다. 광고 conversion 헤드 학습에 쓰던 ads_head_masking은 JAX 학습 그래프에서 numpy 데이터 로더로 옮겨지면서, web conversion과 app(MMP, Mobile Measurement Partner) conversion 두 축을 분리 학습할 수 있게 됐다.

새로 알게 된 것A. Phoenix cold-start retrieval이 켜지고 포스트 나이 상한이 2시간으로 줄었다

  • 홈믹서(home-mixer, For You 피드 요청을 처리하는 서비스)의 cold-start 파라미터 6개가 크론 미러에서 이동했다 확인 — home-mixer/params/param.rs.
    • cold-start는 신규 유저 또는 exploration 대상을 가리킨다. 크론 미러는 프로덕션 파라미터 값을 매일 동기화해 공개하는 파일이다.
    • Phoenix cold retrieval 채널이 0에서 200 posts로 켜졌다.
    • MaxPostAge는 48h에서 2h로 극단화됐다.
    • FollowerCap은 1000에서 50k로 사실상 해제됐다.
    • Thompson sampling도 켜졌다. Thompson sampling은 cold-start 슬롯을 채울 후보를 Beta 보상 분포에서 표본을 뽑아 고르는 방식이다.

6개 파라미터의 어제 값과 오늘 값은 다음과 같다.

파라미터 어제 값 오늘 값 배율
PhoenixColdStartMaxResults 0 200 0 → 200(Phoenix cold-start retrieval 배출량이 0에서 200으로 활성)
ColdStartImpressionThreshold 1000 200 ×0.2(홈 노출 200회 미만 포스트만 대상, 대상 축소)
ColdStartFollowerCap 1000 50,000 ×50(author follower 상한 사실상 해제)
ColdStartMaxPostAgeSecs 172,800(48h) 7,200(2h) 1/24(post 신선도 극단화)
LowImpressionsMaxPositionRatio 0.85 0.97 +0.12(position boost 상한이 피드 뒷부분까지 확장)
EnableColdStartThompsonSampling false true 신규 ON

파일 주석 헤더의 last sync는 2026-09-28T16:00:35Z → 2026-09-29T17:02:52Z로 갱신됐다.

새로 알게 된 것B. VF는 리트윗 원본을 두 번째 hydrate 호출 없이 한 번의 호출 안에서 채운다

  • 리트윗 소스를 채우던 두 번-hydrate 패턴이 한 번-hydrate와 in-flight 확장으로 단순해졌다 확인 — retweet.rs.
    • 바뀐 파일은 retweet.rs(+562/−110)다.
    • 어제까지는 filter_tweets.hydrate(request)로 원본 배치를 채운 다음, source_ids로 리트윗 소스 후보를 뽑아 요청 배치에 없는 소스에 두 번째 filter_tweets.hydrate(...)를 발사했다.
    • 오늘은 filter_tweets.hydrate_with_retweet_sources(request)를 한 번만 호출한다.
  • 이 한 번의 호출은 pure_cores 응답이 도착하는(land) 순간 내부에서 리트윗 소스를 요청에 붙인다 확인 — store.rs:308-330.
    • pure_cores는 작성자 id·본문·원본 트윗 id를 담은 트윗 코어 데이터다.
    • 이때 실행되는 함수는 store.join_retweet_sources()다.
    • 이 함수는 pure_cores의 source_tweet_id 가운데 요청에 없는 것들을 request_tweets에 붙이고, Landing::SourcesJoined를 반환한다.
  • 소스가 붙으면 실행기는 처음 그룹들을 다시 준비 상태로 돌려, fetched 소스에 대해서만 확장 배치를 발사한다 확인 — execute.rs:112-118.
    • execute.rs가 Landing::SourcesJoined를 받으면 inputless() 그룹(pure_core 의존이 없는 최초 그룹들)을 다시 ready에 넣는다.
    • Fetcher의 claim dedup 덕에 이미 요청 배치에 있던 키는 재요청하지 않는다.
  • 새 Fetcher<V> trait은 키마다 조회 상태를 들고 있다가, 아직 없는 키만 골라 실제 RPC로 보낼 키로 돌려준다 확인 — fetcher.rs.
    • 새 파일 visibility-filtering/hydration/fetcher.rs(NEW +113)에 Fetcher<V>와 AnyFetcher trait이 있다.
    • 내부는 HashMap<u64, State<V>> 하나이고, 상태는 enum State<V> { Pending, Landed(Hydrated<V>) }다.
    • claim(keys) -> Vec<u64>는 아직 없는 키만 Pending으로 잡고, 실제 RPC로 보낼 키만 반환한다. dedup과 이전 콜과의 join이 여기서 함께 일어난다.
    • land(&[u64], HydrationBatch)는 클레임된 키에 응답을 채우고, 응답이 없는 키는 Hydrated::NotFound로 채운다.
    • has_incomplete/is_incomplete/has_claimed/is_claimed가 재호출 판별을 맡는다.
  • Store가 들고 있던 8개 필드는 모두 Fetcher로 바뀌었다 확인 — store.rs:54-84.
    • 바뀐 것은 store.rs의 Option<...> 필드이고, 새 타입은 Fetcher<V>다.
    • Edge마다 별도 Fetcher<bool>을 두고, 어레이 edges: [Fetcher<bool>; Edge::VARIANTS.len()]로 묶는다. Edge는 Follows/Blocks/Mutes/MuteRetweets/BlockedBy/SuperFollows/FollowedBy/SecondDegree의 8-variant다.
    • 새 CallRequest<'p> 구조체는 한 그룹의 실제 발사 세부를 캡슐화한다. 세부 항목은 group, is_first, keys, key_count, queries, viewer_id, batch_size, counts다.
    • offer(&mut self, group) -> Option<CallRequest>는 그룹의 키를 claim해 CallRequest를 만들고 스케줄러에 넘긴다.
    • 두 번째 호출(is_first=false)에서는 record_expanded_batch 메트릭이 발생한다.
  • 조회 계획의 edge 표현이 8-variant enum 하나로 통합됐다 확인 — plan.rs:8-20.
    • plan.rs의 Part::Edge(Graph, EdgeDirection)이 Part::Edge(Edge)로 바뀌었다.
    • Edge::flock()은 flock RPC 파라미터를 Option<(Graph, EdgeDirection)>로 반환한다. SecondDegree만 None이고, Wingman으로 통합 라우팅된다.
    • 어제 Part::Column이던 Hydrator::RootFollowsViewerSecondDegree가 오늘 Part::Edge(Edge::SecondDegree)로 승격돼, fetcher array로 통일 라우팅된다.
  • 그룹에 위치와 reader 목록 필드가 생겨, offer→land→ready 스케줄을 매 그룹당 O(readers)로 계산한다 확인 — plan.rs:172-207.
    • 새 필드는 Group의 position: usize·readers: Vec<usize>다.
  • 리트윗 소스를 세 경우로 나눠 기록하는 메트릭이 생겼다 확인 — filter.rs:62-79.
    • 메트릭은 RetweetSources::{NoSource, InBatch, Fetched}다.
    • 테스트 each_request_kind_labels_its_phase_samples가 세 케이스를 고정한다: [2] → NoSource, [1,2,3,5] → InBatch, [1,2,3,4] → Fetched 확인 — retweet.rs:721-738.

새로 알게 된 것C. 판정 결과를 thrift·proto·메트릭 표현으로 바꾸는 함수가 한 파일로 격리됐다

  • rules가 내놓은 순수한 판정을 세 종류의 다운스트림 표현으로 사영하는 함수 묶음이 새 파일로 격리됐다 확인 — treatment.rs.
    • 새 파일은 visibility-filtering/treatment.rs(NEW +119)이고, 입력 판정은 Verdict(Withheld / Shown{media, engagement})다.
    • thrift_action(&Verdict, SafetyLevel) -> Action은 thrift action::Action(Allow / Drop / Tombstone / ComposedMediaVisibilityResults / Interstitial / LimitedEngagements / TweetInterstitial)으로 사영한다.
    • thrift_result_state(&Verdict, SafetyLevel) -> TweetFieldsResultState는 tweet-service 응답 상태(Found / Filtered)로 사영한다. FilteredReason::{TweetIsBounced, AuthorBlockViewer, AuthorIsProtected, AuthorIsSuspended} 네 개만 레거시 arm을 따로 두고, 나머지는 SafetyResult로 감싼다.
    • proto_action(Verdict) -> (vf_pb::Action, Option<vf_pb::FilteredReason>)은 VF proto용 3-way(Allow / Drop / Interstitial)로 사영한다.
    • metric_label(&Verdict) -> &'static str은 6-way 라벨(allow / drop / tombstone / interstitial / limited_engagement / tweet_interstitial)을 낸다.
    • decided_rows(&Verdict)는 verdict를 (rule, phase) 튜플 열로 펼치는 이터레이터다.
    • 테스트 dashboard_generator_pins_the_rpc_and_verdict_mix_labels는 scripts/dashboard.py를 실제로 읽어, FT_VERDICT_ACTIONS에 6개 라벨이 있는지 assert한다. 메트릭 라벨과 dashboard는 골든으로 묶인다.
  • 나이 확인 옵션 상수도 이 파일에 고정됐다 확인 — treatment.rs:120-123.
    • 상수는 AGE_VERIFICATION_OPTIONS = [SELFIE, PERSONA]다.
    • blurred_media는 blur prompt가 AGE_VERIFICATION_PROMPT일 때만 이 두 옵션을 응답에 넣는다.

새로 알게 된 것D. VF 클라이언트는 이제 판정 액션 대신 결과 상태를 받는다

  • VF 응답이 판정 액션 대신 결과 상태를 싣도록 클라이언트 계약이 바뀌었다 확인 — evaluated.rs:22-33, vf_client.rs:35-41.
    • 응답이 Thrift Action → TweetFieldsResultState로 승격됐다.
    • proto는 Outcome::ActionThriftCompact → Outcome::ResultStateThriftCompact로, 상수는 MAX_ACTION_BYTES → MAX_RESULT_STATE_BYTES로 바뀌었다. 값은 여전히 64KB다.
    • VF가 이제 (Found | Filtered) 결과 상태 자체를 실어, caller가 tweet-service 응답을 직접 구성할 수 있는 형태가 됐다.
  • 응답의 tweet.id 순서 검증이 사라지고, 응답 길이만 검증한다 확인 — vf_client.rs:35-46.
    • 어제까지는 tweet.as_ref() == Some(expected) assert로 순서와 quote context를 검증했다.
    • 이 변경은 wire format 최적화다.
  • 요청 헤더에 metadata 매개변수가 추가됐다 확인 — vf_client.rs:8-25.
    • 매개변수는 metadata: &tonic::metadata::MetadataMap이다.
    • 각 chunk RPC에 caller metadata(twittercontext 등)를 forward한다.

새로 알게 된 것E. Phoenix retrieval two-tower 설정이 preset 6개짜리 카탈로그로 registry에 올랐다

  • two-tower 설정 파일이 registry에 카탈로그로 승격돼, preset 6개를 담는다 확인 — xrecsys_two_tower.py.
    • 파일 경로는 phoenix/xrex/configs/xrecsys_two_tower.py다.
    • preset은 xrecsys_two_tower.py의 MODEL_CFGS 딕셔너리에 있다.
    • preset 이름은 xrecsys_two_tower / xrecsys_two_tower_immersive_only / xrecsys_two_tower_immersive_only_gb300 / xrecsys_two_tower_combined / xrecsys_two_tower_combined_gb300 / xrecsys_two_tower_nano다.
    • 여러 preset이 함께 쓰는 공용 스케일은 _xrecsys_two_tower_combined_base에 있다 확인 — xrecsys_two_tower.py:466-475.
      • 시퀀스 길이: history_seq_len=1023 · candidate_seq_len=64
      • 모델 크기: num_layers=8 · emb_size=1024 · emb_table_width=1024 · query_heads=16 · kv_heads=4(GQA 4:1)
      • 학습 샘플: num_global_negatives_per_example=64 · total_samples=1e11
      • vocab: item_hash_vocab_size=100_000_000 · author_vocab_size=30_000_000
    • 유저·포스트 임베딩은 쓰지 않고 SID만 쓴다 확인 — xrecsys_two_tower.py:311-318.
      • use_user_embedding=False · use_post_embedding=False · use_post_sid=True
      • sid_num_levels=6 · sid_codebook_size=256 · sid_embed_dim=1024 · sid_hash_level=True · sid_cross_attn=True
    • sequence packing과 right-anchored RoPE를 쓴다.
      • use_seqpack=True · effective_sequence_len=513 · BetaLengthDistribution(min=0, max=1023, mean=511, α=β=1.0, block_size=128)
    • Home과 Immersive 두 candidate head를 공유한다 확인 — xrecsys_two_tower.py:293-302.
      • num_candidate_heads=2 · head_names=["home", "immersive"]
      • head_dataset_mapping은 HOME/HOME_COLD/HOME_HOT → head 0, IMMERSIVE4Day/IMMERSIVE2Day/IMMERSIVENSFW → head 1로 대응시킨다.
      • home의 positive_actions는 [SERVER_TWEET_FAV] 하나뿐이다. immersive_positive_actions는 FAV / REPLY / QUOTE / RETWEET / VIDEO_QUALITY_VIEW / FOLLOW_AUTHOR / BOOKMARK / SHARE 8종이다 확인 — xrecsys_two_tower.py:283-292.
    • 하드웨어 프리셋은 H100용과 GB300용이 따로 있다 확인 — xrecsys_two_tower.py:409-413.
      • _H100_OVERRIDES = {bs_per_device: 480, ep: 128, attn_impl: "cutedsl_ranker_varlen_attn"} · _GB300_OVERRIDES = {bs_per_device: 960, ep: 64, ...}
      • GB300에서는 per-device batch가 두 배이고 EP는 절반이다.
    • 옵티마이저는 Adam이고, embedding에는 rowwise adagrad용 학습률을 따로 둔다 확인 — xrecsys_two_tower.py:826-831, 271.
      • Adam(b1=0.95, b2=0.98, weight_decay=1e-3) · learning_rate=2e-3 · emb_learning_rate=0.1(embedding rowwise adagrad)
      • apply_u2u_and_i2i_loss=False(기본 off) · empty_history_user_dropout_rate=0.1
    • Candidate max_posts 값은 combined와 immersive에서 다르다 확인 — xrecsys_two_tower.py:611-618.
      • combined 28,672,000 · immersive 40,960,000
    • linear projection 설정은 combined·immersive와 nano에서 다르다 확인(같은 출처).
      • enable_linear_proj은 combined/immersive에서 False, nano에서 True다.
    • 같은 줄 범위에는 두 설정을 함께 켤 수 없게 막는 assert도 있다 확인(같은 출처).
      • apply_u2u_and_i2i_loss와 enable_candidate_tower_linear_proj는 상호 배타 assert로 묶인다.

"Beta length distribution used for sequence packing: BetaLengthDistribution(min=0, max=1023, mean=511, alpha=1.0, beta=1.0, block_size=128)." — phoenix/xrex/configs/xrecsys_two_tower.py, 2026-09-30

새로 알게 된 것F. 광고 conversion 헤드의 학습 마스크가 데이터 로더로 옮겨지고 web과 app으로 나뉘었다

  • 광고 헤드 마스킹 코드가 모델 쪽 JAX 구현에서 데이터 쪽 numpy 구현으로 다시 쓰였다 확인.
    • 새 파일 phoenix/xrex/data/recsys/ads_head_masking.py(NEW +87)가 phoenix/xrex/models/ads_head_masking.py(−67)를 대체하며, ads_head_masking을 JAX → numpy로 재작성했다.
    • 삭제된 models/ads_head_masking.py patch에는 import jax; import jax.numpy as jnp가 있고, 신설 data/ads_head_masking.py는 numpy as np만 쓴다.
  • 새 함수가 데이터 파이프에서 numpy bool 마스크를 미리 계산한다 확인 — phoenix/xrex/data/recsys/ads_head_masking.py:44-88.
    • 함수는 build_trained_candidate_mask(actions, sample_source, trained_actions_bits, *, ads_head_masking: bool) -> npt.NDArray[np.bool_]다.
    • 인자 이름은 source_id → sample_source, raw_targets → trained_actions_bits: uint8 비트마스크로 바뀌었다.
    • 신규 상수 ADS_FAMILY_SLICE_HEADS는 4개 슬라이스(delayed_website_clicked / delayed_website_non_clicked / delayed_app_clicked / delayed_app_non_clicked)의 대표 head index다.
    • MMP app-conversion 축이 붙어, masking이 web × app × early/late × click/view 격자로 확장됐다.
  • 모델의 clicked 마스크가 web과 app으로 나뉘었다 확인 — recsys_model.py:1493-1520.
    • recsys_model.py의 masks["clicked"]가 website_clicked / non_negative_website_clicked / app_clicked / non_negative_app_clicked 4-way로 분화됐다.
  • 새 검증이 광고 헤드 마스킹과 seqpack을 함께 켜지 못하게 한다 확인 — recsys_model.py:610-614.
    • 검증 함수 validate_ads_head_masking은 ads_head_masking and use_seqpack을 금지한다.
    • packed layout에서는 per-candidate/per-head trained_candidate_mask가 정의되지 않는다.
  • 학습 배치 스키마의 컬럼 이름이 바뀌었다 확인 — phoenix/xrex/data/recsys/recsys_batch.py:471-479.
    • recsys_batch.py에서 conversionKeepMask: bool → conversionKeepBits: uint8로 바뀌었다.
    • null일 때의 fallback 값은 True → CONVERSION_KEEP_WEB | CONVERSION_KEEP_APP = 0b11로 바뀌었다.
    • sample_source 컬럼을 새로 받는다. 없으면 all zero다.
  • 상수 파일 constants.py에 MMP 액션 묶음, 비트 상수, enum, 새 라벨이 추가됐다 확인 — phoenix/xrex/data/recsys/constants.py.
    • MMP_CLICK_ACTION_INDEX = ADS_MMP_CLICK
    • MMP_CLICK_CONDITIONED_ACTION_INDICES는 app click-through 7종이다.
    • MMP_CLICK_VIEW_THROUGH_ACTION_INDICES는 app view-through 7종이다. 어제까지 VIEW_THROUGH_ACTION_INDICES에 섞여 있던 것들이 분리됐다.
    • 비트 상수는 CONVERSION_KEEP_WEB = 1 << 0 · CONVERSION_KEEP_APP = 1 << 1이다.
    • LineItemObjective(enum.IntEnum): WEBSITE_CLICKS = 5는 어제까지 line_item_objective == 5 매직 넘버였던 것을 enum으로 승격한 것이다.
    • 새 라벨 IsCustomConversion / IsContentViewConversion은 각각 ADS_CUSTOM_CONVERSION / ADS_CONTENT_VIEW_CONVERSION에 매핑된다.
  • proto에 MMP install 액션 두 개가 추가됐다 확인 — phoenix/crates/serving/xai-recsys-proto/proto/recsys.proto.
    • recsys.proto의 새 action은 ADS_ATTRIBUTED_MACT_MMP_CLICK_INSTALL = 194, ADS_ATTRIBUTED_MACT_MMP_VIEW_INSTALL = 195다.

새로 알게 된 것그 밖의 변경

  • 홈믹서의 diversity 통계 helper 파일이 삭제됐다 확인.
    • 삭제된 파일은 home-mixer/util/composition.rs(−63)다.
    • 어제까지 이 파일은 Composition {size, unique, max_count, hhi, entropy_norm} 구조체와 from_keys / from_counts / unique_ratio / max_share API를 담은 diversity stats helper였다.
    • response_diversity_stats_side_effect.rs의 사용부는 use xai_candidate_pipeline::component_library::utils::Composition;으로 import path만 바뀌었다 확인 — response_diversity_stats_side_effect.rs.
    • candidate-pipeline 공용 유틸에 이미 같은 이름의 Composition이 있어, 자기 사본을 지우고 공용을 쓰는 중복 제거다.
    • rules/registry Policy(4세대+30)와는 무관하다.
  • Brazil 2026 election filter에 handle 9개가 추가됐고, list 크기는 2,786 → 2,795다 확인 — home-mixer/filters/brazil_2026_election_filter.rs:5849-5852.
    • 추가된 handle(주석 기준)은 @linoaa, @LPVellozo, @erikakokay, @douglascamargoo, @Anadelso_p, @zeosmaruniao, @siandrade11777, @tiagopiaui22, @gloriabsoares다.
    • 로직 변경은 없다.

정본 반영 services/x.md에 ### 4세대+32 절을 새로 만들어 위 사실을 요약했고, ## 출처에 커밋 sha 77d431a를 추가했으며, 최종 갱신을 2026-10-01로 갱신했다.

의미 세 축이 겹친다.

  1. 홈믹서 cold-start가 프로덕션 파라미터로 세팅됐다. 4세대+28(44d37eb)에서 HOME_HOT=14와 함께 신설된 HOME_COLD=13 채널에 4세대+30이 코드 경로를 추가한 데 이어, 오늘 파라미터가 잡혔다.
    • Phoenix cold retrieval 채널이 0에서 200 posts로 열렸고, MaxPostAge가 48h에서 2h로 극단화됐다.
    • FollowerCap이 1000에서 50k로 사실상 해제되어 author 풀이 폭증했다.
    • ImpressionThreshold는 1000에서 200으로 낮아져, 홈 노출이 200회 미만인 포스트만 cold-start 대상이 됐다(대상 축소) 확인 — author_cold_start.rs:294. Thompson sampling도 켜졌다.
    • cold-start가 지금까지 tracked author나 신규 유저를 대상으로 한 좁은 exploration이었다면, 이 파라미터 세팅에서는 신선도가 극단적으로 엄격한 2h와 넓게 열린 author 풀의 조합이 작동한다.
    • 이 튜닝이 A/B에서 유지되는지가 다음 크론 sync에서 관측할 지점이다.
  2. VF hydration의 재확장 능력이 확보됐다. 4세대+29(09-25)부터 4세대+31(09-29)까지 나흘의 흐름이 데이터 기반 파이프라인 골격과 retweet.rs 모듈 추출을 완성했다.
    • 오늘 그 위에 Fetcher<V> trait이 더해져 claim이 idempotent해졌다.
    • 이 덕에 pure_cores가 land한 순간 in-flight로 request_tweets를 확장하고 inputless 그룹을 재발사하는 Landing::SourcesJoined 흐름이 성립한다.
    • retweet.rs의 두 번-hydrate 패턴은 한 번-hydrate와 in-flight 확장으로 단순해졌다.
    • 메트릭 축(NoSource / InBatch / Fetched)이 라벨로 잡혀, 확장 배치의 실제 발생률을 관측할 수 있다.
    • VF 클라이언트 응답도 Thrift Action → TweetFieldsResultState로 승격돼, caller가 tweet-service 응답을 직접 구성할 수 있는 형태로 넘어왔다.
    • treatment.rs가 rules → thrift/proto/metric 사영을 한 파일로 격리하고 dashboard.py와 6개 metric label을 골든 테스트로 묶은 것도 이 단순화의 마무리다.
  3. Phoenix retrieval two-tower가 카탈로그로 승격됐다. 지금까지 xrecsys_two_tower.py는 파일로 존재했고 여러 커밋에서 소품 수정이 있었지만, registry 카탈로그 자체는 잠기지 않은 상태였다.
    • 소품 수정은 4세대+6에서 qk_norm=True·attn_logit_cap=-1·right_anchored_rope=True 3옵션을 도입한 것과, 4세대+21에서 H100 attn 커널을 pallas_ranker_varlen_attn → cutedsl_ranker_varlen_attn으로 전환한 것이다.
    • 오늘 6개 preset(기본, immersive-only와 그 GB300판, combined와 그 GB300판, nano)이 MODEL_CFGS에 잠기면서, 프로덕션 데이터 파이프에 연결되도록 이관됐다 추정. 근거는 파일 안의 유일한 in-file dataset이 aggregated_kafka이고, preset이 hardware-aware로 잘 정의돼 있다는 점이다.
    • 특히 SID-only(포스트 임베딩 대신 6-level codebook hash)·seqpack·H100/GB300 하드웨어 프리셋·Home과 Immersive 두 head 공유가 한 파일에 정리됐다는 점이 눈에 띈다.
    • 4세대+13에서 관측된 "DPA 광고 제품에도 sid_codes 배선"과 짝을 이루면, SID 어휘 체계가 유기 post·광고 DPA·retrieval two-tower의 세 사용처를 하나로 묶을 잠재가 커진다.
  4. 광고 conversion 헤드가 web/app 축으로 분화됐다. 4세대+6에서 도입된 delayed feedback split과 4세대+24에서 통합된 ads_head_masking 노브가, 오늘 학습 그래프 내부 float multiplier에서 데이터 로더가 미리 계산한 boolean mask로 이동했다.
    • 이는 그래프가 sample_source에 의존하지 않게 해 컴파일 안정성을 확보한다.
    • 또 웹 conversion 헤드와 앱(MMP) conversion 헤드를 분리 학습해, keep_web / keep_app 두 축의 sample subset을 각기 다르게 쓸 수 있게 한다.
    • 마스크 semantics는 여전히 같은 late-window twin suppression 로직을 유지하고, 계산 위치만 바꾼 정확한 리팩터다.
    • use_seqpack과의 상호 배타 assert가 새로 걸린 것은 seqpack에서는 candidate 슬롯 대응이 무너지기 때문이다.
    • proto의 ADS_ATTRIBUTED_MACT_MMP_{CLICK, VIEW}_INSTALL = 194, 195 두 액션 신설은 MMP 측 app-install conversion을 정식으로 학습 헤드에 편입할 채널을 만든다.

Brazil 2026 election filter에 handle 9개를 추가한 것은 리스트 유지보수이고, 로직 변경은 없다. Composition.rs 삭제는 candidate-pipeline 공용 라이브러리를 재사용해 중복을 없앤 것이다.

↑ 목차

2HELIX가 TikTok e-commerce A/B에서 유저당 GMV를 약 6% 높였다 — 레이더

자료 HELIX: Purified and Unified - Rethinking Feature Interaction and Sequence Modeling for Large-Scale Recommendation — arXiv 2609.37183 v1, 2026-09-29(arXiv 제출), 논문. 저자는 21명이다. v1 HTML은 렌더링이 404지만 초록에 "Deployed in TikTok's e-commerce recommendation system"이라는 문구가 있어, 소속은 TikTok(ByteDance)으로 본다 추정.

배경 산업 추천 랭킹 모델은 대체로 두 축으로 스케일한다.

  • heterogeneous feature interaction: 유저 / 아이템 / 컨텍스트 / 크로스 피처를 조합해 상호작용시킨다.
  • sequence modeling: 길고 다양한 유형의 유저 behavior 시퀀스를 인코딩한다.

HELIX 저자들은 어느 한 축만 키우면 scaling-law slope가 서브옵티멀임을 관찰하고, 두 축을 함께 확장하는 "unified" 랭킹 아키텍처를 제안한다.

새로 알게 된 것A. TikTok e-commerce에 배포됐고, 온라인 A/B에서 유저당 GMV가 약 6% 늘었다

  • 초록은 HELIX가 TikTok의 e-commerce 추천 시스템에 배포됐고, 오프라인 CTR AUC·CVR AUC 등 랭킹 지표를 일관되게 개선한다고 밝힌다 확인(초록 직접 인용).
  • 온라인 A/B에서는 e-commerce video GMV per user가 약 6% 늘었다 확인(초록 직접 인용).

"Deployed in TikTok's e-commerce recommendation system, HELIX consistently improves offline CTR AUC, CVR AUC, and other ranking metrics. In online A/B tests, it achieves an approximately 6% increase in e-commerce video GMV per user." — HELIX abstract, 2026-09-29

새로 알게 된 것B. 핵심 관점은 두 축을 함께 키워야 scaling law가 서브옵티멀에서 벗어난다는 것이다

  • HELIX는 feature-interaction 축과 long/multi-type user-behavior sequence 축을 동시에 스케일링하는 "purified and unified" 랭킹 아키텍처다 확인(초록 문구).
  • 둘을 함께 확장해야 scaling law가 서브옵티멀에서 벗어난다는 관찰이 논문의 핵심 관점이다 확인(초록 문구).

새로 알게 된 것C. 서비스 규모는 밝히지 않았다

  • 논문은 사용자 수나 요청 수를 명시하지 않는다.
  • GMV per user 지표를 쓴다는 점은 대규모 e-commerce 트래픽을 뜻하는 것으로 본다 추정.

정본 반영 radar.md의 "이번 달 신규"에 2줄 포인터를 추가했다. 서비스 정본(X·Meta·Netflix)과는 직결되지 않는다.

의미 TikTok의 e-commerce recommendation에서 feature-interaction과 long sequence를 함께 스케일링하는 랭킹 아키텍처를 정식으로 이름 붙여 공개한 것은 이번이 처음이다.

  • 그동안 이 영역에서는 EGA(Elastic Generative Auction, 광고 경매·랭킹) 계열과 GreenLightning 계열의 공개가 이어져 왔다. GreenLightning은 단일 인퍼런스 서비스다.
  • Scaling law가 두 축의 동시 확장을 요구한다는 관점은, Meta HSTU(Meta의 생성형 순차 추천 아키텍처) / GEM 계열의 sequence-only 확장과 DCN·xDeepFM 계열의 feature-interaction 확장이 각각 서브옵티멀임을 시사한다.
  • 다만 초록 기반 triage 단계라 세부 아키텍처(어떤 인터랙션 구조, 어떤 sequence 인코더, scaling law slope의 실측치)는 심층 분석 대상이다.
  • 서비스 정본에는 반영하지 않고 radar에 둔다.

↑ 목차

3Snap의 GRP가 retrieval·ranking·reward를 한 모델로 합쳤다 — 레이더

자료 GRP v0.1 Technical Report — arXiv 2609.36688 v1, 2026-09-29(arXiv 제출), 논문. v1 HTML 페이지에 Snap Inc. 조직명이 렌더링돼 있어, 소속은 Snap이다 확인.

배경 산업 추천 시스템은 대체로 retrieval → pre-ranking → fine-ranking → reward 재순위의 다단 cascade로 구성된다. 각 단계를 별도 모델로 학습·배포하다 보니 스택 전체를 함께 교체하기가 어렵다. 이번 논문의 GRP(Generative Recommendation Platform으로 추정)는 이 다단을 단일 encoder-decoder 모델로 통합하는 프레임워크를 제시한다. 이 모델은 multimodal Semantic ID를 생성하고, joint MHP(Multi-Head Prediction)가 후보 스코어링과 RL post-training의 frozen reward를 겸한다.

새로 알게 된 것A. retrieval만 비교한 A/B와 bypass·source replacement를 함께 적용한 A/B에서 view time과 shares가 늘었다

  • retrieval만 비교했을 때 프로덕션 대비 view time이 0.46%, shares가 0.77% 늘었다 확인(A/B 직접 인용).
  • bypass와 source replacement를 함께 적용한 별도 비교에서는 view time +0.82%, shares +2.56%였고, 플랫폼 수준 guardrail은 중립이었다 확인(A/B 직접 인용).

"In a retrieval-only comparison, view time increases by 0.46% and shares by 0.77% relative to production. A separate comparison combining bypass and source replacement yields increases of 0.82% in view time and 2.56% in shares, with neutral platform-level guardrails." — GRP v0.1, 2026-09-29

새로 알게 된 것B. retrieval bypass 조합에서는 views와 shares가 늘고 view time은 줄었다

  • retrieval bypass 조합의 추가 축은 다음 수치다: "+0.24% views, −0.24% view time, +2.30% shares (p<0.05)".

새로 알게 된 것C. retrieval·ranking·reward를 encoder-decoder 하나로 통합한다

  • GRP는 retrieval · ranking · reward를 단일 encoder-decoder로 통합하는 generative recommendation 프레임워크다.
  • multimodal Semantic ID를 생성하고, joint multi-head prediction(MHP)이 후보 스코어링과 RL post-training의 frozen reward를 겸한다. RL post-training은 mGRPO(reference-anchored margin)다.

새로 알게 된 것D. 서빙 최적화로 retrieval latency를 줄였다

  • 사용자 수나 요청 수는 명시하지 않았다.
  • serving 최적화로 end-to-end retrieval latency가 69% 줄었다.
  • 논문 분량은 26 pages, 11 tables다.

정본 반영 radar.md의 "이번 달 신규"에 2줄 포인터를 추가했다. Snap은 추적 서비스 밖이라 서비스 정본에는 반영하지 않는다.

의미 GRP는 이번 달 초부터 관찰해 온 "generative recommendation의 서빙 경로 통합" 각도의 새 진술이다.

  • Kuaishou OneTrans-V2는 retrieval·pre-rank·fine-rank 3단 cascade를 단일 Transformer로 묶어 GMV +9.74%를 얻었다(2026-09-28 radar). Tencent PCG TGR은 랭킹·retrieval·slate 생성·reason token을 한 프레임에 묶어 5개 지면에 배포했다. GRP는 이 둘과 방향이 같다.
  • GRP에는 여기에 두 축이 더해진다. 하나는 reward까지 같은 모델 안에서 처리하는 mGRPO joint MHP 축이고, 다른 하나는 multimodal Semantic ID 생성 축이다.
  • 서빙 latency −69%는 다단 cascade 대비 큰 절감이고, encoder-decoder 통합이 latency 예산까지 정당화하는지가 industrial-scale generative recsys 채택의 핵심 기준이라는 신호다.
  • 서비스 정본에는 반영하지 않고 radar에 둔다.

↑ 목차

레이더

  • HELIX(TikTok [추정])는 feature-interaction과 long user-behavior sequence 두 축을 함께 스케일링하는 unified 랭킹 아키텍처다(arXiv 2609.37183). TikTok e-commerce에 배포되어 A/B에서 GMV per user +~6%를 얻었다. 지표는 확인, 소속은 추정이다(v1 HTML 렌더링 404, 초록 문구 기반). radar.md 이번 달 신규에 편입했다.
  • GRP v0.1(Snap)은 retrieval · ranking · reward를 단일 encoder-decoder로 통합하는 generative recommendation 프레임워크다(arXiv 2609.36688). 구성 요소는 multimodal Semantic ID, joint MHP, mGRPO다. 프로덕션 A/B에서 view time +0.82%, shares +2.56%를 얻었고, serving latency는 −69%다. 소속과 지표는 확인이다. radar.md 이번 달 신규에 편입했다.

↑ 목차

다음에 볼 것

↑ 목차