Skip to content

Add custom statistics (per-channel & cross-channel, multi-output) to StatsAggregator - #67

Open
tombonfert wants to merge 8 commits into
mainfrom
feature/arbitrary_stats_methods
Open

Add custom statistics (per-channel & cross-channel, multi-output) to StatsAggregator#67
tombonfert wants to merge 8 commits into
mainfrom
feature/arbitrary_stats_methods

Conversation

@tombonfert

@tombonfert tombonfert commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extends StatsAggregator in both the query engine and the reporting layer so users can inject arbitrary statistics functions alongside the built-ins (min/max/mean/median/start/end).

Two kinds of custom statistics

  • Per-channel: computed once per input channel per interval, exactly like a built-in. Results ride the existing numeric_values map under the real channel names.
  • Cross-channel: computed once per interval over a declared set of channels. Results carry a descriptor-provided channel_name (defaulting to the output label).

Self-describing descriptors

  • PerChannelStatistic and CrossChannelStatistic (in the new custom_statistic.py) declare the function, its params, and mandatory aggregation_labels.
  • A function returns a sequence of scalars mapped positionally to those labels, so one call can emit multiple outputs.
  • Statistics are passed as lists of descriptors. Labels are the sole identity and must be globally unique and must not shadow built-ins.

Reporting integration

  • custom outputs flow end-to-end into stats_aggregator_fact with no schema change (they reuse aggregation_label/statistic_value).
  • The dimension row's statistics lists all labels. The definition hash folds in each statistic's kind, labels, resolved input indices, params, and function bytecode so changes invalidate cached results, while custom-free aggregators keep their previous hash.

Tests

  • unit and integration coverage for single/multi-output, params, input subsetting, empty-interval handling, validation errors, definition-hash stability, and end-to-end fact-row production. Full suite green; black and ruff clean.

Test Plan

  • Unit tests added/updated
  • Manual testing completed
  • Documentation updated (if applicable)

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • No new linter warnings introduced

- Introduced the CrossChannelStatistic class to facilitate cross-channel custom statistics in the query engine.
- Updated StatsAggregator to support cross-channel and per-channel custom statistics, including validation and normalization of input statistics.
- Enhanced documentation for both classes, detailing parameters, expected behaviors, and usage examples.
- Added integration tests to validate the functionality of custom statistics within the StatsAggregator, ensuring correct computation and output.
- Updated existing tests to accommodate changes in the output schema, including cross-channel values in the results.
- Removed the CrossChannelStatistic class and integrated its functionality into a new custom_statistic module, which now includes both CrossChannelStatistic and PerChannelStatistic classes.
- Updated StatsAggregator to utilize the new custom statistics classes, enhancing support for both cross-channel and per-channel custom statistics.
- Implemented parameter handling for custom statistics, allowing for dynamic configuration during aggregation.
- Added validation for custom statistic parameters to ensure correct usage and prevent errors.
- Enhanced unit and integration tests to cover the new functionality and validate the behavior of custom statistics with parameters.
- Replaced dict-based custom statistic registration with lists of
  `PerChannelStatistic`/`CrossChannelStatistic` descriptors.
- Added required `aggregation_labels` to each descriptor; functions now
  return a sequence of values mapped positionally to those labels.
- Updated query-engine and reporting-layer `StatsAggregator` validation,
  definition hashing, and fact-row generation to handle multiple outputs
  per statistic.
- Added integration tests for multi-output per-channel and cross-channel
  custom statistics.
@tombonfert
tombonfert requested a review from a team as a code owner July 29, 2026 14:56
- Add API reference for impulse_query_engine.analyze.query.aggregations.custom_statistic.
- Update StatsAggregator, data model, report reference, and skill docs to cover per-channel and cross-channel custom statistics.
- Refresh CalculatedChannel API docs to reflect get_expression returning the wrapped expression.
…positional-only partial handling

- Incorporate `__defaults__` and `__kwdefaults__` into the custom statistic fingerprint so behavior changes carried only by default arguments alter the definition hash.
- Guard against `None` keywords when unwrapping `functools.partial` to avoid crashes for positionally-bound partials.
- Add unit tests covering default-argument hash stability and positional-only partial hashing.
@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.69406% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.94%. Comparing base (f654d22) to head (39674eb).

Files with missing lines Patch % Lines
...ine/analyze/query/aggregations/custom_statistic.py 87.75% 3 Missing and 3 partials ⚠️
...impulse_reporting/aggregations/stats_aggregator.py 91.04% 3 Missing and 3 partials ⚠️
...ine/analyze/query/aggregations/stats_aggregator.py 96.03% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #67      +/-   ##
==========================================
+ Coverage   88.72%   88.94%   +0.22%     
==========================================
  Files          59       60       +1     
  Lines        4826     5013     +187     
  Branches      552      596      +44     
==========================================
+ Hits         4282     4459     +177     
- Misses        445      451       +6     
- Partials       99      103       +4     
Files with missing lines Coverage Δ
...ngine/analyze/query/aggregations/statistic_type.py 100.00% <100.00%> (ø)
...e_reporting/aggregations/point_value_aggregator.py 97.64% <ø> (ø)
...ine/analyze/query/aggregations/stats_aggregator.py 95.83% <96.03%> (+4.03%) ⬆️
...ine/analyze/query/aggregations/custom_statistic.py 87.75% <87.75%> (ø)
...impulse_reporting/aggregations/stats_aggregator.py 94.17% <91.04%> (-1.54%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…ion hash and canonicalize StatsAggregator event_timestamps

- Query engine `StatsAggregator.build` now returns a canonical `event_timestamps` list with one entry per non-degenerate interval, aligned 1:1 with `numeric_values` per signal and `cross_channel_values`; removes the previous series-major repetition.
- Reporting layer includes `channel_names` in `StatsAggregator` and `PointValueAggregator` definition hashes, and each cross-channel custom statistic's `channel_name` in its fingerprint, so renames force a recompute and stale fact rows are pruned in incremental mode.
- Update reference docs, skill docs, and tests to reflect the new hash inputs and canonical timestamp layout.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant