0x00 한

Research / Daily reports

  • Sources read: 2
  • Canon files updated: 2
  • Radar entries: 1
In one lineX added a new final precheck to its enforcement service that blocks re-applying suspensions and labels a human reviewer overturned on appeal. The gate's default mode is Off.

Other changes reviewed today:

  • In the same X commit, the visibility-filtering service VF split the state-management logic out of data lookup and deleted two lookup function files.
  • From the same commit, Cold retrieval candidates of Phoenix (X's Grok-based Transformer model) are shown only to the Treatment arm of the author cold-start experiment.
  • The research-automation paper AgentX-Model reported acquisition +10-15%, ad spend +15-20%, and watch time +0.3-0.8% in five production A/B tests.

1A gate now blocks re-applying suspensions and labels that a human reviewer overturned — X

Source xai-org/x-algorithm@4c5cfe8 — 2026-09-26 commit, +9,130/−2,652, 80 files. These notes number X commits after the Gen4 release in order, and this commit is Gen4+30.

Background The X repository has published a snapshot commit roughly every day since Gen4 (first released 2026-08-13). Yesterday's commit (Gen4+29, bf7db1b) rewrote the hydration layer of VF from a function layer into a data table and a scheduler. Hydration is the stage that merges the data needed for rule verdicts (tweet text, safety label, social graph edges, etc.) from multiple backends. This commit continues that rewrite on two axes.

  • On the abuse-enforcement side, a new precheck layer called the overturn-hold gate was introduced in abuse-enforcement-service (AES below), X's internal enforcement dispatcher.
    • The introduced overturn_hold_gate, 5,270 lines, appears as a single file, overturn_hold.rs.
    • This gate is the last door that, while a hold is valid, stops a suspension or label that a human reviewer overturned while handling an appeal from being applied again.
    • It prevents the recurrence in which an account is suspended, released after the user's appeal is approved, and then suspended again by an automated follow-up verdict.
  • On the VF hydration side, the state-management logic of execute.rs (1,280 lines), introduced yesterday, was split today into a separate file, store.rs.
    • The data table and scheduler that resulted from yesterday's rewrite consisted of plan.rs, execute.rs, and sources.rs.
    • store.rs is a new file of 339 lines.
    • safety_label_hydrator.rs (167 lines) and tes_hydrator.rs (79 lines) were deleted entirely.
    • All the function-based leftovers that remained through yesterday were removed, and the scheduler now references only the data table.

What we learnedA. The overturn-hold gate was introduced as an AES precheck

  • This gate is the last precheck before a suspension or a gated label is dispatched verified. The comment at the top of the file states the purpose in one sentence: it exists so that an enforcement a human reviewer already overturned on appeal is not applied again.

    "Overturn-hold gate: the last precheck before a suspend (or a gated label) is dispatched. It exists so we do not re-apply an enforcement that a human reviewer already overturned on appeal." — abuse-enforcement-service/service-lib/src/overturn_hold.rs

  • The gate runs in three modes, Off, Shadow, and Enforce, and the default is Off verified.

    • The modes are defined as GateMode::Off | Shadow | Enforce.
    • Shadow runs the verdict line but takes no actual action, recording only to metrics and the decision outcome.
    • Enforce actually blocks the dispatch.
  • There are two gate kinds, blocking suspension re-application and blocking label re-application verified.

    • They are GateKind::Suspend and GateKind::Label, respectively.
    • The two kinds correspond to the constants HOLD_KIND_SUSPEND="suspend" and HOLD_KIND_LABEL="label".
  • Suspensions split into temporary and permanent, and a separate verdict flows for each suspension kind verified.

    • A temporary suspension is GatedAction::Suspend and a permanent suspension is GatedAction::PermSuspend.
  • The gate receives the list of active holds from a remote ledger service verified.

    • An HTTP client reaches the ledger service at the /v1/holds/lookup path.
    • The connect timeout is 200ms.
    • The positive cache is 60 seconds and can be tuned up to 3,600 seconds.
    • The response body cap is 64 KiB.
    • The maximum weight of the moka cache is 100,000, and the config publish interval is 15 seconds.
  • The circuit breaker opens after 5 consecutive failures and blocks requests for 10 seconds verified.

    • Retry works by letting one request at a time through as a half-open trial.
    • Separately, when reachable errors (for example, HTTP 5xx) occur 5 times in a row, this is mitigated with a 5-second back-off.
  • The gate is integrated at two points in lib.rs verified.

    • At startup it builds the gate with HoldGate::from_url(cfg.overturn_hold_ledger_url, ..., cfg.overturn_hold_env). Then it injects Arc<overturn_hold::HoldGate> into EnforcementCtx.
    • On the execution path, gated_actions(&specs, &cfg) picks out and returns only the gated actions (Suspend/Label) from the dispatch candidates. The type of the dispatch candidates is Vec<ActionSpec>.
    • strip_held_labels(&mut specs, &gate.strip_labels) removes the already-overturned label names from the spec list.
  • The verdict result is exposed as two status codes verified.

    • STATUS_HOLD_OVERTURNED = "hold_overturned" is the case where a hold is active and the action was actually blocked.
    • STATUS_HOLD_LOOKUP_FAILED = "hold_lookup_failed" is the case where the ledger lookup itself failed.
  • The following diagnostic keys are carried in the same decision outcome dict verified.

    • overturn_hold_id indicates which hold matched.
    • overturn_hold_mode indicates in which mode, off, shadow, or enforce, the verdict was made.
    • overturn_hold_head is the head fingerprint of the ledger response.
    • overturn_hold_expires_at is the hold's expiry time.
    • overturn_hold_labels_stripped is the list of label names the label gate removed.
  • These diagnostic keys also enter the dedup retention layer verified — abuse-enforcement-service/service-lib/src/lib.rs:2469-2501.

    • A dedup retention entry is newly set for each of the two statuses, so the duplicate-action removal pipeline treats the two statuses as separate slices verified — same file.
      • The new entries are dedup_retention_for(STATUS_HOLD_LOOKUP_FAILED) and dedup_retention_for(STATUS_HOLD_OVERTURNED).

What we learnedB. VF hydration split the running state into a separate struct and moved the follows lookup to the wingman service

  • A new struct that holds in-flight results during hydration execution was introduced verified.

    • The struct is Store, introduced by the new file store.rs (339 lines, new).
    • It has the following 8 fields, all held as Option<...>.
      • pure_cores: the minimal skeleton of a tweet
      • tweets: TweetForVisibility
      • controls: ConversationControl arm
      • labels: SafetyLabelMap
      • viewer: ViewerProfile
      • authors: DecodedAuthor
      • edges: socialgraph edge result Vec<(Hydrators, RawHydrationBatch<Hydrators>)>
      • viewer_country: Arc<str>
  • The input keys that downstream hydrators need are extracted by the store along the origin axis verified.

    • The function that does this is Store::keys(origin: KeyOrigin) -> Vec<u64>.
    • Axes such as KeyOrigin::RequestTweets, Viewer, ViewerForCoAllowedList, PureCoreAuthor, PureCoreReplyRoot, and ExclusiveConversationAuthor are defined.
    • In yesterday's plan.rs, the key of NodeSpec { source, part, key, label } was this origin. Now the store resolves the actual value for each origin on the execute path.
  • The edges field is filled only with a subset of the set of hydrators executable in this request verified.

    • Store::callable: Hydrators holds this set as a bitset, locking the edges field so that it is filled only with that subset.
  • The follows relationship lookup moved from direct socialgraph calls to a separate service path called wingman verified.

    • The wingman_client that handles this lookup is the new file clients/wingman_client.rs (54 lines, new).
    const FOLLOWS_GRAPH: u32 = 1;
    const FOLLOWS_FLEET: Fleet<'static> = Fleet {
        wily_path: "/s/wingman/wingman-api-follows",
        authority_template: "wingman.wingman-api-follows.prod.{datacenter}.s2s.twttr.net",
        ...
    };
    

    — visibility-filtering/clients/wingman_client.rs:1-14

  • The wingman client's interface is only batch_exists_intersect(viewer_id, root_author_ids), and the mode is IntersectMode::FwdXRev verified.

    • FwdXRev is the mode that checks the product of the forward viewer → author edge and the reverse author → viewer edge.
    • This mode is used to check in a single RPC call whether "the reply root author and the viewer follow each other".
    • From FOLLOWS_GRAPH being the constant 1, we can guess that wingman holds multiple graphs. Graph 2 and later are not yet in the public code.
  • Two hydrator files whose functions became unnecessary yesterday were deleted entirely in this commit verified.

    • The two files are safety_label_hydrator.rs (167 lines) and tes_hydrator.rs (79 lines).
    • Their functions became unnecessary yesterday when they were moved to the data-based scheduler, but the files remained for a 24-hour grace period.

