- 읽은 자료 1건
- 정본 반영 1개 파일
- 레이더 0건
1광고 랭킹 학습이 지연 피드백을 세 스트림으로 나눠 다룬다 — X
자료 xai-org/x-algorithm@c279172 — GitHub 커밋, 코드, 2026-09-18. 커밋 메시지는 Open-source X Recommendation Algorithm이고, 정규 일일 미러 릴리스다. 바뀐 파일은 30개, 줄 수는 +1491/−154다. 이 노트들은 X 추천 코드의 네 번째 공개(4세대) 뒤에 나온 커밋에 차례로 번호를 붙여 4세대+1·4세대+2 …로 부르며, 이 커밋은 4세대+24다.
배경 X의 오픈소스 미러는 매일 밤 x.com 프로덕션 스냅숏의 재편된 커밋 하나를 공개한다. 4세대+24는 4세대+23(2026-09-17, FavHoldoutFilter 신설 등)의 다음 릴리스다.
지연 피드백(delayed feedback)은 학습 라벨이 시점상 밀려서 도착하는 조건을 말한다. 광고 노출 후 며칠에 걸쳐 관측되는 컨버전(구매·설치·리드 폼 완료 등)을 학습 라벨로 취급할 때 생긴다. X는 4세대+6(2026-08-21)에서 광고 컨버전 액션을 20개 확장하면서 이 문제를 다루는 config 플래그 세 개를 처음 붙였다. 세 플래그는 condition_conversion_on_click·train_view_through_heads·split_head_training_by_source다. 4세대+23(2026-09-17)에서는 지연 창을 3-tier(원본·tier 2·tier 3)로 세분화했다. 이번 커밋(4세대+24)은 이 세 플래그를 단일 ads_head_masking 플래그와 3개의 sample-source 스트림 ID로 통합했다.
새로 알게 된 것 이번 커밋에는 크게 세 방향의 변경이 몰려 있다.
- 광고 랭킹 학습 파이프라인이 delayed feedback을 sample-source 축의 3-stream으로 재정의했다.
- Phoenix(X For You 피드의 랭킹 트랜스포머)의 wire proto에 새 채널 두 개가 생겼다. 유저 광고 참여 이력의 시간창 카운트와 검색 렉시컬 매치다.
- grox(Grok 기반 nearline 분류기)의 안전 파이프라인에 새 spam-clone 탐지 흐름이 붙었다. 참조 영상 번들과 후보 영상을 VLM(이미지와 글을 함께 입력받는 모델)으로 비교하는 흐름이다.
그 외에 다수의 소규모 정리가 함께 왔다.
A. 지연 피드백 플래그 셋이 하나로 합쳐지고, 학습 샘플은 세 스트림으로 나뉜다
광고 랭킹 학습 설정에서 지연 피드백을 다루던 플래그 세 개가 지워지고, 그 자리에 플래그 하나가 들어왔다. 이 플래그를 켜면 헤드마다 어느 스트림의 샘플로 학습할지가 정해진다.
이 변경은 다음 파일에 있다 확인 —
phoenix/xrex/models/recsys_model.py(+50/−55), 신규phoenix/xrex/models/ads_head_masking.py(67줄),phoenix/xrex/data/recsys/constants.py.모델 설정에서 지연 피드백용 필드 세 개가 전부 삭제되고, 기본으로 꺼져 있는 필드 하나가 들어왔다 확인.
RecsysAggregatedModelConfig에서condition_conversion_on_click·train_view_through_heads·split_head_training_by_source세 필드가 삭제됐다.- 그 자리에 들어온 필드는
ads_head_masking하나이고, 선언은ads_head_masking: bool = False다.
샘플 출처를 가리키는 스트림 ID 상수 세 개가 새로 생겼다 확인.
FRESH_STREAM_ID = 0 EARLY_RELABEL_STREAM_ID = 1 LATE_SPLIT_STREAM_ID = 2플래그를 켜면 새 함수가 헤드별 loss 마스크를 조립한다 확인.
ads_head_masking=True일 때 loss 마스크는ads_head_masking_factor(targets, source_id, num_actions)함수가 조립한다.- 함수는 (batch, seq, num_actions) 크기의 실수 텐서를 반환한다. 각 액션 인덱스는 아래 규칙으로 켜진다.
헤드 종류마다 학습에 쓰는 스트림이 다르다 확인.
- Engagement 헤드는
num_actions에서 CT·VT·twin 인덱스를 뺀 나머지이고,FRESH_STREAM_ID샘플에서만 1이다. - CT 헤드(click-conditioned,
CLICK_CONDITIONED_ACTION_INDICES)는EARLY_RELABEL_STREAM_ID샘플에서 클릭이 있었으면 1이다. - VT 헤드(view-through,
VIEW_THROUGH_ACTION_INDICES)는EARLY_RELABEL_STREAM_ID샘플에서 클릭이 없었으면 1이다. - Twin 헤드(late-window delayed, 신규 목록
ADS_LATE_WINDOW_TWIN_HEAD_INDICES)는LATE_SPLIT_STREAM_ID샘플에서 클릭이 있었고 early counterpart가 없을 때만 1이다.
- Engagement 헤드는
Twin 헤드는 4세대+6에서 신설된 base tier 지연 컨버전 10종이다 확인 —
phoenix/xrex/data/recsys/ads_late_window.py(29줄 신규).- 10종의 이름은
ADS_ATTRIBUTED_KEY_CLICK_CONVERSION_DELAYED·ADS_ATTRIBUTED_CLICK_CONVERSION_DELAYED·ADS_PURCHASE_CONVERSION_DELAYED·ADS_MID_FUNNEL_CONVERSION_DELAYED·ADS_ADD_TO_CART_CONVERSION_DELAYED·ADS_UPPER_FUNNEL_CONVERSION_DELAYED·ADS_WEB_CONVERSION_DELAYED·ADS_SEARCH_CONVERSION_DELAYED·ADS_SIGN_UP_CONVERSION_DELAYED·ADS_CHECKOUT_INITIATED_CONVERSION_DELAYED다(action index 204-213, 4세대+6에서 신설).
- 10종의 이름은
이번 커밋은 이 base tier 10종에만 twin 로직을 붙였다 확인. 어제(2026-09-17) 4세대+23에서 신설된 tier 2(214-223)·tier 3(224-233)은 아직 이 목록에 편입되지 않았다.
twin 헤드마다 그것을 억제하는 fresh-stream 카운터파트가 함께 정의됐다 확인.
동시에 신설된
ADS_LATE_WINDOW_TWIN_SUPPRESSOR딕셔너리가 twin 헤드마다 억제자인 fresh-stream 카운터파트 인덱스를 매핑한다.ADS_LATE_WINDOW_TWIN_SUPPRESSOR = { ADS_ATTRIBUTED_KEY_CLICK_CONVERSION_DELAYED: ADS_ATTRIBUTED_KEY_CLICK_CONVERSION, ADS_ATTRIBUTED_CLICK_CONVERSION_DELAYED: ADS_ATTRIBUTED_CLICK_CONVERSION, ADS_PURCHASE_CONVERSION_DELAYED: ADS_PURCHASE_CONVERSION, ADS_MID_FUNNEL_CONVERSION_DELAYED: ADS_MID_FUNNEL_CONVERSION, ADS_ADD_TO_CART_CONVERSION_DELAYED: ADS_ADD_TO_CART_CONVERSION, ADS_UPPER_FUNNEL_CONVERSION_DELAYED: ADS_UPPER_FUNNEL_CONVERSION, ADS_WEB_CONVERSION_DELAYED: ADS_ATTRIBUTED_CLICK_CONVERSION, ADS_SEARCH_CONVERSION_DELAYED: ADS_SEARCH_CONVERSION, ADS_SIGN_UP_CONVERSION_DELAYED: ADS_SIGN_UP_CONVERSION, ADS_CHECKOUT_INITIATED_CONVERSION_DELAYED: ADS_CHECKOUT_INITIATED_CONVERSION, }—
phoenix/xrex/data/recsys/ads_late_window.py, 2026-09-18
같은 (유저·광고) 샘플에서 fresh stream의 카운터파트 컨버전이 이미 잡혀 있으면, late-split의 twin 헤드는 학습에서 제외돼 이중 계산을 피한다 확인.
ads_head_masking_factor안에서no_early_counterpart = 1 - targets[:, :, suppressor_index]로 이 억제자를 조회한 뒤, late-split twin 헤드 마스크에 곱한다.
웹 컨버전의 지연 헤드는 웹 컨버전이 아니라 attributed-click 컨버전을 억제자로 잡는다 확인. 웹 컨버전이 attributed-click 컨버전의 지연 관측으로 간주된다는 뜻으로 읽힌다 추정.
ADS_WEB_CONVERSION_DELAYED의 카운터파트는ADS_WEB_CONVERSION이 아니라ADS_ATTRIBUTED_CLICK_CONVERSION으로 매핑돼 있다.
메트릭 슬라이스도 함께 재정의됐다 확인. late-split 스트림에서 클릭이 있고 early 카운터파트가 없는 샘플을 보는 슬라이스가 새로 생겼다.
build_metric_masks가condition_conversion_on_click·split_head_training_by_source두 파라미터를 잃고, 대신ads_head_masking하나만 받는다.- 새 슬라이스는
late_split_no_early(=mask × late × click × no_early)다. 기존fresh·delayed_clicked·delayed_non_clicked는 유지된다.
의미. 지연 피드백 라벨링을 프로덕션 학습 파이프라인에서 3-스트림으로 명확히 나눠 처리한다는 결정이다. Chapelle 2014 이후의 delayed feedback 문헌은 대체로 "라벨 관측 창을 기다린다 vs 예측치를 상시 갱신한다" 축에서 논의됐다. X는 후자에 가깝게 "fresh(즉시)·early(짧은 창)·late(긴 창)" 세 관측 시점을 각각 sample source로 명시한다.
train_view_through_heads=False 기본으로 view-through 헤드를 꺼 두던 이전 관행은 사라졌다. 4세대+6에서 도입된 VT 헤드 8종이 이번엔 ads_head_masking=True이면, 클릭이 없을 때 EARLY_RELABEL 슬라이스에서 자동으로 학습에 편입된다. 배포 시점은 이 config가 mparams(학습 config에 넘기는 모델 파라미터)에 "ads_head_masking": True로 설정되는 커밋에서 확인할 수 있다.
B. 구매액 loss는 이제 early-relabel 스트림의 샘플로만 학습한다
광고 구매액(purchase value)을 회귀로 예측하는 loss가 유효하다고 보는 샘플 범위가 좁아졌다. 4세대+22에서는 fresh가 아닌 샘플 전체가 유효했고, 이제는 early-relabel 스트림의 샘플만 유효하다.
이 변경은
phoenix/xrex/models/loss_recsys.py(+75/−10)에 있다 확인.유효 마스크의 조건이 early-relabel 스트림으로 좁혀졌다 확인. 즉 late-split 스트림에서는 구매액 회귀를 학습하지 않고, twin 헤드의 분류만 학습한다.
purchase_value_valid_mask의 조건이sample_source > 0에서sample_source == EARLY_RELABEL_STREAM_ID로 좁혀졌다.- 4세대+22(2026-09-16)에서 구매액 loss가 정식으로 연결됐을 때는 "delayed(=fresh가 아닌 것) 샘플" 전체를 유효로 봤지만, 이번엔 오직 early-relabel 스트림만 유효로 취급한다.
loss 통계 이름도 대부분 새 이름으로 바뀌었다(합계 키
_purchase-value-sums는 그대로) 확인.purchase-value-*에서purchase-value_delayed_clicked-*로 변경됐다.위 마스크 조건과 이름을 맞춘 것이다. 이 헤드가 학습되는 실효 슬라이스가 "delayed sample 중 clicked"라는 부분집합임을 스탯 이름 자체에 담았다.
"purchase-value_delayed_clicked-loss": loss, ... "_purchase-value-sums": sums, —
phoenix/xrex/models/loss_recsys.py, 2026-09-18
구매액 지표를 지수 이동 평균(EMA)으로 평활해 발행하는 함수가 새로 생겼다 확인.
- 새 함수
purchase_value_smoothed_stats가 EMA 스무딩된 loss·ratio-mae·target-ratio·baseline-mean-usd·usd-mae·calib을 발행한다. - 기본 스무딩 창은
(1 << 28, 1 << 30)이다. 각각 2^28 ≈ 2.68억 샘플, 2^30 ≈ 10.7억 샘플 크기의 지수 이동 평균이다. trainer_recsys.py는 이 창 두 개에 대해 shape=(10,) 텐서를 EMA state로 유지하도록 훅_purchase_value_ema_keys를 추가했다. 체크포인트 리로드 시점에 shape 불일치가 나면 zeros로 재초기화한다.
- 새 함수
USD MAE와 calibration 지표도 새로 발행된다 확인.
- USD MAE는
purchase-value_delayed_clicked-usd-mae다. - calibration은
purchase-value_delayed_clicked-calib이고, 예측 ratio 총합 대비 실제 ratio 총합이다.
- USD MAE는
광고 매출 예측이 옥션에서 어떻게 재조정되는지에 관해서는 이번 커밋에 실제 연결이 없다 확인.
purchase_value_loss_weight=0.0기본도 유지된다.
의미. 4세대+22에서 붙었던 광고 매출 회귀 loss의 학습 범위가 좁혀졌다. 예전에는 "지연 관측 창 안"이면 무조건 학습에 들어갔고, 이제는 "지연 관측이 조금(early) 발생한 슬라이스에만" 학습에 들어간다. Late-split 슬라이스는 이제 twin classification 헤드만 학습하고 구매액 회귀는 하지 않는다.
즉 X의 광고 랭킹은 두 갈래 학습 스택으로 정착 중이다. 짧은 시차 관측에서는 구매액을 회귀로 학습하고, 긴 시차 관측에서는 컨버전 여부만 분류로 학습한다.
C. Phoenix 요청에 광고 참여 횟수를 시간 창별로 담는 필드가 생겼다
Phoenix의 서빙 요청 형식에, 액션별 참여 횟수를 여러 시간 창으로 센 표가 들어갈 자리가 생겼다. 유저의 광고 참여 이력과 후보 광고 자체의 참여 이력, 두 곳에 같은 형식이 쓰인다. 이 값을 소비하는 학습·배치 인코딩은 이번 커밋에 없다.
이 변경은 두 proto 파일에 있다 확인 —
phoenix/crates/serving/xai-recsys-proto/proto/recsys.proto(+22),phoenix/python/common/xai-proto/proto/recsys.proto(+22).- 새 메시지는
EngagementCounts다.
message EngagementCountRow { int32 action = 1; repeated uint32 counts = 2; } message EngagementCounts { bool present = 1; repeated uint32 window_secs = 2; repeated EngagementCountRow rows = 3; int64 updated_at_ms = 4; int64 window_end_ms = 5; }- 새 메시지는
카운트 표는 요청의 두 슬롯에 연결됐다 확인.
PredictNextActionsRequest.user_ads_engagement_counts = 24: 유저 컨텍스트에 실리는 광고 참여 이력의 시간창 카운트 매트릭스다.AdInfo.engagement_counts = 23: 각 후보 광고 자체가 갖는 참여 이력 시간창 카운트다.
이 매트릭스는 (action × time window) 이차원 카운트 표이고, 요청 페이로드에 실려 서빙 랭커로 들어간다 확인.
window_secs는 시간 창 길이의 리스트이고,rows의 각 원소는 특정 액션 인덱스에 대해 그 창들에서 관측된 카운트를 나열한다.updated_at_ms·window_end_ms가 이 매트릭스의 시간 기준점이다.
이 필드를 소비하는 서버 측 학습·배치 인코딩은 이번 커밋에 반영되지 않았다 확인. Proto 층만 열렸고,
xrex/data/recsys/*에는 관련 파싱이 없다.
의미. 이 필드는 4세대+9(2026-08-26)에서 ConvAssetIds가 유저의 최근 광고 크리에이티브 노출 이력을 요청에 실은 데 이은 후속이다. 이번엔 크리에이티브 asset이 아니라 액션 단위의 시간창 카운트가 대상이다. 각 광고 후보의 자체 engagement 이력과 유저의 광고 engagement 이력이 대칭적으로 열렸다는 점이 특징이다. 광고 랭킹에서 유저·아이템 페어의 최근 참여 통계가 명시 피처로 진입한다는 신호로, YouTube/Meta 계열의 "user × item time-window count" 표준 피처와 방향이 같다 추정.
D. Phoenix의 포스트 정보 메시지에 검색어 일치 신호가 생겼다
Phoenix wire proto의 포스트 정보 메시지에 검색 렉시컬 매치(검색어 단어가 포스트에 그대로 나오는지) 필드가 새로 붙었다. 이 값을 학습이나 서빙에서 쓰는 지점은 이번 커밋에 없다.
같은 두 proto 파일에서
TweetInfo에 새 필드가 붙었다.message TweetInfo { // ... 기존 필드 37개 ... SearchLexicalMatch searchLexicalMatch = 38; } message SearchLexicalMatch { float matchedWordFraction = 1; bool exactPhrase = 2; }필드 타입은
SearchLexicalMatch이고, 단어 일치 비율과 완전 일치 여부 두 값으로 이뤄진다.matchedWordFraction은 검색 쿼리 단어 중 트윗에 등장하는 비율이다.exactPhrase는 쿼리 문자열이 완전 일치로 등장했는지 여부다.
검색 랭킹 config에서 소비될 것으로 보이지만, 학습·서빙 소비 지점은 이번 커밋에 없다.
- 그 config는
xrecsys_search다.
- 그 config는
의미. 렉시컬 매치가 후보 생성 신호에서 랭킹 신호로 통과할 채널이 열렸다. X의 오픈소스 미러 4세대 이후로 검색 랭킹 라인에서는 대체로 두 관행이 유지되어 왔다. xrecsys_search config가 별도로 도는 것과, EarlyBird 스타일 렉시컬 매치를 후보 생성 단계에서 흡수하는 것이다. 이번엔 렉시컬 매치를 후보 자체의 wire 필드로 승격했다.
Elasticsearch/Lucene 계열의 BM25(단어 빈도에 기반한 고전적 검색 점수) 스코어 대신, (fraction, exact_phrase) 두 축의 단순 통계를 넘기는 방식이다. X 특유의 짧은 텍스트·해시태그·핸들이 섞인 쿼리 도메인에서는 이 두 축이 오히려 노이즈에 강할 수 있다.
E. grox가 확인된 위반 영상과 후보 영상을 VLM으로 비교하는 스팸 클론 탐지를 추가했다
grox의 안전 파이프라인에 새 탐지 흐름이 생겼다. 참여가 많은 영상 포스트를 골라, 확인된 위반 영상들의 스토리보드(시간순 프레임 묶음)와 함께 VLM에 넘겨 비교하게 한다.
- 이 흐름은 다음 파일에 있다 확인 —
grox/flows/ptos/plan_safety_ptos_media_injected_adult_infrared_video_spam_detection.py(44줄 신규),task_safety_ptos_media_injected_adult_infrared_video_spam_detection.py(188줄),task_safety_ptos_media_injected_adult_infrared_video_spam_detection_filter.py(55줄),grox/core/data_loaders/media_reference_bundle.py(146줄 신규). - 흐름은 grox의 PTOS(정책 기반 위반 카테고리 판정)에 붙었고, Kafka 토픽 하나가 이 흐름을 트리거한다 확인.
- 흐름 이름은
safety_ptos_media_injected_adult_infrared_video_spam_detection으로 길다. - Kafka 토픽
safety-ptos-media-injected-adult-infrared-video-spam-detection을 소스로 하는 streaming task generator가 이 흐름을 트리거한다.
- 흐름 이름은
- 대상은 이미 NSFW로 플래그되지 않은 고참여 영상 포스트다 확인. Eligibility 필터는 다음 조건을 모두 요구한다.
- 유저가 있다.
- 포스트나 인용된 포스트에 비디오가 있다.
- fav count가
media_hydration.deluxe_fav_count_threshold이상이다(고참여 포스트). - 이미 NSFW로 플래그된 포스트가 아니다.
- 필터 이름은
TaskSafetyPtosMediaInjectedAdultInfraredVideoSpamDetectionFilter다.
- 통과한 포스트는 참조 영상 번들과 함께 VLM으로 넘어간다 확인.
MediaReferenceBundleLoader.current("media_injected_adult_infrared_video_spam")으로 blobstore에서 참조 영상 번들을 가져온다.- 그 뒤 VLM에 참조 영상 스토리보드와 후보 영상 스토리보드를 함께 넘긴다.
- 참조 번들은 참조 영상을 최대 10개까지 담고, 15분마다 새로 읽는다 확인. 번들 loader의 규격은 다음과 같다.
- Blobstore URI(
blobstore://<namespace>/<subpath>형식)에서manifest.json을 읽어 최대 10개의 참조 영상 스펙을 로드한다. - 각 영상은 최대 10 프레임이고, 프레임 크기는 최대 2 MiB다.
- 15분 주기로 리프레시하고(
refresh_interval_s=900기본), 최초 로드에 실패하면 60초마다 재시도한다. - 번들 identity를 위해 매니페스트와 프레임 바이트의 SHA-256 digest 12자를 유지한다.
- Blobstore URI(
- VLM으로는 vision sampler config 하나가 60초 timeout으로 호출된다 확인.
- 그 config는
GROK_4_1_FAST_HEDGEHOG_CRITICAL이고,grox_config.get_model로 조회한다.
- 그 config는
- 프롬프트는 참조 영상 프레임을 먼저 넣고, 심사할 포스트를 그 뒤에 넣어 비교를 지시한다 확인.
- 시스템 메시지는 새 템플릿
media_injected_adult_infrared_video_spam_detection.j2다(본문 미공개). - 유저 메시지는
Reference storyboards from N confirmed violating videos (frames in chronological order):로 시작해 참조 영상 프레임들을 순서대로 인터리브한다. - 그 뒤에
Post under review:와 함께 후보 포스트(descendants 제거)를 렌더한다. - 마지막에
Compare the video storyboard(s) of post {post.id} against the reference storyboards and provide the requested JSON object.라고 지시한다. - 어시스턴트 시드는
THINKING_CONTROL_END다. 즉 사고 컨트롤 토큰으로 열린다.
- 시스템 메시지는 새 템플릿
- 응답이 위반이면 안전 상태에 위반 정책이 붙고, 결과는 안전 파이프라인 sink로 넘어간다 확인.
- 응답에서
<json>{"violation": bool, "reason": "..."}</json>패턴을 뽑아MediaInjectedAdultInfraredVideoSpamVerdict로 파싱한다. violation=True이면SafetyPtosState에SafetyPolicy(category=..., type=..., ...)형태로 위반 정책을 붙인다.- 이후
TaskWriteSafetyPostAnnotationsResultSink가 결과를 안전 파이프라인 sink로 흘려 보낸다.
- 응답에서
의미. X의 grox 파이프라인이 "확인된 위반 영상 스토리보드 집합과의 시각 비교"라는 형태로 확장됐다. 문헌상 near-duplicate video detection(거의 같은 영상 찾기)은 임베딩 기반이 표준인데, X는 임베딩 매칭 대신 VLM 프롬프트에 스토리보드 프레임을 직접 넣어 시각적 매칭 판정을 맡기는 방식을 선택했다. Reference bundle이 blobstore에서 15분마다 리프레시되므로, 운영 팀이 새로 확인된 클론 후보 영상을 번들에 추가하면 별도 재배포 없이 판정에 반영된다는 특성이 있다. 흐름 이름의 infrared가 특정 촬영 모드(예: 야시경으로 촬영된 성인 영상 클론)를 지칭하는 것으로 읽히지만, 원문 공개 없이는 정확한 카테고리 정의를 확인할 수 없다 추정.
F. 그 밖의 소규모 변경
- abuse-enforcement-service(모델 점수로 계정 조치를 내리는 서비스)의 Kafka 컨슈머·프로듀서가 토픽마다 cluster/zone을 따로 지정할 수 있게 됐다. 변경 파일은
abuse-enforcement-service/service-lib/src/lib.rs(+390/−56)와growthbook.rs(+35/−6)다.- 컨슈머·프로듀서 config가 서비스 전역 mTLS cluster/zone 대신 토픽 단위로 override할 수 있게 됐다.
- 새 메트릭
abuse_enforcement_kafka_consumer_start_total{topic,cluster,result}이 부팅 시점의 컨슈머 시작 결과를 라벨로 기록한다. consumer_error_total이 감시 대상 토픽 집합에만 스코프되도록 필터도 붙었다.
- grox가 URL을 모으는 순서가 바뀌었고, 도메인 집합이 삽입 순서를 지키게 됐다. 변경 파일은
grox/core/data_loaders/data_types.py다._collect_urls에서 유저 URL이 카드 URL 뒤로 밀렸다.- 도메인 dedup이
set대신dict[str, None]이 되어 삽입 순서가 유지된다. 다운스트림 판정에서 도메인 노출 순서가 안정되는 부수 효과가 있다.
- grox가 웹 검색 도구에 넘기는 허용 도메인이 최대 5개로 잘린다. 이전에는 전체 리스트가 그대로 넘어갔다. 변경 파일은
grox/libs/grok_sampler/eapi_sampler.py다.eapi_sampler가web_search툴에 넘기는allowed_domains가search_allowed_domains[:MAX_SEARCH_DOMAINS]로 잘린다(MAX_SEARCH_DOMAINS = 5).
- grox 리플라이 스팸 판정의 로그 라벨 이름이 바뀌었다. 변경 파일은
grox/flows/reply_spam/task_spam_detection.py다.- "lower than 1000 follower bucket"이 "Gemma bucket"으로 바뀌었다. 4세대+22의 follower 분기 이후 Gemma 스코어 = 0 판정을 지칭하는 표기로 통일한 것이다.
- home-mixer(For You 피드를 조립하는 서비스)의 파라미터 미러는 동기화 시각만 바뀌었고, 실제 기본값 변경은 없다. 변경 파일은
home-mixer/params/param.rs다.- 이 파일은 가중치와 상수의 프로덕션 값을 매일 동기화해 오는 크론 미러다.
- 동기화 시각은
2026-09-16T16:23:12Z → 2026-09-17T20:46:44Z로 바뀌었다.
- Brazil2026 election filter(브라질 선거법원이 조치한 계정을 하드코딩해 걸러 내는 필터)의 계정 목록이 갱신됐다. 변경 파일은
home-mixer/filters/brazil_2026_election_filter.rs(+143/−4)다.- 신규 계정 12개를 하드코딩했고, "no live account found" 주석 4건을 갱신했다. 정기 갱신 관행이 이어지고 있다.
- Phoenix의 Cargo 설정이 thrift crate 저장소를 git tag에서 crates.io registry로 옮겼다. 변경 파일은
phoenix/Cargo.toml이다.- 버전은
0.24.0으로 같지만, checksum 잠금이 붙어 공급망 재현성이 강화된다.
- 버전은
- Phoenix 서빙 번들을 export할 때, 요청에서 채울 필드와 템플릿 값으로 고정할 필드를 나누게 됐다. 코드는 Phoenix
xrex/train/recsys_bundle_export.py다.- 새 상수
REQUEST_BATCH_KEYS(약 30개 배치 키 집합)가 정의됐다. - 서빙 번들 export 시점에 이 키에 속하는 필드는
source: "request"로 표기해 요청 페이로드에서 채운다. - 나머지는
source: "template"으로 표기하고, example_data의 균일 값을 fill로 굳혀 번들에 포함시킨다. 균일하지 않은 template은 오류를 낸다. - 즉 요청 스키마가 명시적으로 정의되면서, 서빙 시 어떤 필드가 클라이언트에서 오고 어떤 필드가 고정 상수인지가 계약으로 잠긴다.
- 새 상수
- visibility-filtering(포스트마다 이 뷰어에게 보여도 되는지 판정하는 서비스)의 테스트 하나에 기본값 채움 구문이 추가됐다. 다른 곳에서 구조체가 필드를 얻은 것으로 보이는 부수 변경이다.
gizmoduck_hydrator테스트에..Default::default()가 추가됐다.
정본 반영 services/x.md의 ## 광고 절 아래에 새 하위 절 ### 4세대+24 (2026-09-18, c279172)를 추가했다. 4세대+22의 광고 conversion 액션 절(condition_conversion_on_click·train_view_through_heads·split_head_training_by_source 서술)에는 "이 세 필드는 4세대+24에서 통합됐다"는 짧은 크로스링크를 붙였다. 4세대+22의 구매액 loss 서술에서는 stat 이름도 새 명명으로 크로스링크했다.
의미 ⚠ 주장 변경: 정본이 서술해 온 지연 피드백 옵션 세 개는 코드에서 사라졌고, 4세대+22 구매액 loss의 유효 범위 서술도 뒤집혔다.
- ⚠ 주장 변경 #1. 지연 피드백 학습을 나누던 config 옵션 세 개가 삭제되고 플래그 하나로 통합됐다.
- 4세대+6 이래로 정본이 서술해 온 "delayed feedback 학습 분기 config 옵션 3종(
condition_conversion_on_click·train_view_through_heads·split_head_training_by_source)"이 4세대+24에서 전부 삭제되고ads_head_masking하나로 통합됐다. - 이전 표에 담긴 세 옵션은 이제 코드에 존재하지 않는다. 다만 3-스트림 마스킹 자체는 이전 세 옵션의 조합을 강화한 형태이므로 개념 골자는 유지된다.
- 4세대+6 이래로 정본이 서술해 온 "delayed feedback 학습 분기 config 옵션 3종(
- ⚠ 주장 변경 #2. 4세대+22 구매액 loss의 유효 범위가 early-relabel 스트림으로 좁혀졌다.
- 4세대+22 구매액 loss가 "delayed sample 전체(
sample_source > 0)에 대해 유효"라던 서술이 뒤집혔다. 이번엔EARLY_RELABEL_STREAM_ID(early-relabel 스트림)에서만 유효다. - Late-split 스트림에서는 구매액 회귀가 학습되지 않고 twin 분류 헤드만 학습된다.
- 4세대+22 구매액 loss가 "delayed sample 전체(
- ⚠ 부분 주장 변경 #3. 4세대+23이 열어 둔 tier 2/3 질문은 4세대+24에서도 풀리지 않았다.
- 4세대+23 서술 "delayed conversion tier 2/3의 시차 창 정의와 학습 loss weight는 이번 커밋에 명시되지 않음"이 4세대+24에서도 그대로 열려 있다.
- 4세대+24가 twin 마스킹을 붙였지만 그 대상은 base tier(204-213)이고, tier 2(214-223)·tier 3(224-233)은 여전히 연결되지 않았다. 즉 어제 신설된 tier 2/3 액션이 오늘 학습 파이프라인에는 편입되지 않았다.
- 4세대+9(
ConvAssetIds) 이후 광고 요청 페이로드가 유저 광고 이력을 명시적으로 실은 두 번째 채널이 열렸다. 이번은 크리에이티브 asset ID가 아니라 (action × time-window) 카운트 매트릭스라는 점이 다르다. - 검색 랭킹 라인에 렉시컬 매치 시그널이 wire 필드로 처음 등장했다. 렉시컬 매치가 후보 생성에만 흡수되던 관행이 랭킹까지 확장될 가능성이 열렸다.
검증에서 뒤집힌 것
- 정본이 서술해 온 지연 피드백 옵션 세 개가 삭제됐고, 구매액 loss의 유효 조건이 좁혀졌다. 위
## 1의 A·B 절 참조.condition_conversion_on_click·train_view_through_heads·split_head_training_by_source3개 옵션이 삭제됐다.- 조건은
sample_source > 0→sample_source == EARLY_RELABEL_STREAM_ID로 바뀌었다.
다음에 볼 것
ads_head_masking이 미러에서 켜지는 시점 —mparams["ads_head_masking"] = True가 어느 학습 config에 실리는지 본다. 특히 홈 랭킹 계보인_home_direct_packed_base와 광고 랭킹 계보인_ads_*가운데 어디에서 먼저 활성화되는지가 3-스트림 마스킹의 실제 배포 축을 결정한다.- tier 2/3 지연 액션의 twin 마스킹 편입 — 4세대+23에서 신설된 tier 2·3(214-233)이 언제
ADS_LATE_WINDOW_TWIN_HEAD_INDICES와ADS_LATE_WINDOW_TWIN_SUPPRESSOR에 편입되는지 본다. 편입되면 tier별 suppressor 매핑, 즉 어떤 fresh 카운터파트를 억제 축으로 잡는지가 tier 정의 자체에 대한 힌트가 된다. EngagementCounts의 소비 지점 — Phoenix 학습·서빙의 어느 계층이 이 (action × window_secs) 매트릭스를 소비하는지 본다.xrex/data/recsys/에 파싱이 붙는 커밋에서 확인할 수 있다.SearchLexicalMatch가 랭킹에 들어가는 위치 —xrecsys_searchconfig가 이 두 신호를 어떤 layer에서 소비하는지 본다. 후보 생성 스코어와 조합되는지, 혹은 별도 헤드로 붙는지도 본다.media_injected_adult_infrared_video_spam_detection흐름의 실제 배포 — reference bundle의 blobstore URI가 dynamic config에 등장하는 시점을 본다. VLM 판정률·false-positive 관측이 dashboard에 붙는 시점도 본다. 흐름 이름의infrared카테고리 정의가 공개되는지도 본다.- 구매액 loss가 late-split 스트림에서 빠진 결과 — 매출 예측 헤드의 학습 슬라이스 축소가 실측 매출 예측 지표(usd-mae·calib)에 어떻게 반영되는지 본다. 새로 발행된 스무딩 창(2^28·2^30) 두 축의 stat이 학습 로그에 나타나는 시점도 본다.
레이더
- 오늘 arXiv cs.IR 30건을 선별했고, 통과는 0건이다. 파싱된
<entry>개수는 30이다.- 어제(2026-09-18 daily, 4세대+23)에서 LIGE-GR·SARA·ANGLE·PCap 4건이 이미 편입됐다.
- 오늘 새로 등장한 30건 가운데 수용 기준을 넘는 것은 없다. 기준은 플랫폼 기업 저자, 프로덕션 배포·A/B 결과 주장, 랭킹·retrieval 메커니즘의 신규성이다.
- 대부분이 RAG·LLM 재랭킹·retrieval 벤치마크·의료·법률·과학 도메인에 국한된 학술적 증분이다.
- 산업 블로그는 월요일에만 훑는다. 오늘은 토요일이므로 건너뛰었다.