The MAC and Conference USA tiebreakers are now dated epochs that follow the published procedures. The MAC uses its 2024 order (common opponents, order of finish, opponents' win pct, then SportSource) through 2024, and from 2025 puts SportSource right after common opponents, then order of finish and opponents' combined conference win pct before the draw; the old entry stopped at SportSource and went to a draw (#16). Conference USA keeps its 2024 cascade (CFP clause, composite, APR) through 2024 and from 2025 uses record vs common opponents, a common-opponent descent, the average computer ranking and opponents' combined conference win pct before the coin toss (#17).
The SEC, Big Ten, ACC and Big 12 "record against common opponents in order of finish" tiebreaker now compares only opponents that every tied team played, as those conferences' published policies require ("common conference opponents played by all other teams involved in the tie"). Before, a tier of tied opponents counted once each tied team had played any one team in it. The real 2025 ACC berth now goes to Duke (it went to Georgia Tech) and the real 2025 SEC pairing is Alabama then Georgia (it was Georgia then Ole Miss), matching the actual title games. The Sun Belt's "next highest position" rung is unchanged (#14).
Multi-team tiebreakers now restart from the first rung whenever a rung eliminates a team, instead of continuing down the rung list with the survivors. The Big 12's published policy says "the multiple-team tiebreaker will repeat the tie-breaking procedure" after a team is seeded, and that a tie "reduced to two teams" gets the two-team procedure; the SEC restarts the same way. When a record-vs-common-opponents rung drops a third team and leaves two level, the pair's head-to-head now decides. Previously the cascade kept descending: e.g. a Big 12 field of Utah (clear), BYU, Arizona and Texas Tech dropped Texas Tech on common opponents but then handed the berth to Arizona on its Utah win, even though BYU had beaten Arizona and the two-team procedure gives it to BYU. A rung that keeps every candidate still advances as before.
cfb_simulations() now aborts with a clear error when a team appearing in a
game that still has to be simulated is missing from teams. Previously the
missing team produced an NA rating, rnorm() returned NA, and the NA
propagated through every remaining week - so the run either returned a season
in which no team won a game, or failed much later with an unrelated complaint
that playoff_seeds exceeded the number of teams. The check is deliberately
limited to games awaiting a result: a PLAYED game against an unlisted
opponent remains valid, exactly as it is in cfb_standings(), because
standings only read results while simulation has to generate them. An
unplayed game whose home_team or away_team is NA is rejected the same
way and for the same reason - standings_validate_games() checks that those
columns exist and rejects NA results, but never NA team names.
The test suite now runs on CRAN, reversing the 0.2.0 change that skipped
every test there. All tests are offline against the bundled toy season;
the ones that need gt or scales call skip_if_not_installed().
Examples are no longer wrapped in \donttest{}: they are all offline and
fast, so CRAN's regular example run now exercises them. The
fmt_pct_special() and summary.cfbseedR_simulation() examples run only
when their Suggests packages (scales, gt) are installed, via @examplesIf.
cfbfastR is no longer listed in Suggests. No code, test or example used it;
cfb_games_from_schedule() still accepts its load_cfb_schedules() output.
DESCRIPTION declares Language: en-US, and an inst/WORDLIST was added for
spell checking.
The citation year is pinned to 2026 instead of following the current date.
2026-season rules refresh (researched against official conference and CFP sources, 2026-08-26).
cfb_playoff_seeds() gains a season-keyed autobid policy. The new
default "2026" implements the current CFP automatic-qualifier rule:
the ACC / Big 12 / Big Ten / SEC champions are in regardless of ranking,
the highest-ranked Group-of-6 team is in whether or not it won its
conference, and Notre Dame is in when ranked inside the field.
autobid = "2025" keeps the 2024-2025 rule (5 highest-ranked
champions). cfb_simulations() passes the policy through.sim ids). The ACC's all-new 2026 policy (head-to-head, then
SportSource Team Success Ranking, then a draw, with the
alternate-game-count candidate-pool rule and the postseason-eligibility
filter) applies from 2026; earlier ACC seasons keep the 2024 cascade.cfp_ranked_final_week (fed by
tiebreaker_data$cfp_rankings; the best-ranked tied team advances only
if it won its final conference game) and div_pct (win pct vs
same-division opponents).cfb_simulations() gains tiebreaker_data (external tiebreaker
inputs, held static across simulations) so simulated standings use the
same official rungs as cfb_standings().apr rung (fed by
tiebreaker_data$apr); the CFP auto-bid policy matches both short and
full conference spellings (e.g. "Southeastern Conference").\donttest{}, and the packaging metadata (LICENSE, cph, CITATION,
.Rbuildignore, .gitattributes) was reviewed.teams gains two optional columns: conf_division (division-format
ranking - the two division champions take conf_rank 1-2, as in the
2026 Sun Belt) and postseason_eligible (an ineligible team cannot
occupy a championship-game berth while its games still count).cfb_simulations() gains chunks (default 8):
simulations are split into contiguous blocks and dispatched with
furrr::future_map(), so setting a parallel plan
(future::plan("multisession")) spreads them across cores. Progress is
reported through progressr. A given seed reproduces exactly for a fixed
chunks, and a parallel plan gives bit-identical results to a sequential
one -- but the RNG stream differs from a single unchunked pass, so output
for the same seed changes if you change chunks.summary() for simulations. cfbseedR_simulation objects were classed
but had no methods, so summary() fell back to R's generic list summary.
There is now a summary.cfbseedR_simulation() gt method rendering the
overall table grouped by conference, the counterpart of nflseedR's
summary.nflseedR_simulation().fmt_pct_special() formats probabilities the way simulation summaries
want them: <1% instead of a flat 0%, >99.9% instead of a false
100%. Ported from nflseedR.cfb_games_example and cfb_teams_example
replace the read.csv(system.file(...)) dance in examples, mirroring
nflseedR's sims_games_example / sims_teams_example.verbosity on cfb_simulations(), matching cfb_standings() and
nfl_simulations(); "NONE" silences it completely. The simulation's
tiebreak notes are now attached to the returned standings as well -- they
were previously computed and discarded.ranks = "NONE" on cfb_standings() skips the conference-rank
cascade entirely when you only need records, after nflseedR's ranks
argument.summary() and fmt_pct_special()).Initial release.
cfb_standings() computes overall and conference standings with a
documented generic tiebreaker cascade (win pct, head-to-head, common
opponents, SOV, SOS, point differential, coin flip) gated by
tiebreaker_depth.cfb_playoff_seeds() implements 12-team College Football Playoff
straight seeding (5 highest-ranked conference champions guaranteed).cfb_simulations() simulates seasons week by week with a pluggable
compute_results function and returns a classed cfbseedR_simulation
list with standings, games, and aggregated probabilities.cfbseedR_compute_results() is the default ELO-based results generator,
a faithful adaptation of nflseedR_compute_results().cfb_games_from_schedule() maps cfbfastR::load_cfb_schedules() output
to the engine games schema.simulations_verify_fct() verifies custom compute_results functions.Adapted from nflseedR (MIT) by Sebastian Carl and Lee Sharpe.