Commit Graph

3 Commits

Author SHA1 Message Date
e8c9d4ed29 feat(api): add Game::ranked, one_v_one, free_for_all, custom constructors
Public Game API now returns Result<_, InferenceError> on invalid input
(p_draw out of range, outcome rank count mismatches team count).

New types:
- GameOptions { p_draw, convergence } — bundled config
- OwnedGame<T, D> — owned variant of Game that carries its result
  and weights internally (no borrow of History's slices). Returned
  by public constructors to avoid leaking internal borrow lifetimes.

The internal Game::new is renamed Game::ranked_with_arena (pub(crate))
and keeps the borrowing-arena signature for History's hot path. All
in-crate callers updated (21 call sites: 18 in game.rs tests, 2 in
time_slice.rs, 1 in history.rs).

Game::custom is a T2-minimal power-user escape hatch exposing raw
factor + schedule plumbing. Full ergonomics in T4 (#[doc(hidden)]
for now).

Game::log_evidence() accessor added on both Game and OwnedGame (was
previously accessible only through the pub(crate) evidence field).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 12:55:26 +02:00
59e4cb35cc refactor(api): generify Drift, Rating, Competitor, TimeSlice, CompetitorStore, History over T: Time
Drift now takes &T -> &T and is generic over the time axis. Untimed
impls return elapsed=0. ConstantDrift impl covers all T via the Time
trait. An additional variance_for_elapsed(i64) method on the trait
serves callers that work with the pre-cached i64 elapsed count.

Competitor.last_time moves from i64 with MIN sentinel to Option<T>
with None sentinel. receive(&T) computes variance from last_time
dynamically; receive_for_elapsed(i64) uses a pre-cached elapsed count
(needed in convergence sweeps where last_time has already advanced).

TimeSlice.time changes from i64 to T. compute_elapsed is now generic
over T and takes Option<&T> for the last-seen time. new_forward_info
uses receive_for_elapsed to preserve the cached elapsed during sweeps.

History<D> becomes History<T, D>; HistoryBuilder<D> becomes
HistoryBuilder<T, D>; Game<D> becomes Game<T, D>. Defaults keep
existing call sites compiling with zero changes: T = i64,
D = ConstantDrift.

add_events / add_events_with_prior stay on impl History<i64, D> since
times: Vec<i64> is i64-specific (Task 8 will generalise this).

In !self.time mode the old i64::MAX sentinel guaranteed elapsed=1 for
every slice transition regardless of time gaps. Replaced by advancing
all previously-seen agents' last_time to Some(current_slice_time) at
the end of each slice; this preserves elapsed=1 between adjacent
slices in sequential-integer untimed mode.

The time: bool field on History and .time(bool) on HistoryBuilder are
NOT removed by this task — deferred to Task 8 so this commit is
purely a type-level generification.

Part of T2 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 11:50:35 +02:00
5e752f9e98 refactor(api): rename Batch to TimeSlice
TimeSlice says what it is: every event sharing one timestamp. The
History field .batches is renamed to .time_slices. Local variables
named `batch` referring to TimeSlice instances are renamed to
`time_slice`.

Part of T2 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md.
2026-04-24 10:54:31 +02:00