docs: complete the public API documentation contract
Closes the last open item in #25. `cargo clippy -W missing_errors_doc -W missing_panics_doc -W must_use_candidate -W doc_markdown` went from 56 warnings to zero. The 13 hand-written sections name the actual variants each function returns rather than gesturing at "an error". Establishing that meant reading the error paths — `Game::ranked` alone returns four distinct variants, and `record_draw` can hit TieWithoutDrawProbability where `record_winner` provably cannot, since a two-team decisive outcome has nothing to tie. Documenting those as interchangeable would have been worse than leaving them undocumented, because a reader would trust it. Two existing doc comments already described panics in prose but not under a `# Panics` heading, so neither rustdoc nor clippy surfaced them: `Outcome::winner` and `EventBuilder::weights`. Both now carry the heading, and `Outcome::winner` gained the note that it ties every loser, so `n >= 3` needs a positive p_draw — the crate's easiest error to hit by accident. The 43 mechanical fixes (31 `#[must_use]` on pure accessors, 11 missing backticks) were applied with `cargo clippy --fix`. `#[must_use]` on Gaussian's arithmetic and on `posteriors()` matters: discarding those results is always a bug, and until now nothing said so. Also documented why `[profile.release] debug = true` exists — cargo-flamegraph needs the symbols, and library profile settings are ignored downstream, so it reads as an oversight without the note. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5SYDExxL4vZgvunrcNSMc
This commit is contained in:
+41
-1
@@ -198,6 +198,7 @@ impl Default for History<i64, ConstantDrift, NullObserver, &'static str> {
|
||||
}
|
||||
|
||||
impl History<i64, ConstantDrift, NullObserver, &'static str> {
|
||||
#[must_use]
|
||||
pub fn builder() -> HistoryBuilder<i64, ConstantDrift, NullObserver, &'static str> {
|
||||
HistoryBuilder::default()
|
||||
}
|
||||
@@ -205,6 +206,7 @@ impl History<i64, ConstantDrift, NullObserver, &'static str> {
|
||||
|
||||
impl<K: Eq + Hash + Clone> History<i64, ConstantDrift, NullObserver, K> {
|
||||
/// Like `builder()` but uses a custom key type `K` instead of the default `&'static str`.
|
||||
#[must_use]
|
||||
pub fn builder_with_key() -> HistoryBuilder<i64, ConstantDrift, NullObserver, K> {
|
||||
HistoryBuilder {
|
||||
mu: MU,
|
||||
@@ -552,7 +554,11 @@ 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)]`.
|
||||
///
|
||||
/// Panics if `teams.len() != 2`. N-team support lands in T4.
|
||||
/// N-team support lands in T4.
|
||||
///
|
||||
/// # 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");
|
||||
let gather = |team: &[&K]| -> Gaussian {
|
||||
@@ -574,6 +580,15 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
}
|
||||
|
||||
/// Run the full forward+backward convergence loop and return a summary.
|
||||
///
|
||||
/// Failing to reach `epsilon` within `max_iter` is not an error: the
|
||||
/// returned report carries `converged: false` and the final step.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// `NonFiniteResult` if a sweep produces a NaN or infinite step. EP has
|
||||
/// broken down at that point and further iterations cannot recover, so the
|
||||
/// loop stops rather than reporting a NaN step as convergence.
|
||||
pub fn converge(&mut self) -> Result<ConvergenceReport, InferenceError> {
|
||||
use std::time::Instant;
|
||||
|
||||
@@ -830,6 +845,13 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Record a single two-competitor event that `winner` won.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Ingests through the same path as [`History::add_events`], so it returns
|
||||
/// the same errors. A two-team decisive outcome cannot tie, so
|
||||
/// `TieWithoutDrawProbability` is not reachable here.
|
||||
pub fn record_winner<Q>(&mut self, winner: &Q, loser: &Q, time: T) -> Result<(), InferenceError>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
@@ -847,6 +869,13 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
)
|
||||
}
|
||||
|
||||
/// Record a single two-competitor event that ended level.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Ingests through the same path as [`History::add_events`]. Note
|
||||
/// `TieWithoutDrawProbability` *is* reachable here: a draw needs a
|
||||
/// positive `p_draw`.
|
||||
pub fn record_draw<Q>(&mut self, a: &Q, b: &Q, time: T) -> Result<(), InferenceError>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
@@ -870,6 +899,17 @@ impl<T: Time, D: Drift<T>, O: Observer<T>, K: Eq + Hash + Clone> History<T, D, O
|
||||
}
|
||||
|
||||
/// Bulk-ingest typed events.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - `MismatchedShape` if an event's outcome does not describe the same
|
||||
/// number of teams the event has, or if per-member weights do not match
|
||||
/// the team's membership.
|
||||
/// - `InvalidParameter` if a per-event `score_sigma` override is not
|
||||
/// strictly positive.
|
||||
/// - `TieWithoutDrawProbability` if an event ties two teams while the
|
||||
/// history's `p_draw` is zero. This includes `Outcome::winner(w, n)` for
|
||||
/// `n >= 3`, which ties every loser.
|
||||
pub fn add_events<I>(&mut self, events: I) -> Result<(), InferenceError>
|
||||
where
|
||||
I: IntoIterator<Item = crate::event::Event<T, K>>,
|
||||
|
||||
Reference in New Issue
Block a user