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>
This commit is contained in:
2026-04-24 12:55:26 +02:00
parent fe6f028127
commit e8c9d4ed29
6 changed files with 257 additions and 28 deletions

View File

@@ -226,7 +226,13 @@ impl<T: Time> TimeSlice<T> {
let teams = event.within_priors(false, false, &self.skills, agents);
let result = event.outputs();
let g = Game::new(teams, &result, &event.weights, self.p_draw, &mut self.arena);
let g = Game::ranked_with_arena(
teams,
&result,
&event.weights,
self.p_draw,
&mut self.arena,
);
for (t, team) in event.teams.iter_mut().enumerate() {
for (i, item) in team.items.iter_mut().enumerate() {
@@ -315,7 +321,7 @@ impl<T: Time> TimeSlice<T> {
self.events
.iter()
.map(|event| {
Game::new(
Game::ranked_with_arena(
event.within_priors(online, forward, &self.skills, agents),
&event.outputs(),
&event.weights,
@@ -341,7 +347,7 @@ impl<T: Time> TimeSlice<T> {
.any(|item| targets.contains(&item.agent))
})
.map(|(_, event)| {
Game::new(
Game::ranked_with_arena(
event.within_priors(online, forward, &self.skills, agents),
&event.outputs(),
&event.weights,