◂ 일일 리포트2026-08-29 빌드
FEED RESEARCH · 일일 리포트

2026-08-19

수요일 · 읽는 데 약 36분
  • 읽은 자료 2건 (X 4세대+2 드랍 1건 + arXiv triage 30건 중 통과 1건 [SDF/Google Discover])
  • 정본 반영 1개 파일 (x.md 4개 절 갱신)
  • 레이더 갱신 1건 (Google Discover SDF 신규 등록)
  • Meta 엔지니어링 블로그 0(마지막 관련 글 2026-08-05, canon에 이미 반영)
  • Netflix 테크 블로그 0(마지막 2026-08-07
  • 알고리즘 무관)
한 줄 요약X가 4세대 이후 세 번째 후속 드랍(b089ce6, 2026-08-17)에서 (1) 광고 브랜드 안전 판정을 V2로 이중배선해 Grok 라벨 6종을 _V2 버전으로 마이그레이션하고 V1 라벨 중 PROMPT_OWNED_RULES(botmaker rule id 7개) 소속을 강제로 제거하는 compute_verdict_v2를 신설했고 (2) 성인 컨텐츠 판정 불일치 시 Grok 4.5를 심판으로 호출하는 cross-validation 태스크를 추가해 safemodel(자체 비전 모델)이 positive이지만 PtOS 정책이 hard 위반을 못 잡거나 그 반대일 때 Grok 4.5가 다시 판단해서 hard→soft로 강등 가능하게 만들었으며 (3) phoenix-rankall의 인덱싱 게이트 두 개(build1FavIndex·buildMMEmbMetadataDump)의 favoriteCount >= 1 조건을 제거해 이제 후보 전체를 "1fav" 인덱스와 멀티모달 임베딩 메타데이터 덤프에 흘려보내고 fav 없이 도착한 케이스는 1fav_uec_count_race 카운터로 관측만 하게 바꾼 것을 확인했다. 커밋 규모는 파일 34개 +751/−162로 4세대+1(2026-08-14)보다 작지만, 광고 브랜드 안전과 성인 컨텐츠 판정이 하나의 커밋에서 각각 다른 방향으로 정교화됐다는 점이 특징 — V2 마이그레이션은 라벨 스키마 정정, cross-validation은 판정 계층 확장.

1. X 알고리즘 4세대+2 후속 드랍 — 광고 브랜드 안전 V2 + Grok 4.5 성인 컨텐츠 심판 + Phoenix retrieval 인덱싱 게이트 제거

자료 xai-org/x-algorithm @ b089ce6 — "Open-source X Recommendation Algorithm" — 2026-08-17 20:20 UTC, 공개 소스코드. 파일 34개, +751/−162. 4세대+1(2026-08-14) 대비 규모는 작지만 성격은 광고 안전·성인 컨텐츠 심판·retrieval 인덱싱의 세 다른 축을 하나의 드랍에 담았다.

배경

4세대(2026-08-13, 47c1bcd) 초대형 드랍이 파라미터·안전 파이프라인·labeling 서브레포 15개를 통째로 열었고, 4세대+1(2026-08-14, c65aa17)이 그 다음날 가중치 해석 규칙·브라질 선거 필터·Thompson sampling·Phoenix bool 3종·BDSM enforcement note 생성기 부분 공개로 다섯 방향 확장했다 (상세는 daily/2026-08-16.md). 그 흐름 사흘 뒤에 나온 이 커밋(2026-08-17)은 규모가 훨씬 작지만 초점이 광고와 성인 컨텐츠 판정 계층에 명확히 집중돼 있다. X가 4세대 릴리즈 리듬을 "대형 드랍 → 후속 하루짜리 정리 → 며칠 뒤 계층별 정교화"로 잡아가고 있다는 관찰 근거가 하나 더 늘었다 [관찰] 2026-08-19.

특히 세 방향이 canon에 영향을 준다.

첫째, 광고 브랜드 안전 판정에 V2 로직이 나란히 배선됐다. 4세대 초까지 canon은 home-mixer/models/brand_safety.rscompute_verdictMEDIUM_RISK_LABELS(14개)와 LOW_RISK_LABELS(3개)를 순서대로 검사해 광고를 붙일지 판단한다고 반영해 왔다. 오늘 커밋은 그 함수를 지우지 않고 옆에 compute_verdict_v2를 새로 만든 뒤 라벨 세트를 _V2 버전으로 확장하고 특정 V1 라벨을 강제로 필터링하는 strip_v1_grok_written 헬퍼를 도입했다. 이는 라벨 스키마 마이그레이션이 실 프로덕션에서 어떻게 다뤄지는지의 실체 사례 — canon 함정 목록의 "죽은 파일" 판별법에도 관련된다 (V1과 V2가 둘 다 살아 있고 worst_verdict가 그 결과를 결합하는지 여부에 따라 인접성 판정이 달라진다).

