Matchmaker

The /matchmaker/ route is intentionally simple: choose a completed UFC card and read the most plausible next opponents for each fighter. Visitors do not build or manage a fantasy booking board. The complexity belongs in the data and recommendation engine, not in the interface.

Run and verify

Run node scripts/matchmaker/update-matchmaker.mjs to refresh source data, then node scripts/matchmaker/check-matchmaker.mjs for deterministic-engine regressions and real-card checks. The Update Matchmaker data workflow runs twice daily, supports manual dispatch, and also runs when Matchmaker engine/source code changes. Collection is atomic: validation failure leaves the previous good dataset published.

assets/matchmaker-engine.js is the deterministic recommendation engine. scripts/matchmaker/sources/ufc.mjs handles UFC event results, rankings and athlete-profile context. scripts/matchmaker/sources/ufcstats.mjs supplies structured prior-opponent history for rematch detection. The site’s canonical UFC roster, upcoming schedule and portrait registry are reused. Visitors never trigger source scraping; the browser only reads normalized published JSON.

The refresh workflow also runs recommendation-level validation. When official rankings change, scripts/matchmaker/reconcile-ranking-changes.mjs reruns the public shortlist against the previous and current ranking states while holding the refreshed roster, results, bookings and fight history constant. The resulting ranking-reconciliation.json records which recommendations changed specifically because of the ranking update. scripts/matchmaker/audit-recommendations.mjs audits the current engine and the actual public shortlist separately, including reciprocal-fit asymmetry and generic fallback usage. scripts/matchmaker/build-historical-universe.mjs builds an offline UFCStats-backed candidate universe that includes historical fighters absent from today’s public Matchmaker roster. scripts/matchmaker/backtest-recommendations-v4.mjs reconstructs pre-fight states and compares the engine’s recommendations with the fighter’s eventual next UFC opponent; scripts/matchmaker/refine-backtest-classifications.mjs separates future weight-class moves from genuine data-coverage failures. The backtest is diagnostic calibration evidence, not an instruction to imitate every UFC booking.

Engine principles

The engine separates hard facts from matchmaking judgment.

Hard eligibility facts are checked before scoring: active-roster status, announced bookings, division, prior UFC meetings and basic competitive-range constraints. A pair that fails a hard rule is not allowed into the recommendation ranking just because its score would otherwise be high.

Prior meetings receive special treatment because a false first-meeting claim is unacceptable. UFC.com athlete biography/history text remains useful for recent form and record context, but it is not treated as authoritative proof that two fighters have never met. Displayed event participants are cross-checked against structured UFCStats fighter histories. A verified prior meeting blocks an ordinary fresh-matchup recommendation unless the engine can establish a documented rematch case. When structured history coverage is unavailable, the engine labels the history as incomplete and reduces freshness confidence rather than claiming a first meeting.

The known Jean Silva / Diego Lopes fight on September 13, 2025 is a permanent regression case: the test suite must detect that meeting and reject Lopes as a normal fresh recommendation for Silva.

Recommendation model

After hard eligibility checks, eligible opponents are ranked by a deterministic fit model using division hierarchy, trajectory, availability, freshness, progression, timing and limited story context. The score describes how defensible a booking is; it is not a fight-win probability.

The public page intentionally exposes only the useful result: up to three plausible opponents with concise factual context. Internal score components and source evidence remain available to tests and the engine without turning the page into an operator dashboard.

The public shortlist compares a small pool of the engine’s strongest candidates before choosing the final three. When two matchups are already close, reciprocal booking fit can act as a modest ordering nudge: a matchup that also ranks highly in the proposed opponent’s own queue can move ahead of a slightly stronger but one-sided option. Reciprocal fit is not a hard eligibility rule and cannot override a clearly stronger matchup, title-claim rules, prior-meeting rules, bookings or other hard constraints.

A generic divisional-sorting fallback may still exist inside the engine as a diagnostic signal that no stronger matchmaking thesis was found, but it is not public-eligible. Every matchup shown to visitors must have a specific engine case such as hierarchy progression, rebound pairing, prospect progression, contender positioning or a supported rematch/title case.

Rematches are conservative. A previous meeting normally excludes the matchup. Exceptions require an explicit supported case such as a draw/no contest, a qualifying 1–1 series with subsequent wins, or a sufficiently old matchup where both fighters have rebuilt with multiple wins. The presentation layer does not let visitors override these facts.

Temporal backtesting

Historical validation must not leak present-day information backward. The backtest truncates each fighter’s history and verified meeting ledger at the case cutoff date, reconstructs the record from only those bouts, removes current champion-state flags, and infers division only from source-native fight weight classes known at the cutoff.

The backtest candidate universe is broader than the live public dataset. The refresh builds assets/data/matchmaker/historical-universe.json from the UFCStats fighter directory and verified UFC/TUF/Road-to-UFC fight ledger. Fighters that still exist in the public Matchmaker data retain their canonical IDs; historical-only fighters use stable source-native UFCStats identities. This historical universe is loaded only by offline validation and is not exposed as additional live Matchmaker candidates.

Dated ranking snapshots under assets/data/matchmaker/rankings/ are part of the historical state. For each case, the backtest uses only the newest snapshot whose capture is on or before the cutoff and is no more than 14 days old. If no qualifying snapshot exists, that case is deliberately evaluated unranked rather than applying today’s rankings to an older booking. The report separates snapshot-backed cases from unranked cases so the historical score becomes more representative automatically as the archive grows.

The refresh workflow also creates an immutable daily roster-and-booking snapshot under assets/data/matchmaker/state/. A backtest case may use one only when it was captured on or before the cutoff and is no more than seven days old. When no qualifying state snapshot exists, historical active status falls back to pre-cutoff UFC fight recency rather than today’s active-roster flag.

Historical booking state is reconstructed conservatively. Matchmaker’s cumulative explicit-pairing ledger preserves each booking’s earliest firstSeen timestamp. A booking is restored only when firstSeen is at or before the historical cutoff and the booked fight occurs after that cutoff; a qualifying daily state snapshot can also supply a booking known at that time. Cases where the subject was already booked are excluded from recommendation hit-rate denominators. If that booking was the fighter’s eventual next opponent, it is classified as already-known information rather than credited as a prediction hit.

Every sampled historical case receives an explicit diagnostic classification. Cases that cannot fairly test the engine are separated from scoring: an eventual opponent with no pre-cutoff UFC history is a future-newcomer-booking; an eventual bout that requires the subject or opponent to make a future weight-class move is a future division-change case; known booking conflicts and unresolved source coverage are also excluded. Future fight information is used only after candidate scoring to classify the case and never to alter the recommendation ranking.

The clean evaluation set therefore contains only cases where the subject and actual opponent can both be reconstructed in the same historical division, the opponent was available under known-at-the-time evidence, and the engine’s hard eligibility rules allow the matchup. Those cases are then separated into Top-3 hits, near ranking misses, deep ranking misses and candidate omissions. Hard-rule disagreements remain a separate review bucket because an actual UFC booking may expose an engine rule that is too strict, or it may simply be a short-notice, promotional or otherwise unusual UFC booking.

Data quality and failure behavior

The goal is a low-friction page backed by a comparatively strict engine: the visitor should be able to glance at the recommendations, while the collector and tests do the work required to make those recommendations defensible.