fl.round.ess is computed in ObservableFedAvg.aggregate_train over the train replies' num-examples, then attached to the round span in aggregate_evaluate alongside fl.loss and fl.accuracy.
Those two come from different client sets. fraction-train and fraction-evaluate are independent knobs, and flwr samples each phase separately, so even at the default 0.1 / 0.1 the round's train cohort and evaluate cohort are different draws. fl.ess and fl.clients are consistent with each other (both train-derived); fl.loss and fl.accuracy are not.
The docstring on effective_sample_size says so, but a Jaeger or Prometheus view reads the attributes off the span with no docstring in sight, and the natural reading of fl.ess next to fl.accuracy is that they describe the same aggregation.
Recommended fix
Emit the evaluate-side one too, and name both for their phase:
fl.round.train_ess — over aggregate_train weights, what produced the adapters.
fl.round.evaluate_ess — over aggregate_evaluate weights, what produced the reported loss/accuracy.
effective_sample_size and _num_examples already work on either; aggregate_evaluate receives the replies it needs. The change is where they are called, plus the span attributes and the two docs enumerations (docs/architecture.md, docs/getting-started.md).
Keeping fl.round.ess as an alias for the train figure is an option, though nothing depends on it yet — it shipped in #102.
Related: the evaluate-side ESS is the one that qualifies the accuracy number, so it pairs with #104.
fl.round.essis computed inObservableFedAvg.aggregate_trainover the train replies'num-examples, then attached to the round span inaggregate_evaluatealongsidefl.lossandfl.accuracy.Those two come from different client sets.
fraction-trainandfraction-evaluateare independent knobs, and flwr samples each phase separately, so even at the default0.1 / 0.1the round's train cohort and evaluate cohort are different draws.fl.essandfl.clientsare consistent with each other (both train-derived);fl.lossandfl.accuracyare not.The docstring on
effective_sample_sizesays so, but a Jaeger or Prometheus view reads the attributes off the span with no docstring in sight, and the natural reading offl.essnext tofl.accuracyis that they describe the same aggregation.Recommended fix
Emit the evaluate-side one too, and name both for their phase:
fl.round.train_ess— overaggregate_trainweights, what produced the adapters.fl.round.evaluate_ess— overaggregate_evaluateweights, what produced the reported loss/accuracy.effective_sample_sizeand_num_examplesalready work on either;aggregate_evaluatereceives the replies it needs. The change is where they are called, plus the span attributes and the two docs enumerations (docs/architecture.md,docs/getting-started.md).Keeping
fl.round.essas an alias for the train figure is an option, though nothing depends on it yet — it shipped in #102.Related: the evaluate-side ESS is the one that qualifies the accuracy number, so it pairs with #104.