둘째, 성인 컨텐츠 판정에 판정 불일치를 대비한 심판(judge) 계층이 붙었다. 4세대에서 처음 공개된 grox의 안전 파이프라인은 TaskSafetyPtosSafemodelSexNudity(자체 비전 모델 기반 sex/nudity 판정)와 PtOS(정책 기반 위반 카테고리 판정)를 병렬로 돌리고 결과가 다를 때는 로그만 남겼다. 오늘 커밋은 이 로직을 두 파일로 분리한다: safemodel은 판정만 하고(_compare_outcome 제거), 새 파일 task_safety_ptos_adult_content_cross_validation.pysafemodel과 PtOS가 disagree할 때 Grok 4.5 심판을 호출해 재판단을 받는다. 심판이 "hard가 아니다"라고 하면 최종 결정은 AdultContentSexualSoft로 강등되고 safemodel의 positive 표시가 클리어된다. 즉 판정 계층이 (a) safemodel + (b) PtOS + (c) Grok 4.5 심판 세 층으로 확장된 것.

셋째, Phoenix retrieval의 인덱싱 게이트가 사실상 제거됐다. phoenix-rankall-stratobuild1FavIndex는 이름 그대로 "1개 이상 favorite을 받은 포스트를 index에 넣는" 함수였고 buildMMEmbMetadataDump(멀티모달 임베딩 메타데이터를 Kafka로 덤프)도 같은 favoriteCount >= 1 게이트를 통과해야 실행됐다. 오늘 커밋은 두 게이트를 모두 제거했다. 즉 이제 모든 후보가 "1fav" 인덱스와 멀티모달 임베딩 덤프에 흘러들어간다. 다만 "1fav" 이름은 유지됐고, fav가 0인 채로 도달한 케이스는 1fav_uec_count_race라는 새 카운터로 계측만 된다. 이건 canon이 3세대~4세대에서 "인덱스는 인기도 신호를 담는다"고 반영해온 것과 정면 배치되는 변경 — retrieval 후보 풀 자체가 사실상 인덱스 전 포스트 집합으로 커진다는 뜻.

새로 알게 된 것 — 광고 브랜드 안전 V2 (Grok 라벨 마이그레이션)

새 함수와 세 라벨 세트 [확인]home-mixer/models/brand_safety.rs:

pub(crate) const MEDIUM_RISK_LABELS_V2: &[SafetyLabelType] = &[
    SafetyLabelType::NSFW_HIGH_PRECISION,
    SafetyLabelType::NSFW_HIGH_RECALL,
    SafetyLabelType::NSFA_HIGH_PRECISION,
    SafetyLabelType::NSFA_KEYWORDS_HIGH_PRECISION,
    SafetyLabelType::GORE_AND_VIOLENCE_HIGH_PRECISION,
    SafetyLabelType::NSFW_REPORTED_HEURISTICS,
    SafetyLabelType::GORE_AND_VIOLENCE_REPORTED_HEURISTICS,
    SafetyLabelType::NSFW_CARD_IMAGE,
    SafetyLabelType::DO_NOT_AMPLIFY,
    SafetyLabelType::MALICIOUS_URL,
    SafetyLabelType::NSFA_COMMUNITY_NOTE,
    SafetyLabelType::PDNA,
    SafetyLabelType::EGREGIOUS_NSFW,
    SafetyLabelType::GROK_NSFA_V2,           // 신규
    SafetyLabelType::GROK_NSFA_EXPANDED_V2,  // 신규
    SafetyLabelType::NSFW_TEXT,
];

pub(crate) const LOW_RISK_LABELS_V2: &[SafetyLabelType] = &[
    SafetyLabelType::NSFA_LIMITED_INVENTORY,
    SafetyLabelType::GROK_NSFA_LIMITED_V2,   // 신규
    SafetyLabelType::NSFA_HIGH_RECALL,
];

즉 V2는 V1 대비 (a) GROK_NSFAGROK_NSFA_V2로 이름 변경 + GROK_NSFA_EXPANDED_V2 신설 (medium에 하나 추가) (b) GROK_NSFA_LIMITEDGROK_NSFA_LIMITED_V2 이름 변경 (low에서 하나 이동). 결과적으로 V1 대비 medium risk 라벨이 14→16으로 증가했고, low risk는 3개 유지.

