What to build
Allow a Reduction::PerEntity aggregate to represent more than one aggregate measure while preserving the label set, timestamp, and a well-defined output schema for every measure.
Today, per-entity range reductions are structurally limited to one measure. This blocks algebraically valid rewrites such as avg_over_time(x) → sum_over_time(x) / count_over_time(x), tracked by #410.
Current schema derivation encodes the limitation:
Reduction::PerEntity => {
debug_assert_eq!(measures.len(), 1, "a per-entity reduction is single-aggregate");
return Ok(per_series_reduction_schema(in_schema, &measures[0]));
}
and the per-series path replaces the one conventional sample-value column:
let mut columns = input.columns.clone();
columns[vi] = out; // `out.name` is forced to "value"
The resulting schema cannot carry both a per-series sum and count. Define and implement the smallest compatible multi-measure schema contract, including naming and type behavior, so downstream lowering and binary operations can safely consume it.
Acceptance criteria
Blocked by
None — can start immediately.
What to build
Allow a
Reduction::PerEntityaggregate to represent more than one aggregate measure while preserving the label set, timestamp, and a well-defined output schema for every measure.Today, per-entity range reductions are structurally limited to one measure. This blocks algebraically valid rewrites such as
avg_over_time(x) → sum_over_time(x) / count_over_time(x), tracked by #410.Current schema derivation encodes the limitation:
and the per-series path replaces the one conventional sample-value column:
The resulting schema cannot carry both a per-series sum and count. Define and implement the smallest compatible multi-measure schema contract, including naming and type behavior, so downstream lowering and binary operations can safely consume it.
Acceptance criteria
PerEntityaggregate with multiple measures has a deterministic, validated output schema that preserves timestamp and labels and exposes every measure.valueand isFloat64.Blocked by
None — can start immediately.