Skip to content

feat(metrics): add dimensional timeseries querying - #1836

Merged
aleksdotbar merged 4 commits into
mainfrom
feat/1781-weekly-git-output
Jul 21, 2026
Merged

feat(metrics): add dimensional timeseries querying#1836
aleksdotbar merged 4 commits into
mainfrom
feat/1781-weekly-git-output

Conversation

@aleksdotbar

@aleksdotbar aleksdotbar commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Adds grouped timeseries queries and per-metric dimension filters with validation and batch-query support. Extends Git metrics with repository, project, source, category, file extension, change type, and destination branch dimensions; adds lines removed and preserves missing values as null.\n\nCloses #1781

Summary by CodeRabbit

  • New Features

    • Added filtering by metric dimensions, including repository, project, branch, file extension, change type, and category.
    • Expanded Git analytics with additional pull request and change-size measures.
    • Added finer-grained breakdowns for commits, code changes, pull requests, merge rate, and cycle time.
    • Added support for tracking removed lines.
  • Bug Fixes

    • Missing metric data is now returned as null instead of being incorrectly displayed as zero.
    • Filter values are validated, normalized, deduplicated, and consistently ordered.

Signed-off-by: Aleksandr Barkhatov <pm@aleks.bar>
Signed-off-by: Aleksandr Barkhatov <pm@aleks.bar>
@aleksdotbar
aleksdotbar requested a review from a team as a code owner July 21, 2026 13:01
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 87353dbe-4e50-4cca-b5de-9dbe635c6bd8

📥 Commits

Reviewing files that changed from the base of the PR and between da7afad505890908510356cbb550ea002cc076cd and d286a86.

📒 Files selected for processing (3)
  • src/backend/services/analytics/src/domain/metric_definitions/builtin.rs
  • src/backend/services/analytics/src/domain/metric_results/validation.rs
  • src/ingestion/gold/git_metric_observations.sql
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/ingestion/gold/git_metric_observations.sql
  • src/backend/services/analytics/src/domain/metric_definitions/builtin.rs
  • src/backend/services/analytics/src/domain/metric_results/validation.rs

📝 Walkthrough

Walkthrough

Git metrics now expose additional dimensions and measures. Metric requests support validated per-metric dimension filters that flow through batching and SQL compilation. Period and timeseries results preserve missing values as null instead of fabricated zeros.

Changes

Analytics metric dimensions and filtering

Layer / File(s) Summary
Git observation dimensions
src/ingestion/gold/git_metric_observations.sql, src/ingestion/gold/schema.yml
Git observations derive repository, project, destination branch, file-extension, change-type, and category dimensions, with lines_removed added to the accepted measure keys.
Metric dimensions and filter validation
src/backend/services/analytics/src/domain/metric_definitions/builtin.rs, src/backend/services/analytics/src/domain/metric_results/dto.rs, src/backend/services/analytics/src/domain/metric_results/validation.rs
Built-in Git metrics declare expanded dimensions, and metric requests accept filters that are validated, trimmed, deduplicated, sorted, and bounded.
Filtered query compilation and batching
src/backend/services/analytics/src/domain/metric_results/compiler.rs, src/backend/services/analytics/src/domain/metric_results/batch.rs
Dimension filters are included in query predicates and parameters, and period/peer batches are grouped by filter sets.
Null-preserving metric results
src/backend/services/analytics/src/domain/metric_definitions/definition.rs, src/backend/services/analytics/src/domain/metric_results/builder.rs
Missing period entities and timeseries buckets now produce null values; zero-fill classification and fabricated transformed zeros are removed.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MetricRequest
  participant validate_request
  participant plan_queries
  participant metric_results_compiler
  participant git_metric_observations
  participant build_period_view

  MetricRequest->>validate_request: dimension filters
  validate_request->>plan_queries: ValidatedMetricRequest with filters
  plan_queries->>metric_results_compiler: grouped filters
  metric_results_compiler->>git_metric_observations: SQL predicates and bound values
  git_metric_observations-->>metric_results_compiler: metric rows
  metric_results_compiler-->>build_period_view: compiled results
  build_period_view-->>MetricRequest: values or null
Loading

Possibly related PRs

Suggested reviewers: cyberantonz, mitasovr

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning These changes add backend metric dimensions, filters, and null handling, but they do not implement the weekly Git Output table, totals, or empty state requested in #1781. Add the Git Output weekly table UI and wire it to the selected period, repo grouping, totals, summary, em-dash handling, and empty-state behavior.
Docstring Coverage ⚠️ Warning Docstring coverage is 60.61% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: adding dimensional timeseries querying for metrics.
Out of Scope Changes check ✅ Passed The diff stays focused on analytics and ingestion support for Git metrics, with no clearly unrelated feature work.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/1781-weekly-git-output

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@aleksdotbar aleksdotbar changed the title Add repository-level Git metric output feat(metrics): add repository-level Git output Jul 21, 2026
@aleksdotbar
aleksdotbar force-pushed the feat/1781-weekly-git-output branch from da7afad to 4b5bd29 Compare July 21, 2026 13:04
@aleksdotbar aleksdotbar changed the title feat(metrics): add repository-level Git output feat(metrics): add dimensional timeseries querying Jul 21, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
dev-compose.sh (1)

290-314: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Prevent duplicate YAML keys when combining flags.

If a user runs the compose script with both --no-analytics and --from-ghcr=api-gateway, the generated override.generated.yml will declare the api-gateway: key twice: once from the ghcr_list loop and again from the no_analytics block.

Docker Compose strictly rejects duplicate mapping keys and will fail to parse the file, preventing the stack from starting. To fix this, merge the api-gateway configuration directly inside the all_backend loop to ensure the service key is emitted only once.

🐛 Proposed fix to merge YAML blocks
-        if contains "$ghcr_list" "$svc"; then
+        if contains "$ghcr_list" "$svc" || { [[ "$svc" == "api-gateway" ]] && [[ "$no_analytics" == "true" ]]; }; then
           # Ghcr images are amd64-only for now (arm64 builds are
           # tracked separately). Pin the platform so Apple-silicon
           # hosts pull the amd64 manifest and run it under Rosetta
           # instead of erroring with "no matching manifest for
           # linux/arm64/v8".
           cat <<YML
   ${svc}:
+YML
+          if contains "$ghcr_list" "$svc"; then
+            cat <<YML
     build: !reset null
     volumes: !override []
     entrypoint: !reset null
     command: !reset null
     platform: linux/amd64
 YML
           fi
+          if [[ "$svc" == "api-gateway" ]] && [[ "$no_analytics" == "true" ]]; then
+            cat <<YML
+    extra_hosts:
+      - "analytics:host-gateway"
+YML
+          fi
+        fi
       done
       if [[ "$no_analytics" == "true" ]]; then
         cat <<'YML'
   analytics:
     profiles: ["analytics"]
-  api-gateway:
-    extra_hosts:
-      - "analytics:host-gateway"
 YML
       fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dev-compose.sh` around lines 290 - 314, Move the no-analytics api-gateway
configuration into the existing all_backend/ghcr_list generation flow so that
api-gateway is emitted under a single service key when both flags are used.
Update the relevant loop and conditionals around the ghcr service generation,
while preserving the analytics profile and api-gateway extra_hosts settings;
remove the separate api-gateway block from the no_analytics section.
🧹 Nitpick comments (2)
src/backend/services/analytics/src/domain/metric_results/batch.rs (1)

60-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add unit tests for batch splitting by filters.

Including metric.filters in the grouping keys cleanly solves the issue of applying differing filters within the same batch.

Consider adding a test case to plan_queries that confirms views with identical sources but different filter configurations are correctly separated into distinct PlannedQuery::PeriodBatch or PlannedQuery::PeerBatch outputs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/services/analytics/src/domain/metric_results/batch.rs` around
lines 60 - 81, Add unit coverage in plan_queries for batch grouping by filters,
using views with the same source but different metric.filters. Assert they
produce separate PlannedQuery::PeriodBatch or PlannedQuery::PeerBatch outputs,
while identical filter configurations remain grouped.
src/backend/services/analytics/src/domain/metric_results/compiler.rs (1)

546-560: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add unit tests for filter SQL compilation.

The new dimension_filter_where logic successfully guards against empty IN () syntax and safely handles ClickHouse array boundaries, thanks to upstream validation and the indexOf pattern.