핵심 로직 — strip_v1_grok_written [확인]:

fn strip_v1_grok_written(labels: &HashMap<SafetyLabelType, SafetyLabel>)
    -> Cow<'_, HashMap<SafetyLabelType, SafetyLabel>>
{
    const V1_DUAL_WRITTEN: &[SafetyLabelType] = &[
        SafetyLabelType::NSFA_HIGH_PRECISION,
        SafetyLabelType::NSFA_LIMITED_INVENTORY,
    ];
    const PROMPT_OWNED_RULES: &[i64] = &[1400, 1410, 1420, 1500, 1510, 1610, 1700];
    let is_v1_grox_written = |label_type: &SafetyLabelType, label: &SafetyLabel| {
        V1_DUAL_WRITTEN.contains(label_type)
            && botmaker_rule_id_from(label)
                .is_some_and(|rule_id| PROMPT_OWNED_RULES.contains(&rule_id))
    };
    if !labels.iter().any(|(t, l)| is_v1_grox_written(t, l)) {
        return Cow::Borrowed(labels);
    }
    Cow::Owned(
        labels.iter()
            .filter(|&(t, l)| !is_v1_grox_written(t, l))
            .map(|(t, l)| (*t, l.clone()))
            .collect(),
    )
}

즉 V2 판정 시 (a) 라벨이 NSFA_HIGH_PRECISION 또는 NSFA_LIMITED_INVENTORY이고 (b) 그 라벨의 botmaker rule id가 PROMPT_OWNED_RULES = [1400, 1410, 1420, 1500, 1510, 1610, 1700] 7개 중 하나면 → V1 프롬프트가 dual-write한 라벨로 판단해 입력 라벨 집합에서 제거하고 나머지로 판정한다. 이는 "V1 프롬프트가 만든 이중 기록(dual write)을 V2 로직이 무시하고 V2 라벨만으로 판단하게 하는 마이그레이션 사다리" 그 자체.

compute_verdict_v2의 판정 순서 [확인]:

pub(crate) fn compute_verdict_v2(labels: ..., tweet_id: u64) -> BrandSafetyVerdict {
    let labels = strip_v1_grok_written(labels);
    if MEDIUM_RISK_LABELS_V2.iter().any(|l| labels.contains_key(l)) {
        return BrandSafetyVerdict::MediumRisk;
    }
    let scored_by_grok = labels.contains_key(&SafetyLabelType::GROK_SFA_V2)
        || labels.contains_key(&SafetyLabelType::GROK_NSFA_LIMITED_V2);
    if !scored_by_grok {
        return BrandSafetyVerdict::MediumRisk;
    }
    if tweet_id >= PTOS_CUTOFF_TWEET_ID && !labels.contains_key(&SafetyLabelType::PTOS_REVIEWED) {
        return BrandSafetyVerdict::MediumRisk;
    }
    if LOW_RISK_LABELS_V2.iter().any(|l| labels.contains_key(l)) {
        return BrandSafetyVerdict::LowRisk;
    }
    BrandSafetyVerdict::Safe
}

V1과 판정 순서 자체는 동일 (medium 캐스케이드 → Grok 채점 여부 → PTOS 심사 → low → 그 외 safe). 차이는 (a) GROK_SFAGROK_SFA_V2, GROK_NSFA_LIMITEDGROK_NSFA_LIMITED_V2로 참조 라벨 이름 변경 (b) V1 이중 기록 제거 전처리 삽입.

핵심 검증 테스트 [확인] — 같은 파일 v2_mirrors_v1_across_tier_matrix:

#[test]
fn v2_mirrors_v1_across_tier_matrix() {
    fn to_v2(v1_set: &[SafetyLabelType]) -> Vec<SafetyLabelType> { /* V1 → V2 라벨 이름 변환 */ }
    let matrix: &[&[SafetyLabelType]] = &[
        &[],
        &[SafetyLabelType::GROK_SFA],
        &[SafetyLabelType::GROK_SFA, SafetyLabelType::PTOS_REVIEWED],
        // ... 6개 시나리오
    ];
    for v1_set in matrix {
        let v2_set = to_v2(v1_set);
        for tweet_id in [PRE_CUTOFF_ID, POST_CUTOFF_ID] {
            assert_eq!(
                compute_verdict(&labels_with(v1_set), tweet_id),
                compute_verdict_v2(&labels_with(&v2_set), tweet_id),
            );
        }
    }
}

즉 X는 V1과 V2가 같은 판정을 내려야 한다는 것을 6가지 라벨 조합 × 두 tweet_id 시점(PTOS_CUTOFF 전/후)에서 명시적으로 assert한다. 마이그레이션 중에는 두 판정이 어긋나지 않아야 광고 인접성이 바뀌지 않는다는 안전장치.

