1. Phoenix 랭커에 광고 conversion 액션 20개가 늘고 delayed feedback 학습 분기가 붙었다 — X (4세대+6, 28e414f) — 광고·랭킹
자료 xai-org/x-algorithm @ 28e414f — "Open-source X Recommendation Algorithm" — 2026-08-21 19:10 UTC, 공개 소스코드. 파일 35개, +856/−152. 4세대+5(d0cef2f, 2026-08-20, 14 파일 +479/−200) 대비 규모는 2배 가까이지만 4세대+4의 대형 확장(79 파일 +3.3k/−0.7k)의 1/4 수준. 광고 매출 예측 스택의 액션 수·delayed feedback 처리·Muon 레시피 export의 세 축이 이번 드랍의 새 내용이고, 나머지는 4세대+2·+4에서 시작된 흐름(Grok 4.6 심판, dark_traffic shadow, SlateContext 배선)의 후속 정리다.
배경 4세대 이후 X 저장소는 매일 커밋 리듬으로 후속 드랍이 붙어 왔다: 8/14 4세대+1(c65aa17) → 8/17 +2(b089ce6) → 8/18 +3(11a71f8) → 8/19 +4(aad7179, 대형) → 8/20 +5(d0cef2f) → 8/21 +6(28e414f, 이번). 이번 커밋은 4세대~+5까지의 canon이 다뤄 온 세 흐름 —
- (a) 랭킹 파이프라인의 signal 채널 확장 (topic feedback → AI trend feedback, SID 3계층,
RewardOutputs·rewardRerankSlotProb,SlateContext) - (b) PTOS 심판 계층의 세대 전환 (safemodel↔PtOS disagreement → Grok 4.5 심판 → 4.6 dial 0.1 → 0.3)
- (c) VF·grox 리소스 튜닝 (visibility-filtering shadow, grox reply_spam follower 임계)
와 결이 통하지만, 광고 매출 예측 헤드의 세분화라는 새 축이 붙었다는 게 4세대~+5와의 차이다. 새로 나오는 개념 몇 개:
- MACT (Mobile App Conversion Tracking) — 모바일 앱 광고에서 앱 내 이벤트(인앱 구매·튜토리얼 완료·회원 가입 등)를 광고 노출·클릭에 귀속시키는 계측 프레임워크. 광고주가 SDK로 앱 내 이벤트를 로그하면 X 광고 시스템이 어떤 노출·클릭이 그 이벤트를 유도했는지 매칭. 기존 X 랭커 proto에는
ADS_ATTRIBUTED_MACT_CLICK_INSTALL하나만 있었는데(앱 설치가 클릭에 귀속), 이번에 6개 인앱 이벤트 × click·view 각 2종 = 12개로 부풀어 올랐다. - View-through conversion — 유저가 광고를 봤지만 클릭하지는 않고, 이후 다른 경로로 컨버전(구매·가입 등)한 경우. 클릭 기반 귀속(click-through)과 대비되고, 노출만으로도 광고 효과가 있었다고 인정하는 계측 방식. 이번에 X 랭커가 view-through 계열 8개 액션(purchase·add_to_cart·checkout_initiated·sign_up·site_visit·session·landing_page_view·upper_funnel)을 신설.
- Delayed feedback — 광고 conversion은 노출·클릭 시점과 실제 컨버전(예: 회원 가입, 인앱 구매) 시점이 몇 시간~며칠 벌어진다. 학습 시점에 도착한 라벨이 "아직 안 일어남"인지 "안 일어날 것"인지 구분하기 어려워 손실 왜곡이 생긴다. 랭커 문헌에서는 delayed conversion prediction이 별도 학문 분야(Chapelle 2014 이후). 이번 커밋에서 X는 각 학습 샘플에
is_delayed_feedback컬럼을 붙이고, 광고 conversion 헤드는 delayed 샘플만·engagement 헤드는 fresh 샘플만 학습하도록 loss mask를 갈랐다. - Muon optimizer — Newton-Schulz orthogonalization으로 gradient momentum matrix를 근사 직교화하는 optimizer. Keller Jordan 2024 원문 + Moonshot Kimi K2 계열의 LLM 학습에서 확산. 4세대+4(aad7179)에서 X Phoenix 랭커의 dense-parameter 기본 optimizer로 도입됐지만, TRAINING.md는 export 파이썬 코드가 여전히 AdamW라고 명시하고 있었다. 이번 커밋에서 문서·config·reference 학습 스크립트가 flagship + nano가 Muon으로 학습됨을 명시하는 방향으로 재작성돼 export/프로덕션 간극이 좁혀졌다.
- NVIDIA GB300 (Grace Blackwell 300) — NVIDIA의 2025~2026 datacenter GPU. Blackwell 세대(B200 후속). 각 GB300 노드가 대용량 HBM3e과 CUTLASS/CUTe DSL 기반 attention 커널을 지원. X가 처음으로 하드웨어 특정 config(batch size, expert parallelism, remat policy, attention impl)를 명시적으로 코드에 드러냈다.
xai-o2object storage — xAI 내부 스토리지 시스템으로 추정되는 S3 호환 오브젝트 스토리지. 이번 커밋에서 클라이언트 crate 인터페이스는 공개됐으나 실 구현은 오픈소스 빌드 제외. 프로덕션 checkpoint·데이터 저장이xai-o2에 붙는 듯한 신호[추정]— 오픈소스 빌드에서는 표준object_storecrate로 폴백 필요.
광고 conversion 액션 20개 신설 (proto 171–190)
proto 액션 신설 목록 [확인] — phoenix/crates/serving/xai-recsys-proto/proto/recsys.proto enum ActionName:
ADS_ATTRIBUTED_MACT_PURCHASE = 171;
ADS_ATTRIBUTED_MACT_ADD_TO_CART = 172;
ADS_ATTRIBUTED_MACT_LEVEL_ACHIEVED = 173;
ADS_ATTRIBUTED_MACT_TUTORIAL_COMPLETE = 174;
ADS_ATTRIBUTED_MACT_SIGN_UP = 175;
ADS_ATTRIBUTED_MACT_CUSTOM = 176;
ADS_ATTRIBUTED_MACT_VIEW_PURCHASE = 177;
ADS_ATTRIBUTED_MACT_VIEW_ADD_TO_CART = 178;
ADS_ATTRIBUTED_MACT_VIEW_LEVEL_ACHIEVED = 179;
ADS_ATTRIBUTED_MACT_VIEW_TUTORIAL_COMPLETE = 180;
ADS_ATTRIBUTED_MACT_VIEW_SIGN_UP = 181;
ADS_ATTRIBUTED_MACT_VIEW_CUSTOM = 182;
ADS_PURCHASE_CONVERSION_VIEW_THROUGH = 183;
ADS_ADD_TO_CART_CONVERSION_VIEW_THROUGH = 184;
ADS_CHECKOUT_INITIATED_CONVERSION_VIEW_THROUGH = 185;
ADS_SIGN_UP_CONVERSION_VIEW_THROUGH = 186;
ADS_SITE_VISIT_CONVERSION_VIEW_THROUGH = 187;
ADS_SESSION_CONVERSION_VIEW_THROUGH = 188;
ADS_LANDING_PAGE_VIEW_CONVERSION_VIEW_THROUGH = 189;
ADS_UPPER_FUNNEL_CONVERSION_VIEW_THROUGH = 190;
두 부류로 나뉜다:
(A) MACT 6개 인앱 이벤트 × click/view = 12개 (171–182):
- purchase (인앱 구매), add_to_cart, level_achieved (게임 레벨 달성), tutorial_complete (튜토리얼 완료), sign_up (회원 가입), custom (광고주 정의 커스텀 이벤트)
- 각각
MACT_<이벤트>(click-attributed = 유저가 광고 클릭 후 앱에서 이벤트) +MACT_VIEW_<이벤트>(view-attributed = 유저가 광고 보기만 하고 클릭 없이 앱에서 이벤트) 두 계열. - 기존에는
ADS_ATTRIBUTED_MACT_CLICK_INSTALL(=140) 하나만 있어서 앱 설치만 예측했다면, 이제 앱 설치 이후의 6가지 참여 이벤트를 클릭·뷰 각각으로 12개 헤드로 예측한다.
(B) View-through conversion 8개 (183–190):
- purchase / add_to_cart / checkout_initiated / sign_up / site_visit / session / landing_page_view / upper_funnel
- 각각
<conversion>_VIEW_THROUGH. 이미 존재하던 click-attributed conversion(ADS_PURCHASE_CONVERSION= 200 등)과 짝을 이뤄 view-through 대응 헤드가 신설. 8개 웹 컨버전(광고주 사이트 방문·구매·가입 등)을 view-through로도 예측.
ads_slim과 ads_conversion_view_through 엔게이지먼트 그룹 매핑
constants.py 신규 매핑 [확인] — phoenix/xrex/data/recsys/constants.py:
기존 ads_conversion_engagement_to_action_types에 신규 12 MACT 매핑 추가:
"IsAttributedMactPurchase": ["AdsAttributedMactPurchase"],
"IsAttributedMactAddToCart": ["AdsAttributedMactAddToCart"],
...
"IsAttributedMactViewCustom": ["AdsAttributedMactViewCustom"],
"IsPurchaseConversionViewThrough": ["AdsPurchaseConversionViewThrough"],
"IsAddToCartConversionViewThrough": ["AdsAddToCartConversionViewThrough"],
...
"IsUpperFunnelConversionViewThrough": ["AdsUpperFunnelConversionViewThrough"],
그리고 새 metric group ads_slim — 7개 signal + 앞 conversion click 매핑에서 primary가 아닌 것들만 걸러 넣음:
ads_slim_engagement_to_action_types = {
"IsOpenLink": ["ClientTweetOpenLink"],
"IsExternalLinkLongDwelled": ["ClientTweetExternalLinkLongDwelled"],
"IsVideoQualityViewed": ["ClientTweetVideoQualityView"],
"IsNotInterestedIn": ["ClientTweetNotInterestedIn"],
"IsBlockAuthor": ["ClientTweetBlockAuthor"],
"IsReported": ["ClientTweetReport"],
"IsMuteAuthor": ["ClientTweetMuteAuthor"],
**{
eng: actions
for eng, actions in ads_p_conv_click_engagement_to_action_types.items()
if eng not in primary_engagement_to_action_types
},
}
즉 광고 랭커의 "slim" 라인은 3개 긍정 신호(open link + external link long dwell + video quality view) + 4개 부정 신호(not interested + block + report + mute) + primary가 아닌 conversion click들만 학습. metric group 라우팅 딕셔너리에도 "ads_slim": ads_slim_engagement_to_action_types 등록. 광고 랭킹 config가 이 그룹을 골라 붙일 수 있게 준비.
SOURCE_SPLIT_CONVERSION_HEAD_INDICES 신설 — click-conditioned action index + view-through action index 두 리스트를 이어붙인 대이스트. 아래 delayed feedback 분기에서 사용.
NEGATIVE_FEEDBACK_HEAD_INDICES에 CLIENT_TWEET_SEARCH_QUERY_REFORMULATED 추가 — 4세대+4의 xrecsys_search config 확장과 이어지는 signal: 유저가 검색 결과가 마음에 안 들어 쿼리를 다시 짜면 이를 부정 피드백 헤드에 포함. 검색 지면 랭킹이 이 신호를 학습.
Delayed feedback를 학습 손실에서 분기
sample_source batch 필드 신설 [확인] — phoenix/xrex/data/recsys/recsys_batch.py:980:
sample_source=(
record_batch.column("is_delayed_feedback")
.fill_null(False)
.to_numpy(zero_copy_only=False)
.astype(np.bool_)
.reshape(-1, 1)
if "is_delayed_feedback" in record_batch.schema.names
else np.zeros((batch_size, 1), dtype=np.bool_)
),
즉 kafka/parquet record batch에 is_delayed_feedback 컬럼이 있으면 그 값(True=이 샘플은 delayed feedback 재관측분)을 sample_source로 배치에 담고, 없으면 전부 False. feature_config.py의 required columns 리스트에 is_delayed_feedback·conversionKeepMask 두 컬럼이 추가돼 upstream 인디케이터가 확정된다.
loss mask 분기 [확인] — phoenix/xrex/models/recsys_model.py loss() 함수:
if self.config.split_head_training_by_source and delayed_mask is not None:
conv_head_split_mask = (
jnp.zeros(num_actions).at[jnp.array(SOURCE_SPLIT_CONVERSION_HEAD_INDICES)].set(1.0)
)
eng_head_mask = 1.0 - conv_head_split_mask
is_delayed = delayed_mask[:, :, None]
loss_mask = loss_mask * (1 - is_delayed * eng_head_mask) # delayed 샘플에서는 engagement head 손실 0
loss_mask = loss_mask * (1 - (1 - is_delayed) * conv_head_split_mask) # fresh 샘플에서는 conversion head 손실 0
즉 각 학습 샘플이 fresh(원본 impression) 또는 delayed(conversion 도착 후 재관측) 두 상태 중 하나이고:
- fresh 샘플: engagement 헤드(favorite·reply·click 등)만 학습, conversion 헤드는 mask=0
- delayed 샘플: conversion 헤드(위 20개 신설 + 기존 click-conditioned 액션)만 학습, engagement 헤드는 mask=0
메트릭 슬라이스 신설 — fresh(delayed=0), delayed_clicked(delayed=1 & clicked=1), delayed_non_clicked(delayed=1 & clicked=0) 세 슬라이스가 관측되도록 build_metric_masks에 분기 추가. condition_conversion_on_click이 필수 전제조건(assert)이라 delayed 샘플이라도 "click 있었나"라는 조건 하에 conversion을 예측하는 conditional 학습 유지.
의미 delayed feedback modeling이 광고 conversion 예측의 표준 문제인데, X는 이제 (a) 별도 kafka 이벤트로 delayed 재관측분을 흘리고 (b) 랭커 학습에서 손실을 분기해 fresh는 engagement로 delayed는 conversion으로 갈라 학습한다. 이는 duplicate labeling 문제(같은 impression을 fresh와 delayed 두 이벤트로 두 번 로그)에 대한 손실 정합성 장치이자, conversion 예측 헤드가 20개로 부풀면서 각 헤드의 학습 signal이 충분히 갱신되게 유지하는 인프라 뒷받침.
mact_in_app_loss_weight — MACT 12개 액션에만 곱하는 loss weight (default 1.0). config 파라미터로 노출되어 광고 conversion 12 헤드의 학습 강도를 조정 가능. stats["mact-in-app-loss-weight"]로 관측.
train_view_through_heads — 8개 view-through 헤드를 학습할지 게이트. False면 view-through head 손실 mask를 0으로 만들어 학습 안 함. 즉 view-through 예측은 config에서 opt-in.
conversion_keep_mask / conversionKeepMask — 후보별로 conversion 학습에서 제외할지 마스킹. from_record_batch에서 kafka의 conversionKeepMask 컬럼을 읽고, null인 행은 True로 대체(=keep). loss()에서 이 마스크를 target_padding_mask와 AND해서 conversion 학습 대상에서 제외. 주의: sequence packing에서는 all(True)만 허용 — 아직 미배선 케이스는 assert로 명시 실패.
Muon optimizer export 승격
TRAINING.md 재작성 [확인] — phoenix/TRAINING.md:
이전:
The dense-parameter optimizer in this export is standard Optax AdamW. The internal deployment uses a tuned RMS-normalized-Adam derivative in that optimizer slot.
이후:
Two dense-parameter optimizer families ship in this export:
- Muon (
xrex/optimizers/recsys/muon.py): the production home-ranker recipe — consistent-RMS scaling with decoupled weight decay on the matrix and embedding partitions. The flagship ranking configs andhome_direct_packed_nanoselect it (optim="muon"), so the nano trains with the same dense-optimizer recipe production runs.- Standard Optax AdamW: the slot used by the remaining shipped configs (two-tower retrieval, gen-recs, and the legacy ranking presets). ...
README.md 역시 이전의 "one training-recipe exception ... standard AdamW rather than production's tuned internal variant"에서 **"The flagship ranking configs and the nano twin train the production Muon recipe, which ships in full"**로 재작성. reference/README.md의 train_step.py 항목도 "dense optimizer + rowwise-AdaGrad"로 일반화됐고 flagship/nano가 Muon 사용 명시.
임베딩 optimizer 도 확장 정본화 — 임베딩 rowwise AdaGrad에 flagship + nano는 (a) accumulator half-life decay, (b) lazy per-row decay, (c) decoupled weight decay 세 옵션을 함께 씀을 TRAINING.md가 명시. 4세대+4의 emb_optim_config(LR 0.28, half-life 2500 step, lazy_decay, weight_decay 2.8e-4) 파라미터가 정본화된 셈.
의미 4세대+4(2026-08-19)에 Muon이 코드로 도입됐을 때 canon 이해는 "코드는 export됐지만 학습 레시피는 여전히 프로덕션 특화"였다. 이번 커밋으로 export되는 학습 파이썬 코드를 그대로 돌리면 프로덕션 Muon 레시피와 동일한 학습이 되는 상태로 이동. 재현성 문서가 좁혀졌지만 데이터·infra는 여전히 미공개(README caveat 유지).
GB300 하드웨어 특정 오버라이드
_GB300_OVERRIDES 정의 [확인] — phoenix/xrex/configs/xrecsys.py:330-345:
_GB300_OVERRIDES = {
"bs_per_device": 512,
"ep": 64,
"attn_impl": "cutedsl_ranker_varlen_attn",
"remat_policy": RematType.SAVE_GB300_RECSYS,
"unroll_layer_stack": True,
"learning_rate": 5e-4,
"checkpoint_every_n": 300,
"optim_config": RecsysDenseOptimConfig(
optim="muon",
muon_consistent_rms=0.2,
muon_matrix_weight_decay=0.01,
muon_split_fused="qkv:128",
adam_embedding_weight_decay=0.01,
b1=0.95,
b2=0.98,
...
),
...
}
bs_per_device=512: 이전_home_direct_packed_nano의bs_per_device=64보다 8배. GB300의 HBM 여유 반영.ep=64: expert parallelism 64-way. MoE 스타일 sharding.attn_impl="cutedsl_ranker_varlen_attn": NVIDIA CUTLASS/CUTe DSL 기반 variable-length attention 커널. GB300 최적화된 신규 attention impl.remat_policy=RematType.SAVE_GB300_RECSYS: GB300 메모리 계층에 맞춘 rematerialization 정책(무엇을 checkpoint하고 무엇을 재계산할지).unroll_layer_stack=True: 트랜스포머 layer stack을 unroll(순환 대신 명시 나열)로 컴파일. XLA 최적화 여지 확장.learning_rate=5e-4: 4세대+4의 flagship base LR 7.1e-4보다 약간 낮음. bs_per_device 8배에 맞춘 스케일링[추정].checkpoint_every_n=300: 300 step마다 checkpoint 저장.
_home_direct_packed_nano가 이 오버라이드를 상속 — 이전엔 learning_rate=2e-3으로 별도였는데 이번 커밋에서 _GB300_OVERRIDES의 LR·optim_config·emb_optim_config를 그대로 상속. 즉 export의 "nano" 모델조차 GB300 학습을 상정한 파라미터로 튜닝됨.
의미 X가 하드웨어 세대 전환을 코드에 노출한 첫 사례. 이전 canon은 "Phoenix가 어느 GPU에서 도는지 미공개"였는데 이제 GB300이 프로덕션 표준 하드웨어라는 강한 신호. NVIDIA GB300은 2025 하반기 출하 시작, Blackwell B200 후속. LLM 회사가 대량 확보하는 최신 세대인데 xAI가 랭커 학습·서빙 파이프라인에 그대로 붙였다. cutedsl_ranker_varlen_attn은 xAI 자체 커널일 가능성 — 오픈소스 커널 카탈로그에 이 이름은 없다 [추정].
xai-o2 스토리지 crate 인터페이스 공개
xai-o2 crate 신설 [확인] — phoenix/crates/storage/xai-o2/:
Cargo.toml description:
Client interface for the xai-o2 (S3-compatible) object storage backend
3개 파일:
base_client.rs(12줄):BaseO2Clientasync trait —put(key, data) -> Result<()>하나만 정의된 최소 인터페이스.o2_client_builder.rs(115줄):O2ClientBuilder가 endpoint·bucket·prefix·access_key_id·secret_access_key·allow_anonymous·timeout·io_timeout·retry_max_times·retry_min_delay·retry_max_delay·write_chunk_size_mib·write_chunk_concurrency·max_concurrent_write_requests·trace_always 15개 builder method를 노출.lib.rs(7줄):pub mod선언.
중요: O2ClientBuilder::build()는 오픈소스 빌드에서 항상 다음 에러 반환:
pub const BACKEND_UNAVAILABLE: &str =
"the xai-o2 backend is not included in this build; use the default object_store backend";
pub fn build(&self) -> Result<Arc<dyn BaseO2Client>> {
Err(anyhow::anyhow!(BACKEND_UNAVAILABLE))
}
즉 인터페이스 스터브만 공개, 실 구현체는 오픈소스 빌드에 포함 안 됨. xai-recsys-engine crate가 xai-o2 = { workspace = true }로 의존성 선언은 했지만 실제 사용 시 폴백 필요.
의미 xAI 내부에 xai-o2라는 이름의 S3 호환 오브젝트 스토리지 시스템이 있다는 게 처음 확정. 15개 builder param은 프로덕션에서 실제 튜닝하는 항목 목록이라 유의미 — chunk 8MiB, concurrency 16, max_concurrent 64, retry 6회, min/max delay 1/32s, timeout 300s가 테스트에 나오는 realistic 값(build_fails_loudly_after_full_configuration 테스트 세팅). 프로덕션 checkpoint·데이터 저장이 여기 붙는다는 신호 [추정] — 오픈소스 빌드는 표준 object_store crate(AWS S3 등)로 폴백.
SlateContext가 NextActionDistribution 필드로 이동
proto diff [확인] — phoenix/crates/serving/xai-recsys-proto/proto/recsys.proto:
message NextActionDistribution {
map<uint32, float> indexToContinuousValues = 7;
RewardOutputs rewardOutputs = 8;
+ SlateContext slateContext = 9;
}
의미 4세대+4(aad7179)에서 SlateContext는 ScoreInfo 메시지의 필드로 처음 등장했다(pool_rank·fatigue·pre_diversity·SID 3계층·SID gap 3계층). 4세대+5(d0cef2f)에서 PostCandidate.served_slate_context가 배선돼 home-mixer가 이 값을 소비하기 시작했다. 이번 4세대+6에서는 NextActionDistribution(각 후보의 action별 예측 분포)에도 SlateContext가 붙는다 — 즉 Phoenix가 서빙 응답에서 (a) 후보 하나에 대해 각 action별 예측 분포를 돌려주고, (b) 각 액션 분포 옆에 slate context를 함께 실어 보낼 수 있게 된다. ScoreInfo(재순위 슬레이트 결정)와 NextActionDistribution(액션 예측)의 두 자리에 slate context가 붙는다는 관찰.
정본 반영 ../services/x.md 랭킹 및 Phoenix 학습·인덱스 절 — 4세대+6 후속 드랍 절 신설 (### 4세대+6 (2026-08-21) — 광고 conversion 20 헤드·delayed feedback split·Muon export 승격·GB300 override·xai-o2 stub·SlateContext per-action·grox 임계 80k·dark_traffic staging·Grok 4.6 100%).
grox reply_spam follower 임계 60k → 80k (3번째 상향, 1.33배)
diff [확인] — grox/flows/reply_spam/task_filter.py:
- FOLLOWER_COUNT_THRESHOLD_FOR_SPAM_DETECTION = 60000
+ FOLLOWER_COUNT_THRESHOLD_FOR_SPAM_DETECTION = 80000
...
- FOLLOWER_COUNT_THRESHOLD_FOR_REPLY_RANKING = 60000
+ FOLLOWER_COUNT_THRESHOLD_FOR_REPLY_RANKING = 80000
10일간 4단계 상향: 15,000 (2026-08-13 이전) → 30,000 (2026-08-14, 4세대+1) → 60,000 (2026-08-18, 4세대+3) → 80,000 (2026-08-21, 4세대+6). 이전 두 번은 2배씩(15→30, 30→60)이었는데 이번은 1.33배로 상승 폭이 완만해졌다.
의미 임계는 "follower_count < threshold일 때만 grok으로 답글 스팸 판정·답글 랭킹 스코어 매김"의 상한이라, 임계가 오를수록 grok 리소스가 더 큰 계정의 답글까지 커버한다. 80k에서 상승 속도가 느려진 건 (a) grok 예산 병목에 근접, (b) 그 이상 계정에서는 스팸 답글 유입이 적어 marginal utility 감소, 또는 (c) 다음 단계는 임계 없이 전면 온으로 넘어갈 준비 중 셋 중 하나 [추정].
visibility-filtering dark_traffic 타깃을 shadow → staging으로 전환
diff [확인] — visibility-filtering/dark_traffic_setup.rs:
-const SHADOW_WORKLOAD: &str = "xai-vf-shadow";
+pub const STAGING_XDS_DEST: &str = "xai-vf-service.staging.visibility:grpc";
+const FORWARDER_NAME: &str = "staging";
+
+pub fn staging_tls_domain(dc: &str) -> String {
+ format!("visibility.visibility-filtering-service.staging.{dc}.s2s.twttr.net")
+}
...
-struct StaticShadowDiscovery;
+struct StaticStagingDiscovery;
4세대+4(aad7179, 2026-08-19)에서 3일 전 도입된 dark_traffic 인프라가 프로덕션 shadow 워크로드(xai-vf-shadow.prod.visibility)에서 스테이징 환경(xai-vf-service.staging.visibility)으로 리네이밍. TLS 도메인도 visibility.visibility-filtering-service.prod.{dc}.s2s.twttr.net에서 .staging.으로 이동. StaticShadowDiscovery 구조체 이름도 StaticStagingDiscovery로 리네이밍.
의미 dark_traffic이 프로덕션 트래픽을 프로덕션 shadow 워크로드에 미러링하는 구조에서 프로덕션 트래픽을 staging 환경으로 미러링하는 구조로 전환. 3일 만에 방향이 바뀐 셈이다. 두 해석:
- Shadow 워크로드를 별도로 유지하지 않고 staging 환경을 shadow처럼 활용 — infra 정리.
- 프로덕션 트래픽 shadow가 staging 배포 검증에 쓸 만한 값이 있다고 판단.
어느 쪽이든 VF 실험이 프로덕션 shadow 자원이 아니라 staging 자원 예산에서 돌게 됨. 4세대+5까지의 canon은 "shadow deploy 기반이 배선됐다"였는데 이제 그 기반이 stage 미러링으로 재정의된다 — ⚠ 4세대+4의 shadow 서술 재해석.
Grok 4.5 internal 완전 제거, PTOS 심판 100% Grok 4.6 internal 전환
diff [확인] — grox/flows/ptos/classifier.py (+6/−63):
삭제:
_EAPI_4_5_INTERNAL_BREAKER_CONFIG(circuit breaker config)_eapi_4_5_internal_breaker(breaker instance)_GROK_4_6_INTERNAL_DIAL상수 (하루 전 0.3이었던)self.eapi_4_5_internal두 클래스에서 초기화 제거_sample_4_5_internalmethod 제거_cross_model_validate_with_4_5에서 확률 분기 제거 — 항상 4.6 internal 직접 호출classify_policy_for_violation의 deluxe 4.3 재분류에서 확률 분기 제거 — 항상deluxe-4.6-internal
의미 4세대+2 (2026-08-17)에 도입된 심판 계층 → +4 (0.1) → +5 (0.3)의 dial-up 흐름이 4세대+6에서 4.6 internal 100% 전환으로 완결. Grok 4.5 internal은 코드에서 완전 제거돼 롤백 불가. dial 상승이 4일간(10%→30%→100%) 이뤄진 셈. EAPI_GROK_4_5_INTERNAL 모델 자체는 grox_config에 남아 있으나 PTOS classifier에서는 참조 안 함. 4세대+5까지의 canon은 "dial의 다음 이동이 관전 포인트 — 50%/100%로 뛰면 완전 전환 근접"이었는데 이번에 그 관전 포인트가 해소됐다.
retrieval post-embedding에 65k 청킹
maybe_build_retrieval_post_embeddings 리팩터 [확인] — phoenix/xrex/train/trainer_recsys.py _forward_chunked 헬퍼 신설:
기존은 shard 전체를 한 번의 candidate_tower_forward_jit 호출로 계산했는데, 이제:
total_samples % data_world_size == 0인 균등 shard 케이스일 때만_chunk_rows = min(_shard_rows, 65536)으로 chunk 진입- 그 외에는 shard 통째 처리 (
_chunk_rows = _shard_rows) - chunk 단위로
jax.make_array_from_process_local_data→_lookup→candidate_tower_forward_jit→ local shard concatenate → 최종 concat
의미 retrieval two-tower의 post embedding 배치가 커지면 XLA 컴파일/실행 시 OOM 위험이 있어 65k row 단위로 잘라 순차 처리. Muon 승격·GB300 config로 학습 규모가 커지는 흐름의 서브루틴 안정화. head_dataset_mapping 여러 head인 경우도 각 head마다 _forward_chunked 호출로 동일 청킹.
inference hotswap에 --hotswap_malloc_trim CLI 추가
diff [확인] — phoenix/xrex/inference/model_runner.py + launch_inference.py:
새 옵션:
hotswap_malloc_trim: bool = True(InferenceModelRunner필드)- CLI 인자
--hotswap_malloc_trim(default True) _malloc_trim_after_swap()메소드: 매 hotswap cycle 마지막에_glibc_malloc_trim()(=libcmalloc_trim(0)) 호출- 관측:
metrics_publisher.checkpoint_reload_step_seconds.labels(step="malloc_trim").observe(secs)
CLI 도움말이 문제를 명시:
glibc malloc_trim(0) on the coordinator thread after each applied hotswap; returns the cycle's freed pages (glibc slots otherwise ratchet ~196 MiB/cycle). No-op under jemalloc.
의미 Phoenix 서빙에서 embedding table hotswap(주기적으로 새 임베딩 checkpoint를 프로세스 안에서 in-place로 교체)이 glibc 메모리 할당자 하에서 사이클당 ~196MiB씩 RSS를 누수해 왔다는 게 처음 문서화. libc의 malloc_trim(0)으로 해제된 페이지를 OS에 반환. jemalloc(다른 할당자 옵션) 하에서는 무의미. 프로덕션 서빙 하드닝의 작은 패치지만 hotswap이 프로덕션에서 오래 도는 인프라라 이 패치가 필요할 만큼 누적 부담이 있었다는 관찰이 붙는다.
two-tower retrieval 소소한 세팅 추가
diff [확인] — phoenix/xrex/configs/xrecsys_two_tower.py:426-431:
_xrecsys_two_tower_combined_base() 기본 config에 세 옵션 추가:
"qk_norm": True— attention query/key normalization"attn_logit_cap": -1— attention logit capping 비활성화 (-1 = 미사용)"right_anchored_rope": True— RoPE positional encoding right-anchored (시퀀스 끝에서 앵커링)
LLM 학습에서 흔한 안정성 트릭들이 retrieval two-tower로 넘어왔다.
EVERGREEN retrieval dataset 축소 — 5년 → 4~14일
diff [확인] — phoenix/xrex/data/retrieval_dataset.py:255-258:
EVERGREEN = (
5,
- _idx("post_sid_v5_256x6_snapshots/evergreen_video_1825day.parquet"),
- _idx("post_sid_v5_256x6_snapshots_backup/evergreen_video_1825day.parquet"),
+ _idx("post_sid_v5_256x6_snapshots/video_4to14day.parquet"),
+ _idx("post_sid_v5_256x6_snapshots_backup/video_4to14day.parquet"),
)
이름은 여전히 EVERGREEN이지만 실 참조는 1825일(5년)에서 4~14일 최신 비디오로 극단적 축소. 신선한 비디오 4~14일 창을 evergreen slot에 넣는 실험 [추정] — 이름과 실체가 어긋난 상태라 임시적 변경일 가능성.
기타 소소한 패치
- request_metrics.rs 이중 카운트 픽스 —
deadline_admission으로 shed된 요청이 그 이후 gRPCResourceExhausted상태 코드 때문에inflight_cap으로도 카운트되던 문제를guard.recorded_rejectflag로 방지. 테스트 두 개(deadline_shed_does_not_double_count_as_inflight_cap,resource_exhausted_without_prior_reject_counts_inflight_cap) 신규. - checkpoint metadata robustness —
_ORBAX_TMP_PREFIX→ 공개 상수ORBAX_TMP_DIR_SUFFIX로 리네임(이름이 suffix 시맨틱과 맞음),_has_committed_payload+_is_loadable_checkpoint헬퍼로 completion marker(COMPLETED_FILENAME)만 있고 실제 orbax tmp-dir 커밋(rename)이 안 된 checkpoint를 스킵. 크래시-during-checkpoint 시나리오에서 오염 checkpoint 로드 방지. - kafkaloader
exclude_required_columns— 특정 kafka feed가 일부 required column을 옵트아웃할 수 있게. 예상 컬럼이 없을 때 경고 로그와 schema-mismatch 에러 경로 모두 스킵. - grox
config.py1줄 제거 — 사소한 정리 (구체 diff는 짧아 생략).
정본 반영 ../services/x.md — (a) 광고 절에 MACT/view-through 20 액션·ads_slim metric group·delayed feedback split 관련 단락 추가, (b) Phoenix 학습·인덱스 (4세대에서 신설)에 Muon export 승격·GB300 override·xai-o2 stub 절 추가, (c) 안전성 하위 절에서 dark_traffic shadow→staging 서술 뒤집기, (d) PTOS 심판 절의 4세대+6 완결 서술(4.5 internal 완전 제거), (e) 열린 질문에 ### 4세대+6 드랍으로 해소된 것 / 신규 (2026-08-23) 절 추가, (f) 출처에 28e414f 커밋 및 관련 파일 링크 추가.
의미 4세대~+5까지의 정본 서술축은 (a) 랭킹 signal 채널 확장·SID 3계층·RewardOutputs, (b) PTOS 심판 세대 전환, (c) VF·grox 리소스 튜닝, (d) 파이프라인 v3 마이그레이션이었다. 4세대+6에서 광고 매출 예측 스택이라는 네 번째 큰 축이 붙었다:
- proto ActionName 20개 신설(전체 액션 수의 큰 폭 확장)
- delayed feedback를 학습 손실 분기로 정식 처리 (X 랭커 학습이 광고 delayed conversion prediction 문헌과 명시적으로 정렬)
ads_slimmetric group으로 광고 랭킹 라인의 signal 조합 분리mact_in_app_loss_weight·train_view_through_headsconfig로 광고 헤드 학습 강도 튜닝 노브 노출
동시에 (a) Muon 학습 레시피가 export에 정식 포함되고 (b) GB300 하드웨어 특정 config가 처음 등장하면서 재현 가능 학습 인프라와 하드웨어 세대 확인이 나란히 온 사이클. xai-o2 stub 공개는 인프라의 어느 스토리지 계층에 xAI 자체 시스템이 있는지 처음 명시. dark_traffic이 shadow → staging으로 재정의된 건 하나의 문서적 관찰이라기보다는 canon이 반영해야 할 4세대+4 재해석이라 유의미.
검증에서 뒤집힌 것
- VF dark_traffic이 프로덕션 shadow에서 staging 미러링으로 재정의됨 — 4세대+4(2026-08-19) 정본 반영 시점의 서술은 "프로덕션 트래픽을
xai-vf-shadow.prod.visibility에 미러링"이었다. 3일 만에 shadow 워크로드 참조가 삭제되고 staging 환경으로 리다이렉트됐다.../services/x.md의 4세대+4 dark_traffic 절 서술을 이번 4세대+6 반영에서 재작성.
레이더
없음. arXiv cs.IR 8/19~8/20 신규 30건 triage — 통과 0. 대부분 학술(dense retrieval RL, sequential rec benchmarks, financial RAG 등)이고 프로덕션 진술 있는 항목 없음. Meta engineering·Netflix tech blog 신규 없음(Meta 최신은 2026-08-12, Netflix 2026-08-21은 Flink autoscaler 순수 인프라).
다음에 볼 것
is_delayed_feedbackupstream 파이프라인 — kafka에 이 컬럼을 흘리는 컨버전 재관측 이벤트 로거의 소스가 코드에 없음. Server-side conversion tracking API 어딘가일 텐데 오픈소스 빌드에는 미포함. 다음 커밋에서 이 컬럼 소스가 드러날 가능성.split_head_training_by_source프로덕션 활성 시점 — config default False라 아직 opt-in._home_direct_packed_base()나 flagship config에서 True로 승격되는 시점이 광고 conversion 학습 파이프라인 프로덕션 전환의 신호.train_view_through_heads승격 — 8개 view-through 헤드가 opt-in 상태. 이 값이 True로 승격되면 X 광고 랭킹이 view-through conversion을 정식으로 예측하기 시작한다는 뜻.- GB300 config의 실 사용 —
_GB300_OVERRIDES가home_direct_packed_nano에 상속됐지만 flagship 랭킹 config에는 아직 명시 상속 안 됨(base가 이미 4세대+4의 Muon으로 세팅됐고 별개). GB300 override 상속이 flagship에도 붙는지가 관측 포인트. xai-o2실 구현 공개 여부 — stub이 나왔다는 건 인터페이스가 안정화됐다는 뜻이지만, 실 구현이 오픈소스 빌드에 들어올 가능성은 낮다[추정].EVERGREENretrieval dataset의 재정의 — 이름이 실체와 어긋난 상태라 다음 커밋에서 이름 변경(EVERGREEN → SHORT_TERM_VIDEO) 또는 원상 복구를 관측.- Grok 4.6 internal이 완전 전환됐으므로 다음 심판 세대(4.7?) 시작 시점 — 4.5 → 4.6이 4일간 dial 0.1→0.3→1.0로 매일 정교화됐다. 4.6 완전 정착 후 4.7 shadow가 언제 시작되는지가 다음 세대 전환 신호.