Skip to main content

tix/
analytics.rs

1//! Burndown and scope analytics (mission `burndown-scope-analytics-01M3C9J1`).
2//!
3//! A **pure projection** over what the tree already records: the append-only
4//! History, issue frontmatter, cycle/milestone planning and snapshots, and the
5//! shared status categories (C-001). Nothing here opens a store, reads a clock,
6//! writes an issue, or introduces a second cycle/status model — an analytics value
7//! is derived on read and persisted nowhere (except the local chart document WP04
8//! exports, which is output rather than state).
9//!
10//! # What is recorded, and what is therefore reportable
11//!
12//! The classification in [`events`] maps **recorded** events only. A day with no
13//! recorded history is `unknown`/coverage-limited, never zero by assumption
14//! (C-005), and a scope change that was never logged is never reconstructed — the
15//! mission's non-goal. Two of the four classes needed a producer rather than a
16//! guess, and WP01 added them at the seam `tix edit --parent` already appends to
17//! ([`crate::model::HistoryEventKind::EstimateChanged`] and
18//! [`crate::model::HistoryEventKind::CycleMembershipChanged`]), so
19//! `scope_addition` and `estimate_change` fold something recorded instead of
20//! staying permanently unproducible.
21//!
22//! # Ownership of this root
23//!
24//! This file is WP01's and is **frozen** after it: all six children are declared
25//! here, and each later work package fills in its own child rather than declaring
26//! one (T045). Without that split this single file would be owned by three lanes at
27//! once — the same shape [`crate::capacity`] and [`crate::time_tracking`] use for
28//! their own children.
29//!
30//! [`events`] carries the scope, the period, the closed classification vocabulary,
31//! the provenance-bearing event value and the idempotency index; it is the
32//! vocabulary every later child consumes. [`series`], [`diagnostics`], [`units`],
33//! [`projection`] and [`chart`] are declared here as compile-clean stubs and are
34//! filled in by WP02 (daily series, coverage, diagnostics), WP03 (unit conversion,
35//! end-date projection) and WP04 (deterministic chart export).
36//!
37//! # The boundary of the record
38//!
39//! A class is only as wide as the recorded evidence. The values `tix edit
40//! --estimate`/`--cycles`/`--parent` write carry an event, so they are visible to the
41//! classification; a path that writes a field without appending — the bulk patch
42//! service writes through `Store::update` — leaves no event and therefore cannot
43//! appear in `estimate_change` or `scope_addition`. A surface reports that as an
44//! explicit coverage marker, never by reading the current frontmatter back into the
45//! past.
46
47pub mod chart;
48pub mod diagnostics;
49pub mod events;
50pub mod projection;
51pub mod series;
52pub mod units;
53
54pub use events::{
55    AnalyticsEvent, AnalyticsScope, Contribution, EventClass, EventIndex, EventSource, Period,
56    ScopeKind, cycle_scope, milestone_scope,
57};