의미 (라벨 스키마 마이그레이션의 관찰 가능성)

canon이 3세대~4세대까지 광고 브랜드 안전을 "손으로 짠 규칙 캐스케이드"로 반영해 왔다면, 오늘의 관찰은 Grok의 안전 라벨 자체가 버전 관리되고 있고 그 마이그레이션이 코드 안에서 dual-write 감지 로직으로 배치돼 있다는 것. 이건 canon 함정 목록의 "죽은 파일" 판별법에도 관련된다 — V1과 V2가 둘 다 export되므로, 어느 쪽이 실제 호출자인지는 상위 하이드레이터(ads_brand_safety_vf_hydrator.rs)에서 확인해야 한다. [확인] 오늘 커밋은 그 하이드레이터도 함께 수정(+13/−7)했다 — 상위 배선이 V1에서 V2로 전환 중이라는 신호.

특히 PROMPT_OWNED_RULES = [1400, 1410, 1420, 1500, 1510, 1610, 1700] 7개 rule id는 botmaker 프롬프트 소유로 명명돼 있는데, 이는 4세대에서 공개된 botmaker-rules/의 어느 규칙과 정확히 매핑되는지는 미공개(rule id → 규칙 파일 매핑 문서 부재). canon의 심층 분석 필요 목록에 이 매핑이 추가된다.

새로 알게 된 것 — 성인 컨텐츠 판정 cross-validation (Grok 4.5 심판)

새 파일 task_safety_ptos_adult_content_cross_validation.py (162줄 신규) [확인]grox/flows/ptos/task_safety_ptos_adult_content_cross_validation.py:

핵심 흐름 4단계:

  1. 판정 비교 — 새 enum CompareOutcomeBOTH_POSITIVE·BOTH_NEGATIVE·SAFEMODEL_ONLY_POSITIVE·PTOS_ONLY_POSITIVE 4가지를 구분. is_disagreement는 SAFEMODEL_ONLY 또는 PTOS_ONLY일 때 true. 이 로직은 4세대의 safemodel_sex_nudity.py 안에 있었는데, 오늘 커밋이 그 로직을 뽑아 새 파일로 이동했다.
  2. 게이트 — (a) is_deluxe = ctx.payload.task_type == SAFETY_PTOS_DELUXE(즉 deluxe 플로우에서만 동작 — 일반 플로우는 그대로 로그만) (b) 이미 NSFW로 플래그된 포스트면 스킵(_post_is_already_flagged_nsfwStratoSafetyPostAnnotationsResultDirectMh 조회).
  3. Grok 4.5 심판 호출 — 새 클래스 SafetyPtosAdultContentCrossValidationJudgeModelName.EAPI_GROK_4_5_X_ALGO 모델을 통해 (_EAPI_4_5_X_ALGO_BREAKER_CONFIG는 실패율 50%·600초 창·회복 600초·half-open 5회의 별도 서킷브레이커) adult_content_policy_prompt()를 system 메시지로, PostRenderer.render(post, include_reply_to=True) + UserRenderer.render(post.user)를 user 메시지로 넣고 <json>...</json> 응답을 파싱해 SafetyPolicy 오브젝트를 얻는다.
  4. 재판단 적용 — 심판이 AdultContentSexualHard이면 원래 판정 유지. 그 외(즉 심판이 "hard가 아니다"라고 하면)면 (a) 모든 AdultContent 위반의 safetyPolicy.policyTypeAdultContentSexualSoft로 강등 (b) 강등된 위반의 reason = "Grok 4.5 Cross Validation disagreed"로 표기 (c) safemodel_sex_nudity.positive를 false로 클리어. 즉 원래 이유가 무엇이었든 최종 감사 로그에 "Grok 4.5 심판이 반대해서 강등됨"이 명시적 텍스트로 기록된다.

연결된 safemodel 변경 — 같은 커밋에서 task_safety_ptos_safemodel_sex_nudity.py도 정리됐다 [확인]grox/flows/ptos/task_safety_ptos_safemodel_sex_nudity.py:

  • _compare_outcome·비교 로그·CompareOutcome enum 정의를 제거 (cross_validation 파일로 이동)
  • deluxe 플로우에서 이미 NSFW 플래그된 포스트면 판정 자체를 스킵하는 사전 게이트 추가
  • 판정 종료 시점에 safemodel_sex_nudity.scored = True를 명시적으로 셋 (cross_validation이 이 플래그로 실행 여부를 판단)

