0x00

리서치 / 일일 리포트

  • 읽은 자료 1건
  • 정본 반영 1개 파일
  • 레이더 0건
한 줄 요약X가 콜드스타트 실험에서 control과 treatment 두 arm이 똑같은 bucket 관측 기록을 남기도록 고쳤다. treatment arm의 콜드스타트 후보는 Phoenix MoE 후보로 좁혔다.

1콜드스타트 실험의 두 arm이 같은 관측 기록을 남기게 됐다 — X

자료 xai-org/x-algorithm@902a06f — GitHub, 2026-09-04 21:03 UTC, 코드. Open-source X Recommendation Algorithm 정기 크론 미러이고, 바뀐 파일은 25개(+472/−179)다. 이 노트들은 4세대 공개 뒤의 X 커밋에 차례로 번호를 붙여 부르며, 이 커밋은 4세대+16이다.

배경 X의 오픈소스 미러는 크론이 프로덕션 캐넌을 정기적으로 흘려보내는 커밋으로, 어제(2026-09-05) 판에는 4세대+15(9b0dc31)까지 반영됐고 이 커밋(902a06f)이 그다음 판이다. Phoenix는 X For You 피드의 트랜스포머 랭킹 모델이고, Phoenix MoE(Mixture of Experts)는 검색·랭킹 백본을 서로 다른 전문가 서브네트워크에 배분해 서빙하는 아키텍처다. VF는 포스트마다 이 뷰어에게 보여도 되는지를 판정하는 visibility-filtering 서비스다. 이번 커밋은 Phoenix MoE의 A/B 인프라를 다시 손본 것이 중심이고, 부수적으로 Phoenix serving 요청 계약과 VF dark-traffic 연결이 바뀌었으며 예정된 muted-keyword VF rule의 실마리도 드러났다.

새로 알게 된 것

A. 콜드스타트 실험의 두 arm이 같은 bucket 관측 기록을 남기도록 실행 순서를 바꿨다

이제 control과 treatment 두 arm이 똑같은 실험 bucket 관측 기록(impression)을 남긴다 확인. codivert는 X 내부 용어로 보인다 추정. 뜻은 bucket 관측 시점을 두 arm에서 똑같이 맞춰 A/B 분석에 편향이 들지 않게 하는 패턴이고, "co-divert"는 두 arm이 같은 시점에서 각자 분기한다는 의미다 추정. 이번 커밋은 이 패턴을 코드로 구체화했다.

  • home-mixer(For You 피드 요청을 처리하는 서비스)에 뷰어가 이 실험의 control인지 treatment인지를 나타내는 bool param 두 개가 생겼다 확인 — home-mixer/scorers/author_cold_start.rs, home-mixer/params/param.rs.
    • rust_home_mixer_phoenix_moe_codivert_viewer_is_control (bool, default false)

    • rust_home_mixer_phoenix_moe_codivert_viewer_is_treatment (bool, default false)

    • 두 param의 값은 moe_codivert_viewer experiment의 bucket membership에서 들어온다. 두 arm의 YAML rule도 다음처럼 서로 대칭이다.

      - description: "co-divert viewer treatment"
        query: >
          [moe_codivert_viewer bucket_membership treatment]
        values:
          rust_home_mixer_phoenix_moe_codivert_viewer_is_treatment: true
          rust_home_mixer_phoenix_moe_codivert_viewer_is_control: false
          rust_home_mixer_enable_viewer_cold_start_boost: true
      - description: "co-divert viewer control"
        query: >
          [moe_codivert_viewer bucket_membership control]
        values:
          rust_home_mixer_phoenix_moe_codivert_viewer_is_treatment: false
          rust_home_mixer_phoenix_moe_codivert_viewer_is_control: true
          rust_home_mixer_enable_viewer_cold_start_boost: false
      

      — home-mixer/scorers/author_cold_start.rs 테스트 fixture, 2026-09-04

핵심 변화는 AuthorColdStart::apply의 실행 순서를 다시 정렬한 것이다 확인 — home-mixer/scorers/author_cold_start.rs. 이전 판(4세대+3까지)에서는 다음 순서로 실행됐다.

  1. ColdStartTrackedIds를 조회하고 record_tracked_ids를 호출한다.
  2. EnableViewerColdStart가 false면 여기서 조기 반환한다.
  3. viewer_arm(query)를 호출한다. experiment bucket을 실제로 조회하며, 이때 첫 impression이 남는다.
  4. author_corpus(...)를 호출한다. author bucket을 실제로 조회하며, 이때 author-side impression이 남는다.
  5. cold-start 로직을 실행한다.

