perf: stop cloning inference inputs in OwnedGame and ingestion

The last two items on #23.

`OwnedGame::new` and `new_scored` cloned the whole team structure to hand one
copy to `Game` and keep another. But `Game` takes the teams by value and is
dropped at the end of the constructor, so the vec can simply be taken back out
of it — the clone existed only because nobody looked at the lifetime.

`add_events_with_prior` deep-cloned each event's composition, results and
weights when chunking events into per-timestamp groups. Nothing reads those
three after the chunking loop (the agent-collection pass and the tie pre-check
both run before it), so the elements are now moved out with `mem::take`.

That soundness argument rests entirely on `o` being a permutation: visiting an
index twice would take an already-emptied vec and silently produce an event
with no teams rather than failing. Since that would be invisible, there is now
a debug_assert checking the permutation property directly, next to the comment
explaining why the code depends on it.

Verified on 1.85.0 as well as the local toolchain — an MSRV break in this
change would otherwise only surface in CI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T5SYDExxL4vZgvunrcNSMc
This commit is contained in:
2026-08-27 17:50:39 +02:00
co-authored by Claude Opus 5
parent aff3fb948d
commit 4e043364fd
2 changed files with 38 additions and 21 deletions
+10 -11
View File
@@ -107,16 +107,13 @@ impl<T: Time, D: Drift<T>> OwnedGame<T, D> {
convergence: crate::ConvergenceOptions,
) -> Self {
let mut arena = ScratchArena::new();
let g = Game::ranked_with_arena(
teams.clone(),
&result,
&weights,
p_draw,
convergence,
&mut arena,
);
// `Game` takes the teams by value and is dropped here, so take the vec
// back out of it rather than handing it a clone.
let g = Game::ranked_with_arena(teams, &result, &weights, p_draw, convergence, &mut arena);
Self {
teams,
teams: g.teams,
likelihoods: g.likelihoods,
log_evidence: g.log_evidence,
}
@@ -130,16 +127,18 @@ impl<T: Time, D: Drift<T>> OwnedGame<T, D> {
convergence: crate::ConvergenceOptions,
) -> Self {
let mut arena = ScratchArena::new();
let g = Game::scored_with_arena(
teams.clone(),
teams,
&scores,
&weights,
score_sigma,
convergence,
&mut arena,
);
Self {
teams,
teams: g.teams,
likelihoods: g.likelihoods,
log_evidence: g.log_evidence,
}