즉 두 파일은 상호 의존한다: safemodel이 먼저 돌면서 scored=True를 남기면, cross_validation이 그 플래그를 보고 실행해 판정 결과를 비교하고 필요시 Grok 4.5로 재판단.

Grok 4.5 심판의 프롬프트 세부 [확인]grox/flows/ptos/classifier.py:597-608:

convo.messages.append(Message(
    role=Role.SYSTEM,
    content=[_strip_thinking_restrictions(adult_content_policy_prompt())],
))
user_msg = Message(role=Role.USER, content=[])
user_msg.content.extend(UserRenderer.render(post.user))
user_msg.content.extend(PostRenderer.render(post, include_reply_to=True))
user_msg.content.append(
    f"\n\nAnalyze the post {post.id} for the specific safety policy violation category: {SafetyPolicyCategory.AdultContent.value}"
)
user_msg.content.append(
    f"\n\nProvide the requested JSON object for the specific safety policy type.{THINKING_CONTROL_START}"
)

세 관찰:

  • _strip_thinking_restrictions()가 시스템 프롬프트를 감싼다 — 즉 원 프롬프트가 "이런 답변은 사고 과정을 노출하지 마라" 유의 제약을 담고 있는데, 심판 컨텍스트에서는 그 제약을 벗겨서 사고 과정을 볼 수 있게 함
  • include_reply_to=True — 답글이면 부모 포스트도 컨텍스트로 넣는다 (답글의 "이건 그 포스트에 대한 반응이다"라는 맥락이 성인 컨텐츠 판정에 영향을 준다는 것)
  • 응답 파싱은 re.compile(r"(.*)<json>(.*)</json>", re.DOTALL) — 즉 응답이 자유 텍스트 + <json>...</json> 태그 안 JSON으로 나오는 형식. 심판이 사고 과정을 자유 텍스트로 남기고 최종 판정만 JSON으로 반환하는 관행

의미 (판정 계층의 확장 방향)

canon이 지금까지 "판정은 단일 (safemodel 또는 PtOS 또는 Grok) → visibility rules → 필터/광고 인접성" 구조로 반영해 왔는데, 오늘 관찰은 판정 자체를 다중 모델 앙상블로 재구성하는 방향을 보여준다. 세 층이 서로 다른 모델(safemodel = 자체 비전 모델, PtOS = 정책 판정 모델, Grok 4.5 = LLM 심판)로 구성되고, disagreement를 이용해 최종 판정을 자동 조정한다는 점이 특징 — 4세대의 "labeling 파이프라인의 완전 공개" 방향과 결이 통한다. 관전 포인트: 이 심판 계층이 다른 카테고리(폭력·혐오·스팸)에도 확장되는지, 그리고 그것이 Grok 4.5 사용 비용(추론 코스트)을 어느 정도까지 소화할 수 있는지.

특히 판정이 강등되는 방향(hard → soft)만 있고 격상 방향은 없다는 것도 중요한 관찰. 즉 이 심판 계층은 과다 게이팅을 완화하는 방향으로만 작동하도록 설계됐다. 원래 판정이 놓친 hard 케이스를 심판이 잡아 격상하는 로직은 이 커밋에 없다 — 이는 성인 컨텐츠 게이팅의 정책적 방향(false positive를 줄이려는 것이지 false negative를 줄이려는 것이 아니라는)을 코드에서 관찰 가능하게 만든다.

새로 알게 된 것 — Phoenix retrieval 인덱싱 게이트 제거

phoenixRankAllCandidateProcessor.strato의 두 함수 diff [확인]phoenix-rankall-strato/columns/phoenix_rank_all/phoenixRankAllCandidateProcessor.strato:

변경 전:

def build1FavIndex(candidate: PhoenixRankAllCandidate, stats: Stats.StatsReceiver): Unit = {
  candidate.engagementCount match {
    case Some(ec) =>
      if(ec.favoriteCount.getOrElse(0) >= 1) {
        val object = { postId = candidate.postId, authorId = candidate.authorId, indexName = "1fav" }
        #<hydra/kafka/indexingEventKafkaTopic>.insert((), object)
        stats.counter("1fav_indexing_event_created").incr(1)
      }
    case None => ()
  }
}

변경 후:

def build1FavIndex(candidate: PhoenixRankAllCandidate, stats: Stats.StatsReceiver): Unit = {
  if (candidate.engagementCount.flatMap { ec => ec.favoriteCount }.getOrElse(0) == 0) {
    stats.counter("1fav_uec_count_race").incr(1)
  }
  val object = { postId = candidate.postId, authorId = candidate.authorId, indexName = "1fav" }
  #<hydra/kafka/indexingEventKafkaTopic>.insert((), object)
  stats.counter("1fav_indexing_event_created").incr(1)
}

