bench,docs: capture T2 final numbers and update CHANGELOG
Batch::iteration: 21.36 µs (T1 was 22.88 µs on same hardware; ~7% improvement attributed to the typed add_events(iter) path being slightly more direct than the nested-Vec path it replaced). Gaussian operations unchanged vs T1. Full test suite: 90 green (68 lib + 10 api_shape + 6 game + 4 record_winner + 2 equivalence). No golden value changed across the entire T2 tier. CHANGELOG documents every breaking rename, every new public type, and the two behavior changes (Untimed drift semantics, Result-based boundary errors). Closes T2 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
84
CHANGELOG.md
84
CHANGELOG.md
@@ -2,6 +2,90 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## Unreleased — T2 new API surface
|
||||||
|
|
||||||
|
Breaking: every renamed type and the new public API land together per
|
||||||
|
`docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md`
|
||||||
|
Section 7 "T2".
|
||||||
|
|
||||||
|
### Breaking renames
|
||||||
|
|
||||||
|
- `Batch` → `TimeSlice`
|
||||||
|
- `Player` → `Rating` (and the `.player` field on `Competitor` is now `.rating`)
|
||||||
|
- `Agent` → `Competitor`
|
||||||
|
- `IndexMap` → `KeyTable`
|
||||||
|
- `History` field `.batches` → `.time_slices`
|
||||||
|
|
||||||
|
### New types
|
||||||
|
|
||||||
|
- `Time` trait with `Untimed` ZST and `i64` impls (generic time axis).
|
||||||
|
- `Drift<T: Time>` — generified from the old `Drift` trait.
|
||||||
|
- `Event<T, K>`, `Team<K>`, `Member<K>` — typed bulk-ingest event shape.
|
||||||
|
- `Outcome` (`#[non_exhaustive]`) — `Ranked(SmallVec<[u32; 4]>)` with convenience
|
||||||
|
constructors `winner`, `draw`, `ranking`. `Scored` lands in T4.
|
||||||
|
- `Observer<T: Time>` trait + `NullObserver` ZST — structured progress callbacks.
|
||||||
|
- `ConvergenceOptions`, `ConvergenceReport` — configuration and post-hoc summary.
|
||||||
|
- `GameOptions`, `OwnedGame<T, D>` — ergonomic Game constructors without lifetime
|
||||||
|
gymnastics.
|
||||||
|
- `factors` module — re-exports `Factor`, `BuiltinFactor`, `VarId`, `VarStore`,
|
||||||
|
`Schedule`, `EpsilonOrMax`, `ScheduleReport`, and the three built-in factor types
|
||||||
|
(`TeamSumFactor`, `RankDiffFactor`, `TruncFactor`) as public API.
|
||||||
|
|
||||||
|
### New `History` API
|
||||||
|
|
||||||
|
- Three-tier ingestion:
|
||||||
|
- Tier 1 (bulk): `add_events<I: IntoIterator<Item = Event<T, K>>>(events) -> Result`
|
||||||
|
- Tier 2 (one-off): `record_winner(&K, &K, T)`, `record_draw(&K, &K, T)`
|
||||||
|
- Tier 3 (fluent): `event(T).team([...]).weights([...]).ranking([...]).commit()`
|
||||||
|
- `converge() -> Result<ConvergenceReport, InferenceError>` — replaces
|
||||||
|
`convergence(iters, eps, verbose)`.
|
||||||
|
- `current_skill(&K)`, `learning_curve(&K)`, `learning_curves()` (now keyed on `K`).
|
||||||
|
- `log_evidence()` zero-arg, `log_evidence_for(&[&K])`.
|
||||||
|
- `predict_quality(&[&[&K]])`, `predict_outcome(&[&[&K]])` (2-team only in T2;
|
||||||
|
N-team deferred to T4).
|
||||||
|
- `intern(&Q)` / `lookup(&Q)` expose the internal `KeyTable<K>` for power users.
|
||||||
|
- `History<T, D, O, K>` is now fully generic with defaults
|
||||||
|
`<i64, ConstantDrift, NullObserver, &'static str>`.
|
||||||
|
|
||||||
|
### New `Game` API
|
||||||
|
|
||||||
|
- `Game::ranked(&[&[Rating]], Outcome, &GameOptions) -> Result<OwnedGame, _>`.
|
||||||
|
- `Game::one_v_one(&Rating, &Rating, Outcome) -> Result<(Gaussian, Gaussian), _>`.
|
||||||
|
- `Game::free_for_all(&[&Rating], Outcome, &GameOptions) -> Result<OwnedGame, _>`.
|
||||||
|
- `Game::custom(...)` minimal escape hatch for user-defined factor graphs
|
||||||
|
(`#[doc(hidden)]` — full ergonomics in T4).
|
||||||
|
- `Game::log_evidence()` and `OwnedGame::log_evidence()` accessors.
|
||||||
|
|
||||||
|
### Errors
|
||||||
|
|
||||||
|
- `InferenceError` now carries `MismatchedShape { kind, expected, got }`,
|
||||||
|
`InvalidProbability { value }`, `ConvergenceFailed { last_step, iterations }`,
|
||||||
|
and `NegativePrecision { pi }`. Shape and bounds validation at the API boundary
|
||||||
|
now returns `Err` rather than panicking.
|
||||||
|
|
||||||
|
### Removed (breaking)
|
||||||
|
|
||||||
|
- `History::convergence(iters, eps, verbose)` — use `converge()`.
|
||||||
|
- `HistoryBuilder::gamma(f64)` — use `.drift(ConstantDrift(g))`.
|
||||||
|
- `HistoryBuilder::time(bool)` and `History.time: bool` — use the `Time` type parameter.
|
||||||
|
- The nested-`Vec<Vec<Vec<_>>>` public `add_events` signature —
|
||||||
|
use typed `add_events(iter)`.
|
||||||
|
- `learning_curves_by_index()` — use `learning_curves()`.
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
|
||||||
|
`Batch::iteration` bench: **21.36 µs** (T1 was 22.88 µs on the same hardware, a
|
||||||
|
~7% improvement from the typed-path being slightly more direct). Gaussian
|
||||||
|
operations unchanged.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- `Time = Untimed` returns `elapsed_to → 0` — **behavior change** from the old
|
||||||
|
`time=false` mode, which implicitly generated `elapsed=1` per event via an
|
||||||
|
`i64::MAX` sentinel in `Agent.last_time`. Tests that relied on the old
|
||||||
|
`time=false` semantics now use `History::<i64, _>` with explicit
|
||||||
|
`1..=n` timestamps.
|
||||||
|
|
||||||
## 0.1.0 - 2026-04-23
|
## 0.1.0 - 2026-04-23
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -65,3 +65,36 @@ Gaussian::pi_tau_combined 234.xx ps (unchanged)
|
|||||||
# - Gaussian operations unchanged vs T0.
|
# - Gaussian operations unchanged vs T0.
|
||||||
# - All 53 tests pass. factor graph infrastructure (VarStore, Factor trait,
|
# - All 53 tests pass. factor graph infrastructure (VarStore, Factor trait,
|
||||||
# BuiltinFactor, TruncFactor, EpsilonOrMax schedule) in place for T2.
|
# BuiltinFactor, TruncFactor, EpsilonOrMax schedule) in place for T2.
|
||||||
|
|
||||||
|
# After T2 (2026-04-24, same hardware)
|
||||||
|
|
||||||
|
Batch::iteration 21.36 µs (1.07× vs T1 22.88 µs — 7% improvement)
|
||||||
|
Gaussian::add 218.97 ps (unchanged)
|
||||||
|
Gaussian::sub 218.58 ps (unchanged)
|
||||||
|
Gaussian::mul 218.59 ps (unchanged)
|
||||||
|
Gaussian::div 218.57 ps (unchanged)
|
||||||
|
Gaussian::pi 264.20 ps (unchanged)
|
||||||
|
Gaussian::tau 260.80 ps (unchanged)
|
||||||
|
|
||||||
|
# Notes:
|
||||||
|
# - API-only tier; hot inference path unchanged. The 7% improvement on
|
||||||
|
# Batch::iteration likely comes from the typed add_events(iter) path
|
||||||
|
# being slightly more direct than the nested-Vec path it replaced
|
||||||
|
# (one less layer of composition construction per event).
|
||||||
|
# - Public surface now matches spec Section 4:
|
||||||
|
# record_winner / record_draw / add_events(iter) / event(t).team().commit()
|
||||||
|
# converge() -> Result<ConvergenceReport, InferenceError>
|
||||||
|
# learning_curve(&K) / learning_curves() / current_skill(&K)
|
||||||
|
# log_evidence() / log_evidence_for(&[&K])
|
||||||
|
# predict_quality / predict_outcome
|
||||||
|
# Game::ranked / one_v_one / free_for_all / custom
|
||||||
|
# factors module (pub Factor/Schedule/VarStore/EpsilonOrMax/BuiltinFactor)
|
||||||
|
# - Breaking type renames: Batch→TimeSlice, Player→Rating, Agent→Competitor,
|
||||||
|
# IndexMap→KeyTable.
|
||||||
|
# - Generic over T: Time (default i64), D: Drift<T>, O: Observer<T>,
|
||||||
|
# K: Eq + Hash + Clone (default &'static str).
|
||||||
|
# - Legacy removed: History::convergence(iters, eps, verbose),
|
||||||
|
# HistoryBuilder::gamma(), HistoryBuilder::time(bool), History::time field,
|
||||||
|
# learning_curves_by_index(), nested-Vec public add_events().
|
||||||
|
# - 90 tests green: 68 lib + 10 api_shape + 6 game + 4 record_winner +
|
||||||
|
# 2 equivalence.
|
||||||
|
|||||||
Reference in New Issue
Block a user