문제는 2단계의 조기 반환이었다. EnableViewerColdStart=false인 control arm은 3·4단계를 아예 거치지 않는다. 그러면 실험 분석에서 두 arm의 impression 로그 형태 자체가 달라진다. treatment는 viewer bucket과 author bucket을 모두 관측한 사용자만 세고, control에는 관측이 아예 없다. 이렇게 되면 triggered-analysis와 intent-to-treat 사이의 정의가 어긋나고, 파이프라인 진입 편향이 lift 추정을 오염시킨다. triggered-analysis는 파이프라인에 실제로 진입한 사용자만 비교하고, intent-to-treat는 할당된 모든 사용자를 비교한다.

이번 커밋은 순서를 이렇게 바꿨다.

  1. ColdStartParams::read(query)가 모든 param을 한 번에 읽고 params.arm으로 저장한다. 이때 viewer_arm도 함께 호출돼 viewer bucket impression이 남는다.
  2. record_tracked_ids(candidates, &params.tracked_ids)를 호출한다.
  3. params.arm이 Control이나 Treatment이면, 즉 어느 arm이든 codivert에 속하면 enabled 여부와 상관없이 author_corpus(...)를 호출해 author-side bucket impression을 남긴다.
  4. 그다음에 !params.enabled이면 scores 원본을 그대로 반환하며 조기 반환한다. impression이 이미 남은 뒤이므로 관측 로그는 두 arm에서 대칭이다.
  5. cold-start 로직을 실행한다.

새 회귀 테스트 두 개가 이 대칭을 고정한다 확인. control이든 treatment든 moe_codivert_viewer bucket 관측을 정확히 3회, moe_exp(author 대상) bucket 관측을 정확히 2회 남겨야 한다.

#[test]
fn both_arms_log_the_same_codivert_impressions() {
    ...
    assert_eq!(control_impressor.impression_count(CODIVERT_EXPERIMENT), 3);
    assert_eq!(treatment_impressor.impression_count(CODIVERT_EXPERIMENT), 3);
}

#[test]
fn both_viewer_arms_log_the_same_author_impressions() {
    ...
    for query in cases {
        let impressor = Arc::new(SpyingBucketImpressor::new());
        let author_cold_start =
            cold_start_with_author_impressor(vec![2], vec![1], impressor.clone());
        author_cold_start.apply(&query, &candidates, &scores);
        assert_eq!(impressor.impression_count("moe_exp"), 2);
    }
}

— home-mixer/scorers/author_cold_start.rs, 2026-09-04

관측 횟수가 arm과 상관없이 같아야 한다는 대칭성을 assertion으로 고정한 것이다.

의미 이번 커밋은 처음으로 콜드스타트의 A/B 관측 방법론 자체를 코드로 고정한다. 정본(서비스별 현재 이해를 담는 이 저장소의 노트)의 이전 판은 4세대+1(2026-08-14)의 Thompson sampling 연결과 4세대+3(2026-08-18)의 count_tracked_ids 단순화까지 알았고, 이 두 흐름은 콜드스타트 로직의 진화였다. SpyingBucketImpressor라는 테스트 유틸(experiment SDK가 노출한 impression 계측 스파이)이 있다는 사실까지 드러난다. X가 A/B 실험에서 bucket 관측 대칭성을 회귀 테스트로 강제한다는 문화 관찰이 정본에 더해진다.

B. treatment 뷰어의 콜드스타트 후보가 Phoenix MoE 후보로 좁혀졌다