즉 (a) fav 카운트에 상관없이 매번 인덱싱 이벤트를 발행 (b) fav가 0인 경우만 1fav_uec_count_race 카운터로 계측. 카운터 이름의 "race"는 uec(user engagement counts) 저장소와 후보 도착 시점이 어긋나서 fav가 아직 반영 안 됐을 가능성을 시사한다는 의미로 보인다 [추정].

같은 함수 안에 있던 buildMMEmbMetadataDump(멀티모달 임베딩 v3·v5_1·v6_dev 세 버전을 조회해 Kafka로 덤프)도 똑같이 favoriteCount >= 1 게이트를 제거해 이제 모든 후보에 대해 실행된다 [확인]:

  • 변경 전: if(ec.favoriteCount.getOrElse(0) >= 1) { ... 멀티모달 임베딩 fetch + Kafka 덤프 ... }
  • 변경 후: 게이트 제거, 모든 후보에 대해 멀티모달 임베딩 3버전 조회 + Kafka 덤프

의미 (retrieval 인덱스 커버리지 확대)

canon이 3세대~4세대에서 관찰해온 "phoenix-rankall이 인기 신호로 인덱스를 갱신한다"는 이해가 이제 정확하지 않다. 오늘 이후로 "1fav" 인덱스 이름은 backward compat용 라벨일 뿐이고, 실제 인덱스는 유입 후보 전체를 담는다. 이는 canon 함정 목록에 "인덱스 이름이 필터 조건을 의미하지 않는다"를 추가할 만한 근거.

멀티모달 임베딩 덤프 게이트 제거는 특히 흥미로운데, v3·v5_1·v6_dev 세 임베딩을 인기 없는 포스트에도 전부 조회해 Kafka로 덤프한다는 것은 retrieval 시그널을 위한 인벤토리 준비 코스트를 크게 늘리는 방향이다. 이는 canon의 "인기도가 있어야 후보로 진입 가능" 서술과 반대 방향 — Phoenix retrieval이 롱테일 포스트에도 임베딩 기반 매칭을 시도할 수 있게 하는 인프라 확장 [추정].

관전 포인트: (a) 1fav_uec_count_race 카운터의 실 관측치가 어느 정도 비율로 나오는지 (b) 인덱스 커버리지 확대가 어떤 param 게이트(예: Phoenix retrieval의 top-k, SID window)와 짝지어 활성화되는지가 향후 커밋에서 드러날 지표.

정본 반영 services/x.md — 4개 절 갱신:

  • "한 줄 요약" 절: 4세대+2 후속 드랍(brand safety V2 + Grok 4.5 cross validation + 인덱싱 게이트 제거) 요약 추가
  • "공개 소스 4세대" 세대 테이블: 4세대+2 행 신설 (커밋 b089ce6, +751/−162, 파일 34개)
  • "광고" 절: brand safety V2 라벨 세트(medium 16 + low 3), strip_v1_grok_written 마이그레이션 헬퍼, v2_mirrors_v1_across_tier_matrix 테스트 추가
  • "Grox → PtOS Adult Content Cross-Validation (4세대+2 신규)" 새 절 신설 — 4단계 흐름, 심판 프롬프트 세부, 강등 방향 특징
  • "Phoenix 학습·인덱스" 절: phoenix-rankall-strato 인덱싱 게이트 제거 관찰 추가 (1fav_uec_count_race 카운터 신설, 멀티모달 임베딩 덤프 게이트 제거)
  • 열린 질문: "4세대+2 드랍으로 해소된 것 (2026-08-19)" 하위절 신설, PROMPT_OWNED_RULES botmaker rule 매핑을 심층 분석 필요에 추가
  • 출처: 4건 추가 (b089ce6 커밋, brand_safety.rs, adult_content_cross_validation.py, phoenixRankAllCandidateProcessor.strato)

의미 (릴리즈 리듬과 계층별 정교화 방향)

4세대(2026-08-13) → 4세대+1(2026-08-14) → 4세대+2(2026-08-17)의 사흘 간격 세 번째 드랍으로 X의 릴리즈 리듬이 확립된 것으로 보인다. 각 드랍의 성격이 다르다는 것이 특히 중요:

  • 4세대: 파라미터·labeling 파이프라인 통째 공개 (구조적 대형 드랍)
  • 4세대+1: 가중치 해석·규제 대응·A/B 배선·모델 입력 확장 (다섯 방향 확장)
  • 4세대+2: 광고 브랜드 안전 V2 마이그레이션 + Grok 4.5 심판 계층 + retrieval 인덱스 게이트 제거 (판정 계층 정교화)

