docs: correct drifted documentation and compile the README in CI
Four README code blocks no longer compiled: `Player` was renamed `Rating`
in T2, the `Drift` trait gained a `T: Time` parameter and a second method,
and two blocks were missing imports outright. The `Rating` example needed
more than a rename — with the binding unused, `T` is ambiguous because
`ConstantDrift` implements `Drift<T>` for every `T`, so it now carries an
explicit annotation.
Nothing compiled those blocks. `src/lib.rs` gains a `cfg(doctest)` struct
carrying `#[doc = include_str!("../README.md")]`, which turns every `rust`
block into a doctest without displacing the curated crate docs as the
front page. Verified it bites: reintroducing `Player` fails the build with
E0432 rather than shipping. Illustrative blocks are fenced `text` — note
that a bare fence defaults to `rust` under rustdoc, which is how the
`variance_delta = elapsed * γ²` formula became a compile error.
Prose fixes: README claimed `Gaussian::forget` takes a square root (it
works in variance space) and pointed at a `.gamma()` builder method that
does not exist. CLAUDE.md's data-flow diagram spliced the public ingestion
shape into the internal one — `Team` is not in that chain — listed
`cdf()`/`erfc()` as public when they are `pub(crate)` and private, and
called `SkillStore` public when only `CompetitorStore` escapes the crate.
Rustdoc fixes: `EventBuilder::scores_with_sigma` claimed a debug-assert
that `Outcome::scores_with_sigma` never had and whose own docs contradict;
rejection happens at ingestion as `InvalidParameter`. `event.rs` described
`add_events_with_prior` as replaced when it is still the ingestion
chokepoint. `factors.rs` advertised `Game::custom` without noting it is
`#[doc(hidden)]`. Internal T2/T4 milestone labels are dropped from public
items; the ones in the private `time_slice` module are left alone.
Closes #35
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014b6wy2q8rnFK8U8GPJVQNU
This commit is contained in:
+2
-2
@@ -7,8 +7,8 @@ use crate::{
|
||||
|
||||
/// Per-history, temporal state for someone competing.
|
||||
///
|
||||
/// Renamed from `Agent` in T2; the former `.player` field is now
|
||||
/// `.rating` to match the `Player → Rating` rename.
|
||||
/// The mutable half of a competitor: `Rating` holds their static
|
||||
/// configuration, this holds what inference learns as it sweeps.
|
||||
#[derive(Debug)]
|
||||
pub struct Competitor<T: Time = i64, D: Drift<T> = ConstantDrift> {
|
||||
pub rating: Rating<T, D>,
|
||||
|
||||
+5
-3
@@ -1,8 +1,10 @@
|
||||
//! Typed event description for bulk ingestion.
|
||||
//!
|
||||
//! `Event<T, K>` is the new public event shape (spec Section 4). Replaces
|
||||
//! the nested `Vec<Vec<Vec<Index>>>`, `Vec<Vec<f64>>`, `Vec<Vec<Vec<f64>>>`
|
||||
//! that the old `add_events_with_prior` took.
|
||||
//! `Event<T, K>` is the public event shape taken by `History::add_events`. It
|
||||
//! is a typed front end, not a replacement: `add_events` flattens it into the
|
||||
//! nested `Vec<Vec<Vec<Index>>>` / `Vec<Vec<f64>>` / `Vec<Vec<Vec<f64>>>` that
|
||||
//! the internal `add_events_with_prior` chokepoint still takes, and which
|
||||
//! `record_winner` and `record_draw` also route through.
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
||||
@@ -107,7 +107,10 @@ where
|
||||
/// Set explicit per-team continuous scores with a per-event noise override.
|
||||
///
|
||||
/// `sigma` overrides `HistoryBuilder::score_sigma` for this event only.
|
||||
/// Must be `> 0.0`; debug-asserts otherwise via `Outcome::scores_with_sigma`.
|
||||
/// Must be `> 0.0`. Constructing the outcome with a non-positive or NaN
|
||||
/// sigma is allowed; the value is rejected with
|
||||
/// `InferenceError::InvalidParameter` when the event is ingested, so
|
||||
/// callers get an error from `commit` rather than a panic.
|
||||
pub fn scores_with_sigma<I: IntoIterator<Item = f64>>(mut self, scores: I, sigma: f64) -> Self {
|
||||
self.event.outcome = crate::Outcome::scores_with_sigma(scores, sigma);
|
||||
self
|
||||
|
||||
+6
-3
@@ -1,8 +1,11 @@
|
||||
//! Factor-graph public API.
|
||||
//!
|
||||
//! Power users can construct custom factor graphs via `Game::custom` (T2
|
||||
//! minimal; full ergonomics in T4) and drive them with custom `Schedule`
|
||||
//! implementations.
|
||||
//! The factor types, `VarStore` and the `Schedule` trait are public so custom
|
||||
//! schedules can be written against them.
|
||||
//!
|
||||
//! Building a factor graph by hand goes through `Game::custom`, which is
|
||||
//! deliberately `#[doc(hidden)]`: it works, but its signature is not yet
|
||||
//! considered stable API and so is not listed in these docs.
|
||||
|
||||
pub use crate::{
|
||||
factor::{
|
||||
|
||||
+2
-2
@@ -554,13 +554,13 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
|
||||
/// 2-team win probability: returns `[P(team0 wins), P(team1 wins)]`.
|
||||
///
|
||||
/// N-team support lands in T4.
|
||||
/// Only two teams are supported.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `teams.len() != 2`.
|
||||
pub fn predict_outcome(&self, teams: &[&[&K]]) -> Vec<f64> {
|
||||
assert_eq!(teams.len(), 2, "predict_outcome T2: 2 teams only");
|
||||
assert_eq!(teams.len(), 2, "predict_outcome supports exactly 2 teams");
|
||||
let gather = |team: &[&K]| -> Gaussian {
|
||||
team.iter()
|
||||
.filter_map(|k| self.keys.get(*k))
|
||||
|
||||
+13
@@ -86,6 +86,19 @@
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
/// Compiles every `rust` block in `README.md` as a doctest.
|
||||
///
|
||||
/// The README is not the crate's front page — the module docs above are — so it
|
||||
/// is pulled in here rather than via a crate-level `#![doc = ...]`, purely so
|
||||
/// its examples are type-checked. Without this nothing compiled them, and they
|
||||
/// had drifted far enough that four blocks no longer built (#35). `cfg(doctest)`
|
||||
/// means this type exists only while collecting doctests.
|
||||
///
|
||||
/// Blocks that are illustrative rather than runnable are fenced as `text`.
|
||||
#[cfg(doctest)]
|
||||
#[doc = include_str!("../README.md")]
|
||||
pub struct ReadmeDoctests;
|
||||
|
||||
use std::{
|
||||
cmp::Reverse,
|
||||
f64::consts::{FRAC_1_SQRT_2, FRAC_2_SQRT_PI, SQRT_2},
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ use crate::{
|
||||
|
||||
/// Static rating configuration: prior skill, performance noise `beta`, drift.
|
||||
///
|
||||
/// Renamed from `Player` in T2; `Rating` better describes the data
|
||||
/// (a configuration) vs. a person (who's a `Competitor` with state).
|
||||
/// A configuration rather than a person: the per-history temporal state
|
||||
/// (messages, last appearance) lives on `Competitor`.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Rating<T: Time = i64, D: Drift<T> = ConstantDrift> {
|
||||
pub(crate) prior: Gaussian,
|
||||
|
||||
Reference in New Issue
Block a user