treatment 뷰어의 cold-start 후보는 이제 Phoenix MoE 소스에서 온 후보로 한정된다 확인. treatment corpus author의 포스트라도 Phoenix MoE 소스에서 온 것이 아니면 cold-start boost 대상에서 빠진다.

  • 후보 자격을 판정하는 함수의 treatment 분기에 Phoenix MoE 조건이 추가됐다 확인 — home-mixer/scorers/author_cold_start.rs.

    • 이전 판의 ViewerArm::Treatment 분기는 corpus == AuthorCorpus::Treatment 조건만 확인했다. 이번 커밋에서 && is_phoenix_moe(c)가 추가됐다.

    • treatment 뷰어의 cold-start 후보는 이제 treatment corpus author의 포스트이면서 served_type == ForYouPhoenixRetrievalMoe인 후보만이다.

      fn cold_start_corpus_eligible(arm: ViewerArm, c: &PostCandidate, corpus: AuthorCorpus) -> bool {
          match arm {
              ViewerArm::Holdout => !is_phoenix_moe(c),
              ViewerArm::Control => corpus == AuthorCorpus::Control && !is_phoenix_moe(c),
              ViewerArm::Treatment => corpus == AuthorCorpus::Treatment && is_phoenix_moe(c),
          }
      }
      
  • 테스트 이름도 treatment MoE 후보만 cold-start한다는 뜻으로 바뀌었다 확인 — home-mixer/scorers/author_cold_start.rs.

    • 이전: treatment_viewer_keeps_treatment_moe_and_cold_starts_treatment_corpus
    • 이번: treatment_viewer_cold_starts_treatment_moe_only
    • fixture가 cold_start_candidate(...)에서 moe_candidate(...)로 바뀐 것도 같은 뜻이다.

의미 이 변경은 Phoenix MoE와 cold-start를 하나의 codivert 실험 안에 묶어, 둘이 서로 confounded되지 않게 하려는 연결이다. treatment 뷰어에서는 MoE 연결을 활성화하고 cold-start도 MoE 후보에만 적용해, "MoE의 효과"와 "cold-start 부스트의 효과"가 겹치지 않게 격리한다. YAML에서 enable_viewer_cold_start_boost가 treatment에서는 true, control에서는 false로 고정된 것도 같은 방향이다. cold-start는 이제 Phoenix MoE의 실 트래픽 실험 옆칸으로 재배치됐다.

C. engagement counts hydration이 cold-start 스위치에서 분리됐다

engagement counts hydration을 켜는 조건에서 cold-start 스위치와 캐시 조건이 빠졌다 확인. cold-start와 engagement counts hydration은 이제 서로 독립된 정책 축이다.

  • hydrator를 켜는 조건식이 짧아졌다 확인 — home-mixer/candidate_hydrators/engagement_counts_hydrator.rs.
    • 이전: fn enable(&self, query) -> bool { query.params.get(EnableViewerColdStart) || (!query.has_cached_posts && (query.params.get(EnableEngagementCountsHydration) || query.is_shadow_traffic)) }
    • 이후: fn enable(&self, query) -> bool { query.params.get(EnableEngagementCountsHydration) || query.is_shadow_traffic }
  • 바뀐 점은 세 가지다.
    • EnableViewerColdStart에 대한 종속이 없어졌다.
    • !query.has_cached_posts 게이팅이 없어져, 캐시가 있어도 항상 갱신한다.
    • 정책 축이 순수 hydration flag와 shadow traffic으로 좁혀졌다.

의미 이번 분리로 두 파이프라인의 rollout이 서로 걸림 없이 진행된다. 이전 연결은 "cold-start가 켜지면 반드시 engagement counts를 hydrate한다"는 강결합이었다. cold-start Thompson sampling이 view_count_on_home·fav_count에 의존하는 4세대+1 초기 연결의 유물로 보인다. 특히 codivert 대칭성(A절)과 결합하면 "Treatment는 cold-start 켜짐 + engagement counts 켜짐, Control은 cold-start 꺼짐 + engagement counts는 자기 flag대로"라는 명확한 실험 축 분리가 가능해진다.

D. Phoenix 서빙 요청에 실험 파라미터 오버라이드 필드와 slate 지표 두 개가 생겼다