However, since all updated tests in this file pass &[] for the filters parameter, consider adding a unit test for one of the query compilation functions (or dimension_filter_where directly) that passes one or more ValidatedDimensionFilter instances. This will ensure that the filter SQL predicates and parameter lockstep are protected against future regressions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/services/analytics/src/domain/metric_results/compiler.rs` around
lines 546 - 560, Add a unit test covering non-empty dimension filters, either
through dimension_filter_where or a query compilation function that invokes it.
Construct one or more ValidatedDimensionFilter instances and assert the
generated SQL contains the expected indexOf/IN predicates and that params
contains the corresponding values in matching order.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/backend/services/analytics/src/domain/metric_results/validation.rs`:
- Around line 357-374: Update the filter-value construction in the validation
loop to collect trimmed, validated, deduplicated values in the existing
BTreeSet, then build ValidatedDimensionFilter.values directly from that set so
values are sorted deterministically and avoid the current duplicate vector
allocations. Preserve the existing empty-value and maximum-byte validation
behavior.

In `@src/ingestion/gold/git_metric_observations.sql`:
- Line 304: Update the git.commits_per_active_day metric explanation in
builtin.rs to explicitly document that active days are counted separately for
each repository due to the source_dimensions passed to presence_measure for
commit_day. Preserve the existing repository drill-down behavior and ensure the
explanation clarifies the resulting repository-day denominator.

---

Outside diff comments:
In `@dev-compose.sh`:
- Around line 290-314: Move the no-analytics api-gateway configuration into the
existing all_backend/ghcr_list generation flow so that api-gateway is emitted
under a single service key when both flags are used. Update the relevant loop
and conditionals around the ghcr service generation, while preserving the
analytics profile and api-gateway extra_hosts settings; remove the separate
api-gateway block from the no_analytics section.

---

Nitpick comments:
In `@src/backend/services/analytics/src/domain/metric_results/batch.rs`:
- Around line 60-81: Add unit coverage in plan_queries for batch grouping by
filters, using views with the same source but different metric.filters. Assert
they produce separate PlannedQuery::PeriodBatch or PlannedQuery::PeerBatch
outputs, while identical filter configurations remain grouped.

In `@src/backend/services/analytics/src/domain/metric_results/compiler.rs`:
- Around line 546-560: Add a unit test covering non-empty dimension filters,
either through dimension_filter_where or a query compilation function that
invokes it. Construct one or more ValidatedDimensionFilter instances and assert
the generated SQL contains the expected indexOf/IN predicates and that params
contains the corresponding values in matching order.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 69dcd1a9-7fb4-4529-b766-cca4aef79067

📥 Commits

Reviewing files that changed from the base of the PR and between ef86925 and da7afad505890908510356cbb550ea002cc076cd.

📒 Files selected for processing (11)
  • dev-compose.sh
  • src/backend/services/analytics/src/domain/metric_definitions/builtin.rs
  • src/backend/services/analytics/src/domain/metric_definitions/definition.rs
  • src/backend/services/analytics/src/domain/metric_results/batch.rs
  • src/backend/services/analytics/src/domain/metric_results/builder.rs
  • src/backend/services/analytics/src/domain/metric_results/compiler.rs
  • src/backend/services/analytics/src/domain/metric_results/dto.rs
  • src/backend/services/analytics/src/domain/metric_results/validation.rs
  • src/ingestion/dbt/macros/metric_observation_measures.sql
  • src/ingestion/gold/git_metric_observations.sql
  • src/ingestion/gold/schema.yml

Comment thread src/backend/services/analytics/src/domain/metric_results/validation.rs Outdated
Comment thread src/ingestion/gold/git_metric_observations.sql Outdated
Signed-off-by: Aleksandr Barkhatov <pm@aleks.bar>
Signed-off-by: Aleksandr Barkhatov <pm@aleks.bar>
@aleksdotbar
aleksdotbar merged commit 8b3acc0 into main Jul 21, 2026
34 checks passed
@aleksdotbar aleksdotbar linked an issue Jul 23, 2026 that may be closed by this pull request
11 tasks
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.

Add a weekly Git output table to the Git Output section

2 participants