canon이 이 흐름에서 얻을 수 있는 것은 두 가지 — (a) X 커밋 로그를 매일 추적하는 것의 가치가 계속 늘어난다 (매 커밋이 다른 축을 건드림) (b) X의 open-source 관행이 특정 방향(규제 대응·안전 판정 계층·retrieval 커버리지)으로 이동하는 초기 신호가 세 드랍에 걸쳐 축적되는 중.

심층 분석 필요 항목 (오늘 처리하지 않음):

  • V1 → V2 라벨 마이그레이션이 완료되는 시점 (V1 함수 삭제 커밋이 나오는지, 아니면 영구 dual-write 유지인지)
  • PROMPT_OWNED_RULES botmaker rule id 7개(1400/1410/1420/1500/1510/1610/1700)와 botmaker-rules/ 실 규칙 파일의 매핑
  • Grok 4.5 심판 계층이 다른 카테고리(폭력·혐오·스팸)로 확장되는지
  • 1fav_uec_count_race 카운터의 실 관측 비율(외부에서 관측 불가능하나 후속 커밋의 임계 조정으로 간접 관찰 가능)
  • 멀티모달 임베딩 v3/v5_1/v6_dev 세 버전의 소비자 (홈 랭킹이 아니라는 것은 canon에 이미 반영, 어디로 가는지 미확인)

2. arXiv triage — SDF (Google Discover의 2년 프로덕션 staleness 필터)

배경

Google Discover는 Android 홈스크린과 Google 앱의 개인화 피드 지면으로, DAU 수억 명·MAU 수십억 명 규모 [확인] (논문 abstract). canon이 지금까지 Google Discover를 추적 서비스로 등록하지 않았는데, 그 이유는 Google이 Discover의 알고리즘·랭킹·retrieval 계층을 통째로 공개한 적이 없어서였다. 이 논문은 그 지면의 staleness 필터만 다루지만 (전면 아키텍처 공개가 아니라 단일 컴포넌트), 프로덕션 배포 2년 + 유저 피드백 지표 54.9% 개선이라는 실제 A/B 결과 진술이 있어 레이더 수용 기준(플랫폼 기업 저자 + 프로덕션 배포 + 대규모 스케일)을 넘는다.

논문의 문제 정의는 콘텐츠 피드에서 "이 후보가 낡았다"를 정하는 두 가지 서로 다른 메커니즘을 분리하고 각각을 독립 모델로 예측한다는 것이다:

  • Supersession (초월/대체) — 새 아이템이 도착해서 이전 아이템의 정보 가치가 무효화되는 경우. 예: 스포츠 선수의 팀 이적 소식이 발표되면 그 이전의 이적 협상 기사들이 자동으로 낡는다. 시간 자체가 아니라 후속 아이템의 존재 여부가 판정 근거.
  • Relevance decay (관련성 감쇠) — 후속 아이템이 없어도 아이템 자체의 정보 가치가 시간에 따라 자연히 줄어드는 경우. 예: "오늘 밤 유성우" 안내는 그날 저녁에는 유용하지만 다음날부터 쓸모 없다. 시간 곡선이 판정 근거.

기존의 관행(age cutoff, engagement heuristic)은 이 두 메커니즘을 구분하지 못해서 (a) age cutoff는 관련성 감쇠를 크게 과대·과소 추정하고 (b) engagement heuristic은 lagging signal이라 낡은 컨텐츠가 이미 노출된 뒤에야 반응한다.

새로 알게 된 것 — 아키텍처와 프로덕션 결과

SDF의 두 필터 [확인]arXiv 2608.15780v1, 3절 Methodology:

  1. Relational Staleness Filter (supersession) — pairwise classification framework. 후보 아이템 d_t와 그 이후 도착한 topic-related 아이템 d'의 쌍에 대해 학습된 함수 f(d_t, d')가 "d'가 d_t를 낡게 만드는가"를 이진 판정. 판정 결과의 disjunction (∃ d' > t: f(d_t, d') = 1)이 supersession indicator. 훈련 데이터는 LLM 파이프라인으로 합성 생성(수동 어노테이션이 규모상 불가능) → 지식 증류(knowledge distillation)로 학생 모델을 서빙에 배포.
  2. Predicted Traffic Ratio (PTR) Filter (relevance decay) — 아이템의 멀티모달 콘텐츠(텍스트·이미지·비디오)를 입력으로 받아 미래 여러 horizon에서의 traffic ratio(정규화된 방문 트래픽)를 예측하는 multi-horizon 회귀 모델. 학습 라벨은 아이템의 lifetime visit traffic(수명 전체 방문). 서빙 시점의 traffic ratio가 임계 미만이면 decay indicator = 1.
  3. Composition — 두 필터를 disjunction(OR)으로 결합해 upstream(ranking 이전 후보 프루닝 단계)에 배치. 즉 supersession OR decay 중 하나라도 판정되면 후보에서 제거. Ranking으로 오는 후보 수를 줄여서 downstream serving cost도 감소.