What we learnedC. The VF rules layer was unified under a Policy struct, and a rules-only metrics module was added

  • The rules registry file was effectively rewritten entirely verified.

    • rules/registry.rs changed by +206/−203.
  • The VF rules layer was unified under a Policy struct verified. The core is the Policy<'a> struct, which holds the rule set of each SafetyLevel.

    pub(super) struct Policy<'a> { base: &'a [RuleClause], additional: &'a [RuleClause] }
    static FILTER_ALL_POLICY: Policy = Policy::new(&[tweet_rules::FILTER_ALL]);
    static TIMELINE_HOME_POLICY: Policy = Policy::new(&TIMELINE_HOME_SHARED_RULES);
    static TIMELINE_HOME_RECOMMENDATIONS_POLICY: Policy = Policy::with_additional(...);
    static TIMELINE_HOME_HYDRATION_POLICY: Policy = Policy::new(&[...]);
    static IMMERSIVE_EXPANDED_RECOMMENDATIONS_POLICY: Policy = Policy::new(&[...]);
    

    — visibility-filtering/rules/registry.rs:28-215

    • RuleEngine::select(level) -> &'static Policy references one of the 5 statics above for each requested SafetyLevel.
    • Policy::with_additional(base, additional) is a tool that builds a derived policy by joining two slices.
  • Because policies became statics locked as data, golden tests can pin the policy specification directly verified.

    • In the previous structure, the rules for each SafetyLevel were assembled inline inside functions.
    • The function used for pinning is wired_rule_names(level), which is actually used in the tests after registry.rs:346.
  • A metrics module dedicated to the rules layer was added verified.

    • The new file is rules/metrics.rs (58 lines, new).
    • Through yesterday, the hydration metrics.rs also held the metrics related to rule verdicts. As verdicts and hydration were separated, the metrics were separated too.
  • Incidentally, filter code shrank verified.

    • filter.rs was trimmed by −94 lines.
    • As the Verdict tree (introduced in Gen4+26, 2026-09-22) settled in, the filter no longer needed to control the rule execution flow directly.