Phoenix 서빙 요청 계약에 필드 세 개가 새로 생겼다 확인. 하나는 요청마다 experiment 파라미터를 오버라이드하는 map이고, 나머지 둘은 slate(함께 노출되는 후보 묶음) 문맥에 붙는 metric이다. 새 필드는 experiment_overrides와 exact_k·exact_gap이다.

  • Phoenix 서빙 요청에 experiment_overrides map이 생겨, 요청마다 experiment 파라미터를 오버라이드할 수 있다 확인 — phoenix/crates/serving/xai-recsys-proto/proto/recsys.proto, phoenix/python/common/xai-proto/proto/recsys.proto.
    • 필드는 PredictNextActionsRequest.experiment_overrides = 21이고, 타입은 map<string, string>이다.
    • 이전에는 Phoenix 서빙이 서비스 배포 시점의 config·feature switch로 experiment 파라미터를 정해 뒀다.
  • 이 필드는 요청자인 home-mixer가 이미 정해진 자기 A/B 배정을 Phoenix에 그대로 전달해, downstream인 Phoenix의 experiment 배정이 upstream인 home-mixer와 일관되게 흐르도록 하는 연결로 읽힌다 추정.
    • upstream에서 codivert 패턴(A절)이 자리를 잡으면서, downstream까지 같은 experiment 스코프를 지게 할 전달 채널이 필요해진 것이다.
  • slate 문맥에 SlateContext.exact_k/exact_gap 두 필드가 추가됐다 확인. 같은 두 proto 파일의 변경이다.
    • SlateContext.exact_k = 16과 SlateContext.exact_gap = 17은 새 Option<uint32> 필드다.
    • 이전 SlateContext 필드와 각 필드가 붙은 시점은 다음과 같다.
      • SID(semantic ID) 계열 sid_known (필드 6), sid_k_l1/2/3 (7–9), sid_gap_l1/2/3 (10–12): 4세대+3(2026-08-18), VMRanker(슬레이트를 재정렬하는 스코어러)의 SID 연결
      • recon_cos_milli (13): 4세대+9(2026-08-26)
      • recon_count_above (14), recon_gap_above (15): 4세대+11 무렵
  • exact_k/exact_gap는 이 시리즈의 연장이다. sid_k/sid_gap이 semantic ID 코드북 매치 기반 metric이라면, exact_k/exact_gap는 이름 그대로 정확 일치 기반 metric일 가능성이 높다 추정.
    • slate 안의 후보 사이에서 특정 신호(post_id? 저자? 미디어 hash?)가 정확히 일치하는 이웃 후보 수를 exact_k로, 정확 일치가 나타나기 시작하는 slot 갭을 exact_gap으로 해석하는 것이 SID 계열 필드와 자연스럽게 대응한다.
    • 실제 정의는 공개되지 않았다. Phoenix 서빙 코드에서 이 필드를 채우는 곳은 오픈소스에 없다.
  • home-mixer 쪽에도 대응 필드가 연결됐다 확인 — home-mixer/models/candidate.rs.
    • SlateContext struct와 From<xai_recsys_proto::SlateContext> 변환 impl 양쪽에 exact_k: Option<u32>, exact_gap: Option<u32> 두 필드가 추가됐다.

의미 Phoenix serving이 slate context에 관측 metric을 계속 추가하는 흐름이 이어진다. SID 계열(4세대+3)에서 시작해 recon 계열(4세대+9~+11)로 넓어졌고, 이번에는 exact 계열이 붙었다. 소비 경로(RankingScorer 폴백)는 이미 4세대+5의 UseServedSlateContext 게이트에 연결돼 있으니, 새 metric이 붙어도 자동으로 흡수된다. experiment_overrides는 upstream과 downstream의 experiment 스코프 일관성 문제에 대한 계약 차원의 대응이고, codivert 연결(A절)과 시점이 겹치는 것은 우연이 아니다.

E. VF 미러링에 devel 배포가 추가돼 PR별 프리뷰 배포도 프로덕션 트래픽을 받는다