A/B 결과 [확인] — 4.2절 Online A/B Testing:

  • 2년 프로덕션 배포 (initial → 확장 → 안정화) 후 user-filed staleness reports 54.9% 감소 (in-product user feedback 기준, pre-deployment baseline 대비)
    • supersession filter 단독 기여: 64.0% 감소
    • decay filter 단독 기여: 34.4% 감소
  • Engagement neutral 제약 하에서 튜닝 — "trivially aggressive cuts would reduce staleness further but shrink candidate set and degrade user engagement, which we explicitly rule out." 즉 인위적으로 aggressive하게 자르면 지표가 더 좋아지지만 그건 engagement를 떨어뜨리기 때문에 배제.
  • 각 필터 개별로 statistically significant negative "engagement lift"(즉 후보 프루닝에도 불구하고 engagement 개선)를 낸다는 진술이 있으나 구체 %는 abstract에 없음
  • Online staleness는 A/B arm의 통제군·처리군에서 매주 샘플링해 4주 연속 관찰 (view delta 크기로 가중치)

의미 (canon 관점)

이 논문은 canon의 세 방향에 영향을 줄 가능성이 있다:

  1. X의 stale post 처리와 비교 축. 4세대+1에서 관찰한 X의 IS_STALE_POST14D bool feature(daily/2026-08-16.md)는 "14일 지나면 engagement count를 0으로 stamp + bool 셋"이라는 규칙 기반 처리다. 반면 SDF는 (a) supersession을 학습 모델로 예측 (b) decay를 lifetime traffic 회귀로 예측하는 완전 학습 기반 접근. 두 접근은 canon 관점에서 staleness의 두 서로 다른 정의를 반영 — X는 "노출 감소가 count zero로 이어지는 자기강화 루프의 완화"(랭커에게 명시 라벨), Google Discover는 "candidate pool에서 아예 제거"(retrieval 이전 프루닝). 두 위치가 근본적으로 다르다.
  2. Feed 지면의 staleness가 topic으로 승격할 후보. 현재 canon의 topic 목록에는 staleness가 없다. Netflix Foundation Model이나 Meta ConnectionMind가 stale item 처리를 어떻게 다루는지 미확인. 두 번째 회사의 유사 진술이 나오면 topics/에 절 신설 후보.
  3. Google Discover를 추적 서비스로 등록할 것인가? 현재는 no. 이 논문은 단일 컴포넌트(staleness 필터)만 공개했고 retrieval·ranking·다양성 등 나머지 알고리즘 스택은 여전히 미공개. 그 상태에서 정본 파일을 만드는 것은 canon의 "서비스 정본은 압축된 결론" 원칙과 맞지 않는다. 레이더에 두고 두 번째 컴포넌트 공개가 나오면 재검토.

정본 반영 radar.md — "이번 달 신규" 절에 SDF (Google Discover — 2년 프로덕션 staleness 필터, supersession + decay 이중 학습) 항목 신설. 상태는 "관찰".

다음에 볼 것

  • X 4세대+3 후속 — 사흘 간격 릴리즈 리듬(8-13 → 8-14 → 8-17)이 유지되면 다음 커밋 후보군은 (a) 브라질 필터의 계정 리스트 갱신 diff (b) V1 → V2 라벨 마이그레이션의 다음 단계 (V1 함수 제거 또는 다른 라벨 세트 추가) (c) Grok 4.5 심판 계층의 다른 카테고리 확장 (d) phoenix-rankall의 인덱스 커버리지 확대에 짝지어질 param 게이트
  • SDF 후속 진술 관찰 — Google Discover가 다른 컴포넌트(retrieval, ranking, 다양성)를 CIKM/WWW 2027 사이클에 공개하는지 여부. Discover가 추적 서비스로 승격할 판단 근거는 두 번째 컴포넌트 공개 이후.
  • Kuaishou/Alibaba/ByteDance 라인 지속 관찰 — 이번 달 지속적으로 프로덕션 논문이 나오는 세 회사. 8월 나머지 arXiv triage에서 계속 통과분 관찰.