What we learnedD. The targets of Phoenix ads purchase-value prediction were cataloged as 6 combinations of event and point in time

  • The event × level combinations for ads purchase-value prediction were stated explicitly as a data structure verified.

    • The file is phoenix/crates/serving/xai-recsys-proto/src/purchase_value.rs, rewritten with +230/−4.
    pub const ACTION_INDEX: usize = ContinuousActionName::AdsWebCtPurchaseValue as usize;
    pub const MAX_EVENT_USD: f64 = 100_000.0;
    pub fn is_countable_usd(usd: f64) -> bool {
        usd.is_finite() && usd > 0.0 && usd <= MAX_EVENT_USD
    }
    pub enum ValueEvent { Purchase, ContentView, AddToCart }
    pub enum ValueLevel { ClickThrough, ViewThrough }
    pub struct ValueTarget { event: ValueEvent, level: ValueLevel }
    impl ValueTarget {
        pub const ALL: [ValueTarget; 6] = [ ... ];
        pub const PUBLISHED: [ValueTarget; 4] = [ ... ];
        pub const REQUIRED: [ValueTarget; 2] = [Self::PURCHASE_CT, Self::PURCHASE_VT];
    }
    

    — phoenix/crates/serving/xai-recsys-proto/src/purchase_value.rs

  • The ads purchase-value continuous head has 3 events × 2 points in time = 6 targets verified.

    • There are three ValueEvents.
      • Purchase: conversion_type 2, clickhouse storage name purchase
      • ContentView: 19, content_view
      • AddToCart: 12, add_to_cart
    • There are two ValueLevels. ClickThrough is a conversion that occurs after an ad click, and ViewThrough is one that occurs with only an ad impression and no click.
    • REQUIRED is the 2 targets the model must predict: purchase_ct and purchase_vt.
    • PUBLISHED is the 4 webhook targets: purchase_ct, purchase_vt, content_view_ct, and add_to_cart_ct.
    • is_countable_usd excludes an event from training and evaluation if a single event exceeds $100,000 USD. NaN, negative, and infinite values are also excluded.
    • These constants (the 6/4/2 combinations) lock in as data which event × level is trained and which is only extracted and not exposed.
  • The ads purchase-value prediction layer, disclosed piecemeal in the three earlier commits, was unified today into a target catalog verified.

    • Gen4+21 (2026-09-15, ADS_WEB_CT_PURCHASE_VALUE introduced)
    • Gen4+22 (2026-09-16, purchase-value loss formally connected)
    • Gen4+24 (2026-09-18, purchase-value loss narrowed to the early-relabel slice)
  • How the baseline field introduced in Gen4+21 holds the event × level axes is now settled in code verified.

    • That field is the PurchaseValueBaseline request field.
    • ValueTarget::mean(&PurchaseValueBaseline) returns the mean for each of the 6 targets.