VF dark-traffic은 프로덕션 트래픽을 별도 배포로 복제 전송해 응답 없이 관측만 하는 미러링이다. 이번 커밋으로 미러링 대상이 staging에 더해 devel app_env까지 넓어졌다 확인.

  • 미러 대상 리스너를 고르는 함수가 staging과 devel 두 app_env를 모두 인식하도록 확장됐다 확인 — visibility-filtering/dark_traffic_setup.rs.

    • 이전 판(4세대+6에서 shadow→staging 리네임 완료)의 parse_staging_listener는 .staging.visibility:grpc 접미사만 인식했다.

    • 이번 커밋은 이 함수를 parse_mirror_listener로 리네임했다.

    • 통과하는 리스너 이름의 예가 회귀 테스트에 고정됐다.

      ("xai-vf-service.devel.visibility:grpc", "xai-vf-service.devel"),
      ("xai-vf-service-pr-123.devel.visibility:grpc", "xai-vf-service-pr-123.devel"),
      (
          "xdstp://kube-discovery/envoy.config.listener.v3.Listener/xai-vf-service-pr-123.devel.visibility:grpc?key=val",
          "xai-vf-service-pr-123.devel",
      ),
      

      — visibility-filtering/dark_traffic_setup.rs 테스트, 2026-09-04

  • 채널 팩토리는 리스너가 devel인지 staging인지에 따라 TLS 도메인이 다른 것을 고른다 확인. 같은 파일의 MirrorChannelFactory다.

    • 대상 리스너의 xds_dest에 .devel.이 있으면 devel용 TLS 도메인(visibility.xai-vf-service.devel.{dc}.s2s.twttr.net)의 채널 팩토리를 쓴다.
    • 그렇지 않으면 staging용(visibility.visibility-filtering-service.staging.{dc}.s2s.twttr.net)의 채널 팩토리를 쓴다.
  • xai-vf-service-pr-123.devel.visibility:grpc 형태의 리스너 이름은 GitHub PR 번호 기반으로 자동 생성되는 프리뷰 배포(Kubernetes preview environments)의 관행을 시사한다 추정.

  • 비슷한 이름은 거부하고, 정확히 staging 또는 devel 두 app_env만 허용한다 확인. 같은 파일의 reject 케이스 회귀 테스트도 좁혀졌다.

    • development나 staging-devel 같은 유사 이름이 거부 대상이다.

      "xai-vf-service.development.visibility:grpc",
      "xai-vf-service.staging-devel.visibility:grpc",
      "xai-vf-service.devel-staging.visibility:grpc",
      "xai-vf-service.devel.visibility:grpc-extra",
      "xai-vf-service.devel.visibility:grpc.other",
      

      — 위 파일의 parse_rejects_out_of_scope_listeners 테스트

의미 VF 재작성의 검증 인프라에 PR 단위 검증까지 붙었다. 이 인프라는 4세대+4 dark_traffic → 4세대+6 shadow→staging 리네임 → 4세대+7 reference_compare까지 이어진 감사 스택이다. 개발자가 VF 규칙 변경 PR을 올리면 그 PR용 devel 배포에 프로덕션 트래픽 미러가 흘러 들어와, 실제 프로덕션 규모에서 verdict 차이를 미리 검증할 수 있다. VF는 fail-closed(정본 x.md의 주의 목록 #1)라 규칙 변경 리스크가 크므로, 미러링 스택이 staging 배포에서 PR 배포까지 넓어지는 것이 자연스러운 진화 경로다.

F. VF가 예정된 muted-keyword rule에 쓸 포스트 텍스트 필드를 미리 남겨 뒀다

VF가 지금은 어떤 rule도 쓰지 않는 포스트 텍스트 필드를, 앞으로 붙을 muted-keyword rule을 위해 남겨 뒀다 확인.

  • CoreFeature.text에 dead-code 경고를 억제하는 어트리뷰트가 붙었고, 이 어트리뷰트가 명시적으로 "upcoming muted-keyword rule에 쓰기 위해 남겨 둔다"고 밝힌다 확인 — visibility-filtering/models/tweet.rs.

    #[derive(Clone, Debug, Default)]
    pub struct CoreFeature {
        #[cfg_attr(
            not(test),
            expect(dead_code, reason = "retained for the upcoming muted-keyword rule")
        )]
        pub text: String,
        pub source_tweet_id: Option<u64>,
    }
    

    — visibility-filtering/models/tweet.rs, 2026-09-04

    • VF 서비스가 hydration 단계에서 각 tweet의 text를 이미 채우고 있지만, 현재 어떤 rule도 그것을 소비하지 않는다.
    • 새 테스트 assemble_hydrates_text_from_core_data가 hydration 경로에서 text가 실제로 채워지는지 회귀로 확인한다.
  • 4세대+4(2026-08-19, aad7179)에서 새로 생긴 FollowingViewerMutedKeywordFilter는 Following 파이프라인 전용(65줄)이었다. 이번 신호는 VF 서비스 자체에도 muted-keyword rule이 곧 붙는다는 예고다.

  • VF는 For You 파이프라인 전역을 커버하므로, 뷰어의 muted-keyword 리스트가 Following뿐 아니라 추천 전체에서 필터되는 쪽으로 정책이 넓어지는 방향이다.

