pub fn fit(
samples: &[TreeSample],
max_depth: usize,
min_samples_leaf: usize,
max_nodes: usize,
min_rel_var_reduction: f64,
) -> SerializedTreeExpand description
Grow a CART regression tree over samples.
The growth is breadth-first so the serialized node order is the level-order layout the store requires (parents before children, index 0 = root). Each node is created as a placeholder, queued, and filled when processed. A node that clears the growth limits becomes an internal node (two new children) and everything else becomes a leaf predicting the weighted mean of its labels.
Growth stops at max_depth edges, when either child would fall below
min_samples_leaf, when the node budget max_nodes would be exceeded
(every node in the tree, internal or leaf, counts), or when no split
removes min_rel_var_reduction of the node’s label variance.
Every training sample is weighted by its recency in the window
(sample_weights: 2^(-age/(n/2))), so the fit concentrates on the
recent regime while the full window still provides the data quantity
and the gates bound every publish. The weighting enters the fit as a
weighted SSE. The leaf means and the variance-reduction ranking are
weighted, and the min_samples_leaf cap still counts samples, not
weight.
All arithmetic is f64 on the weighted label sums. The labels are
emitted by the BPF side clamped to MLFQ_TREE_LABEL_MAX_NS (see
src/bpf/intf.h), so the exact-integer range the SSE math sums is
bounded: a label value of at most 192 ms squares to ~3.7e16, far
below the f64 rounding error. The weights live in [0.25, 1], so the
weighted sums stay within the same magnitude as the uniform fit and
the split ranking is exact except for near-tied candidates containing
extreme labels, where consecutive u64 values collapse in the f64
conversion and the tie-break is approximate; the daemon never sees
such labels because of the emission clamp.
An empty samples slice or max_nodes == 0 yields an empty tree,
which serialize_validate() rejects; the daemon treats an empty tree
as untrained.