What we learnedE. In the author cold-start experiment, Phoenix Cold channel candidates are shown only to the Treatment arm

  • In the author cold-start scorer of home-mixer (the service that receives For You and Following feed requests), the served_type subject to arm-gating was expanded verified.

    • In home-mixer/scorers/author_cold_start.rs, the is_phoenix_moe helper was renamed is_arm_gated_retrieval.
    fn is_arm_gated_retrieval(c: &PostCandidate) -> bool {
        matches!(
            c.served_type,
            Some(
                pb::ServedType::ForYouPhoenixRetrievalMoe | pb::ServedType::ForYouPhoenixRetrievalCold
            )
        )
    }
    

    — home-mixer/scorers/author_cold_start.rs:167-173

  • Starting today, Cold channel candidates are shown only to the Treatment arm among the Holdout/Control/Treatment arms of the cold-start experiment verified.

    • That is, Cold channel candidates follow the same arm-gating rule as MoE retrieval candidates (served_type ForYouPhoenixRetrievalMoe).
    • The new test cold_retrieval_is_gated_like_moe verifies this. In Holdout and Control the Cold candidate score is 0, and in Treatment it remains at 5.0.
    • The Cold channel is the HOME_COLD=13 channel that was introduced in Phoenix retrieval in Gen4+28 (2026-09-24, 44d37eb) together with HOME_HOT=14 verified — retrieval_dataset.py:280-281.
    • This channel had split the 1fav_1day.parquet source with a fav<8 & views<500 mask.

What we learnedOther changes

  • The Phoenix async embedding CUDA layer shrank verified.
    • async_emb_api.cc is +123/−191, and async_emb_comm.cc is +86/−63.
    • The gradient exchange API surface is being tidied in a more data-centric direction.
  • Optimizer and trainer boilerplate shrank verified.
    • trainer_recsys.py is +48/−200, and rowwise_adagrad.py is +51/−120.
  • Two VF hydration files were adjusted slightly verified.
    • They are visibility-filtering/hydration/tes_composite.rs (+29/−32) and hydration/plan.rs (+48/−12).
    • The adjustment to plan corresponds to the addition of wingman.
  • Dispatch was tidied to match the hydration and rules overhaul verified.
    • The changed files are visibility-filtering/server.rs (+35/−21), filter.rs (+26/−120), and evaluate_tweets.rs (+57/−51).

Canon update Introduced a Gen4+30 subsection under the safety section of services/x.md and documented all of the following.

  • The structure and constants of the abuse-enforcement overturn-hold gate
  • The store/execute split in VF hydration and the move to wingman
  • The Policy static form of the rules registry
  • The Phoenix purchase-value target catalog
  • The addition of the Phoenix Cold channel to cold-start

Why it matters Today's real headline is not VF but that abuse-enforcement introduced a human reviewer's overturn as a first-class citizen of the automated prechecks. This introduction suggests two things.

  1. The priority between automated verdicts and human verdicts is locked in as data.
    • Previously, the problem of automated re-verdicts suspending an account again even after an appeal was approved was likely managed through policy and process.
    • Now the code contains a last door that, whenever a suspension spec is created on the automated dispatch path, checks through a hold ledger lookup whether "this action has already been canceled by a human" and gates it.
    • This recurrence prevention became an explicit code path.
  2. The cancellation of a suspension is treated as a "persistent state".
    • A hold is a time window with an expiry time (expires_at). During that window it blocks automated actions against a specific target, and the target is an account or a label.
    • In other words, a human reviewer's approval of an appeal becomes a policy item of "no re-application until time T" rather than a "one-time cancellation".
    • In Gen4+13 (2026-09-01) there was a policy file refactor, and in Gen4+26 (2026-09-22) the binary verdict tree was introduced. Overturn-hold is an enforcement state-management layer placed on top of them.
    • That dedup retention treats the two statuses (hold_overturned, hold_lookup_failed) separately also implies a need for after-the-fact auditing.

The VF overhaul repeats a 24-hour half-life pattern. safety_label_hydrator and tes_hydrator, which were functions through yesterday, were deleted today, and the state logic of execute.rs, introduced yesterday, was split into store.rs today.

2AgentX-Model automated the recommendation model research loop with two agents — arXiv

Source arXiv 2609.30001 — arXiv, 2026-09-24 v1, 37-page technical report. The title is "Advancing Model Research in AgentX: Long-Horizon Autonomy for Industrial Recommender Systems", and it has 23 authors.