의미 다음 커밋에서 관측할 점은 두 파이프라인에서 따로 구현되던 muted keyword 필터가 통합될지(Following 필터가 VF 서비스로 이관), 아니면 나란히 두 층으로 남을지다.

G. 그 밖의 변경

나머지 변경은 Phoenix 학습 코드와 VF·home-mixer 코드를 손본 것이다 확인.

  • Phoenix 체크포인트의 DEK를 KMS로 unwrap하다가 일시적 오류가 나면 재시도한다 확인 — phoenix/python/training/xai-checkpointing/xai_checkpointing/dek.py.

    • 새 함수 _unwrap_with_backoff가 transient 오류(429·502·503·504·"KMS transport" 마커)에서 4회, 총 2초 상한으로 jittered exponential backoff 재시도를 한다.
    • publish_tree_dek·adopt_tree_dek·_unwrap_header_master가 모두 이 wrapper를 거쳐 호출된다.
    • assert_all_enveloped는 finalize 전에 _DEK 마스터 파일이 있는지 반드시 확인한다(encrypted save left no master _DEK at {path}; not committing).
    • 4세대+13에서 새로 생긴 envelope-encrypted Orbax writer를 안정화하는 후속 작업이다.
  • retrieval_dataset.py에서 SID snapshot window 경로를 만드는 코드를 헬퍼 하나로 모았다 확인 — phoenix/xrex/data/retrieval_dataset.py.

    • 헬퍼는 _sid_window(filename) -> (primary, backup)이다.
    • 실제 경로 규칙은 그대로다(post_sid_v8_256x6_snapshots·_backup).
  • StableHLO bundle을 export할 때마다 매니페스트의 생성 시각을 새로 적는다 확인 — phoenix/xrex/train/recsys_bundle_export.py, trainer_recsys.py.

    • restamp_manifest(data)가 export 시점마다 MANIFEST.json의 created_timestamp를 time.time()으로 다시 기록한다.
    • 4세대+13에서 도입한 .mlirbc 번들 시스템의 fresh-detection용 연결이다.
  • backbone score를 bfloat16으로 명시적으로 내렸다가 float32로 다시 올린다 확인 — phoenix/xrex/train/trainer_recsys.py.

    log_probs = jax.nn.log_sigmoid(logits).astype(jnp.bfloat16).astype(jnp.float32)
    cont_preds = candidate_continuous_predictions.astype(jnp.bfloat16).astype(jnp.float32)
    
    • 서빙 정밀도(bfloat16으로 뿌리는 것으로 추정 추정)와 학습 시 관측 numerics를 맞추려는 계산 층이다.
    • 4세대+14에서 새로 생긴 backbone scores 요청 시맨틱과 짝이 되는 numerics 정합 연결이다.
  • 학습 로그 줄 끝에 extra 필드를 자동으로 덧붙이는 구조화 로깅이 생겼다 확인 — phoenix/xrex/utils/log_util.py.

    • log_util이 LogRecord.__dict__에서 표준 어트리뷰트를 뺀 나머지 extras를 key=value 시리즈로 이어 붙여 로그 라인 뒤에 추가한다.
    • event=X extra는 앞에 둔다. bool은 true/false로, 나머지는 json.dumps(default=str)로 적는다.
    • 학습 로그를 grep할 수 있게 하고 downstream 파서를 지원하는 변경이다.
  • VF가 외부에 노출하던 모듈과 함수를 crate 내부용으로 좁혔다 확인 — visibility-filtering/lib.rs.

    • clients·hydration·models·rules·safety_label_source·twemcache 모듈이 pub에서 pub(crate)로, 즉 crate-internal로 좁혀졌다.
    • config.rs·params.rs·server.rs·twemcache/{client,mod}.rs의 여러 pub 함수와 상수도 pub(crate)로 바뀌거나 dead-code로 제거됐다.
    • 4세대+15(9b0dc31)의 800줄 순감소 흐름과 방향이 같다. 재작성이 안정된 뒤 외부에 노출할 필요가 없어진 API를 좁힌다.
  • hydrator 쪽에 작은 변경이 있었다 확인 — home-mixer/side_effects/mutual_follow_stats_side_effect.rs.

    • PhoenixRetrievalMOEInferenceClusterId 조회가 moe_enabled 조건 안팎으로 옮겨져 borrow 수명이 정리됐다.
    • assemble_tweet_features 테스트는 text 하드코딩에서 source_tweet_id로 옮겨졌다(위 F의 muted-keyword 예고와 짝).

"retained for the upcoming muted-keyword rule" — visibility-filtering/models/tweet.rs, 2026-09-04

정본 반영 services/x.md에 다음을 반영했다.

  • 4세대 세대 표에 4세대+16 행을 추가했다.
  • 콜드스타트 절에 codivert impression 대칭 연결, treatment의 Phoenix MoE 국한, engagement counts 게이팅 분리를 추가했다.
  • 4세대+4 dark traffic 절 아래에 devel app_env 확장을 언급했다.
  • SlateContext.exact_k/exact_gap을 SlateContext 진화 계열에, experiment_overrides map을 PredictNextActionsRequest 필드 계열에 추가했다.
  • 새 절 "### 4세대+16 (2026-09-04, 902a06f)"을 4세대+15와 정본 주의 목록 사이에 만들었다.

의미 이번 커밋에서 얻은 문화 관찰은 X가 지금 Phoenix MoE 롤아웃의 A/B 인프라를 재정비하는 국면이라는 것이다. 근거는 다음 세 축이 정합적으로 얽혀 함께 움직였다는 사실이다.

  1. A/B 관측 방법론의 코드화: codivert impression 대칭성이 회귀 테스트로 고정됐다.
  2. experiment 스코프의 수직 전달: experiment_overrides map으로 upstream 배정이 downstream까지 일관되게 흐른다.
  3. cold-start의 Phoenix MoE 실험 축 병합: treatment 뷰어의 cold-start 후보가 MoE 후보에만 걸린다.

VF 스택은 검증 인프라(dark_traffic)를 PR 배포까지 넓히는 방향으로 자체적으로 진화하는 중이고, 예정된 muted-keyword rule의 실마리가 dead-code 어트리뷰트에 명시됐다. Phoenix 학습 스택에서는 4세대+13~+15에서 새로 생긴 envelope encryption·StableHLO bundle·H100 remat 등의 안정화 후속이 이어진다.

검증에서 뒤집힌 것

뒤집힌 것은 없다. 이번 커밋은 정본의 방향과 맞는다. 다만 4세대+3에서 관찰됐던 "count_tracked_ids 로직 단순화 이후 record_tracked_ids 호출자와 param의 실 배선"이 이번 커밋에서 명확해진다.

  • record_tracked_ids는 ColdStartTrackedIds param을 그대로 소비한다.
  • EnableViewerColdStart 게이팅과 상관없이 항상 호출된다(A절 재정렬의 결과).

tracked ID 관측 훅이 A/B와 무관한 상시 관측 채널이 됐다는 사실이 확정된다.

레이더

레이더에 올린 자료는 없다. arXiv cs.IR 30건을 파싱했고, 산업 블로그는 일요일이라 건너뛰었다. 30건을 triage한 결과 통과한 것은 0건이다.

  • 추천·CTR·reranker 관련 9건은 모두 학술 기관 저자 위주이고, 프로덕션 배포나 A/B 주장이 없다. 이 9건은 탈락했다.
    • CORE(MLLM 임베딩 compositional)
    • EPIC(SID diffusion recommendation)
    • LLM4AIGQ(e-commerce guidance query)
    • HypRQ-VAE(hyperbolic long-tail generative rec)
    • SelfDR(LLM 기반 rec reasoning distillation)
    • DoPR(LLM reranker 압축 문서 프리픽스)
    • UniCon(CTR unified context)
    • Recommender System as Slow and Fast Thinkers
    • Training seeds and model-selection stability 등
  • 나머지 21건도 탈락했다. 성격은 세 갈래다.
    • benchmark·평가 방법론: SHELF, MultiGhostBench, Incremental Pooled Eval
    • 도메인 제한: POI·법률·의료·과학·야구·music·finance QA
    • RAG·private retrieval·essay grading 등 LLM 응용 방법론

다음에 볼 것