Background This paper is not about an algorithm itself such as a new ranker or retrieval, but about a framework that automates the research loop that improves algorithms. The paper starts from the observation that the bottleneck of a production recommendation team lies less in the experiment ideas themselves than in the cycle of designing and running experiments and carrying the results into the next idea. Kuaishou, presumed to be the authors' affiliation, is not a tracked service, but the stated production scale and A/B figures are large, so it qualifies for radar inclusion. AgentX-Model in this paper composes this cycle with two agents.

  • The Research Agent builds independently reviewed proposals from papers and earlier experiment results.
  • The Model Agent turns those proposals into actual code and measurements.
  • The Research Agent also formulates the next question based on the results.

What we learnedA. The author affiliation is presumed to be Kuaishou

  • The author affiliation is presumed to be Kuaishou inferred. The v1 HTML version of the paper does not render affiliations.

What we learnedB. The research loop is split between the Research Agent and the Model Agent and organized into four actions

  • The architecture is a dual-agent structure of a Research Agent and a Model Agent verified. The paper's abstract is reproduced as is.

    "AgentX-Model adopts a dual-agent architecture comprising a Research Agent and a Model Agent. The Research Agent develops independently reviewed proposals from papers and experimental findings, while the Model Agent conducts multi-round investigations and returns code, measurements, and unresolved questions. Using the returned results, the Research Agent selects a starting implementation and formulates the next research question, allowing subsequent experiments to build on earlier findings." — AgentX-Model abstract

    • The research loop is organized into 4 actions.
      • Reproduce: reproduces a prior experiment.
      • Follow-up: extends on top of it.
      • Composition: combines multiple techniques.
      • Diagnose: collects the evidence needed to repair, for example, an issue found in online evaluation or a prediction bias measured by PCOC.
    • The first three actions run routine research, and Diagnose covers diagnosis and repair-candidate selection when a problem is detected.

What we learnedC. In the latest 5 online A/B tests three metrics improved, and the paper states that the watch-time model cut FLOPs by about 10%

  • The paper states the production results in its abstract as follows verified.

    "Across the production evaluation, 560 of 636 completed model-changing experiments recorded AUC above their business baselines. As research continued, some experiments recorded AUC above every comparable ancestor in their lineages. The five latest online A/B evaluations across different business settings reported gains including 10-15% in acquisition efficiency, 15-20% in target-segment advertising spend, and 0.3-0.8% in watch time; the watch-time model used approximately 10% fewer FLOPs and parameters." — AgentX-Model abstract

    • Unpacked, the statement has three parts.
      1. Of the 636 model-changing experiments completed along the way, 560 (88%) had higher offline AUC than the business baseline.
      2. The latest 5 online A/B tests produced acquisition efficiency +10-15%, target-segment ad spend +15-20%, and watch time +0.3-0.8%.
      3. The watch-time model achieved this while cutting FLOPs and parameters by about 10%.
    • The statement that the three business metrics (new user acquisition, ad spend, watch time) improved by +10-15%, +15-20%, and +0.3-0.8%, respectively, is quite large as a performance profile for an automated research framework.

What we learnedD. It also released a benchmark that evaluates research resource allocation

  • The paper also releases a dependency-aware historical-replay benchmark. It evaluates research resource allocation, that is, which experiment to spend the next budget on.
  • The initial result states that "when the agent already analyzes and selects concrete candidates, more complex scheduling does not give a consistent efficiency gain".
    • In other words, the observation is that the quality of candidate judgment, not the scheduler itself, is the bottleneck.

Canon update Added AgentX-Model to the top of "new this month" in radar.md. Kuaishou is not a tracked service of the canon (this repository's canon documents), so no services canon file is created.

Why it matters The research-automation angle is the second case this repository has observed this month. However, the novelty of this source lies on the organizational axis, not on the ranking or retrieval mechanism axis, so it is far from the repository's main interest (the feed pipeline itself). We keep it as a deep dive candidate.

  • The first case was the "37-day human-gated autoresearch campaign that caught the evaluator output-depth 3000/600 defect and recovered offline +3.20 pp" in Meta VDD MBR + EvoPilot (2026-09-22).
  • If Meta's was the angle of automating search retrieval improvement, AgentX-Model (presumed Kuaishou) is the angle of automating the whole recommendation model research loop itself.
  • It attaches as an observation thread because two companies publicly named automated research frameworks explicitly, one after the other, this month.

Radar

What to check next