Skip to content

feat(metrics): add evidence metadata and drilldown capability - #2072

Merged
aleksdotbar merged 1 commit into
mainfrom
feat/metric-evidence-metadata
Jul 31, 2026
Merged

feat(metrics): add evidence metadata and drilldown capability#2072
aleksdotbar merged 1 commit into
mainfrom
feat/metric-evidence-metadata

Conversation

@aleksdotbar

@aleksdotbar aleksdotbar commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • store evidence relation and per-measure granularity in the metric registry
  • probe the evidence contract in the schema validator; missing or invalid evidence fails closed
  • advertise drilldown capability through POST /v1/metric-results and GET /v1/metric-definitions
  • return the canonical selection with every metric result

Stack

Merges bottom-up; each PR retargets to main as its parent lands.

  1. feat(gold): add metric evidence serving tables #2071 — evidence serving tables
  2. feat(metrics): add evidence metadata and drilldown capability #2072 — capability metadata
  3. feat(metrics): add metric drilldown endpoint #2073 — drilldown endpoint
  4. feat(metrics): add metric drilldown CSV/XLSX export #2074 — CSV/XLSX export

UI layer: constructorfabric/insight-front#226

Closes #2068

Validation

  • cargo test -p analytics

Summary by CodeRabbit

  • New Features
    • Metric definitions now expose available evidence-based drilldown granularity.
    • Metric results now include a required selection object (metric key, entity, period, and dimension filters).
    • Optionally returned drilldown granularity is included only when evidence is validated and available.
  • Bug Fixes
    • Improved evidence and source status validation, with revision-guarded updates to prevent stale overwrites.
  • Documentation
    • Updated API/metric documentation to describe drilldown capability, result selection, and the distinct_count computation variant.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@aleksdotbar, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 278d184e-c526-400f-8e6c-b689cfe6e031

📥 Commits

Reviewing files that changed from the base of the PR and between 436ce21f054882022eae2591bbecd5163be36f99 and 0862081.

📒 Files selected for processing (20)
  • docs/components/backend/analytics/openapi.json
  • docs/domain/metrics/specs/DESIGN.md
  • src/backend/services/analytics/src/api/metric_results.rs
  • 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_definitions/listing.rs
  • src/backend/services/analytics/src/domain/metric_definitions/live_tests.rs
  • src/backend/services/analytics/src/domain/metric_definitions/mod.rs
  • src/backend/services/analytics/src/domain/metric_definitions/repository.rs
  • src/backend/services/analytics/src/domain/metric_definitions/seeds.rs
  • src/backend/services/analytics/src/domain/metric_definitions/test_fixture.rs
  • src/backend/services/analytics/src/domain/metric_definitions/validator.rs
  • src/backend/services/analytics/src/domain/metric_drilldown/mod.rs
  • src/backend/services/analytics/src/domain/metric_results/builder.rs
  • src/backend/services/analytics/src/domain/metric_results/dto.rs
  • src/backend/services/analytics/src/domain/metric_results/mod.rs
  • src/backend/services/analytics/src/domain/metric_results/validation.rs
  • src/backend/services/analytics/src/domain/mod.rs
  • src/backend/services/analytics/src/migration/m20260727_000001_metric_evidence.rs
  • src/backend/services/analytics/src/migration/mod.rs
📝 Walkthrough

Walkthrough

Adds evidence metadata persistence and validation, derives fail-closed metric drilldown capabilities, and exposes those capabilities plus canonical selection context through metric definitions and metric results APIs.

Changes

Evidence Drilldown Capability

Layer / File(s) Summary
Evidence contract and persistence
src/backend/services/analytics/src/domain/metric_definitions/{definition,builtin,seeds}.rs, src/backend/services/analytics/src/migration/*
Adds evidence granularity and relation types, builtin evidence metadata, seed persistence, and a forward migration for evidence columns, constraints, and triggers.
Evidence validation and revision-safe updates
src/backend/services/analytics/src/domain/metric_definitions/{repository,validator,test_fixture,live_tests}.rs
Validates evidence schemas and granularities, updates statuses with revision guards, and adds database-backed integration coverage.
Capability derivation and definition listing
src/backend/services/analytics/src/domain/{mod.rs,metric_drilldown/*}, src/backend/services/analytics/src/domain/metric_definitions/listing.rs
Derives healthy per-metric drilldown capabilities and includes optional capabilities in metric-definition responses.
Result selection and drilldown response
src/backend/services/analytics/src/api/metric_results.rs, src/backend/services/analytics/src/domain/metric_results/*
Adds structured selection DTOs, attaches canonical request context and capabilities to metric results, and reuses crate-visible normalization helpers.
API schemas and design contract
docs/components/backend/analytics/openapi.json, docs/domain/metrics/specs/DESIGN.md
Publishes the evidence, drilldown, selection, entity, period, and dimension-filter contracts.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant query_metric_results
  participant load_capabilities
  Client->>query_metric_results: request metric results
  query_metric_results->>load_capabilities: load tenant metric capabilities
  load_capabilities-->>query_metric_results: return capability map
  query_metric_results-->>Client: return selection and optional drilldown metadata
Loading

Possibly related issues

  • Issue 1603 — Covers the broader metric drilldown capability and selection-context implementation.
  • Issue 2054 — The backend response fields added here support the UI’s drilldown consumption.

Possibly related PRs

Suggested labels: stack:metric-drilldown

Suggested reviewers: cyberantonz

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main metrics evidence and drilldown change.
Linked Issues check ✅ Passed The changes satisfy the evidence metadata, fail-closed validation, drilldown exposure, and canonical selection requirements in #2068.
Out of Scope Changes check ✅ Passed The docs, tests, migration, and code changes all support the stated metrics objective without obvious unrelated scope.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/metric-evidence-metadata

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.

cyberantonz
cyberantonz previously approved these changes Jul 30, 2026
@aleksdotbar aleksdotbar added the stack:metric-drilldown Stacked PR series for metric evidence drilldown (#1603) label Jul 30, 2026
Base automatically changed from feat/metric-evidence-tables to main July 30, 2026 12:16
@aleksdotbar
aleksdotbar dismissed cyberantonz’s stale review July 30, 2026 12:16

The base branch was changed.

@aleksdotbar
aleksdotbar enabled auto-merge July 30, 2026 12:17
@aleksdotbar
aleksdotbar requested a review from a team July 30, 2026 12:27
@aleksdotbar
aleksdotbar force-pushed the feat/metric-evidence-metadata branch from 509cc93 to 2bb09fb Compare July 30, 2026 15:48

@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)
src/backend/services/analytics/src/domain/metric_drilldown/mod.rs (1)

108-117: 📐 Maintainability & Code Quality | 🔴 Critical | ⚡ Quick win

cargo fmt --check failure (confirmed by pipeline logs).

Two consecutive blank lines before fn db_error — rustfmt collapses these to one, which is exactly what the CI fmt-check diff reports.

🔧 Proposed fix
     Ok(capabilities)
 }
 
-
 fn db_error(error: &sea_orm::DbErr) -> CanonicalError {
     tracing::error!(error = %error, "metric drilldown metadata query failed");
     CanonicalError::internal("failed to load metric evidence metadata").create()
 }
🤖 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_drilldown/mod.rs` around
lines 108 - 117, Remove the extra blank line immediately before the db_error
function so only one blank line separates it from the preceding code, allowing
cargo fmt --check to pass.

Source: Pipeline failures

🧹 Nitpick comments (2)
src/backend/services/analytics/src/domain/metric_definitions/repository.rs (1)

638-665: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Mirror the stale-revision logging added to update_evidence_status.

update_source_status now silently returns Ok(()) when the revision guard matches nothing, and validate_all then proceeds to validate_definitions_for_source as if the write landed. Emitting the same rows_affected == 0 trace keeps the two writers diagnosable.

🔍 Proposed change
-    db.execute(Statement::from_sql_and_values(
+    let result = db
+        .execute(Statement::from_sql_and_values(
         db.get_database_backend(),
     ))
     .await?;
+    if result.rows_affected() == 0 {
+        tracing::trace!(
+            %source_id,
+            config_revision,
+            "metric source status update skipped for stale configuration revision"
+        );
+    }
     Ok(())
 }
🤖 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_definitions/repository.rs`
around lines 638 - 665, Update update_source_status to capture the execute
result, inspect rows_affected, and emit the same stale-revision trace used by
update_evidence_status when no row matches; preserve the existing SQL,
parameters, and return behavior.
src/backend/services/analytics/src/domain/metric_results/builder.rs (1)

286-298: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Empty-string placeholder selection depends on the caller overwriting it.

build_metric_result emits selection with entity.type = "" and period.from/to = "", and correctness relies entirely on query_metric_results replacing the whole struct afterwards. Any future caller silently ships a response whose canonical selection claims an empty entity type and non-ISO empty dates.

Passing the selection (or the validated request + filters) into build_metric_result makes the contract non-optional; there is only one production call site today.

♻️ Sketch
 pub fn build_metric_result(
     def: &MetricDefinition,
     views: Vec<MetricResultViewDto>,
+    selection: MetricResultSelectionDto,
 ) -> MetricResultDto {
         drilldown: None,
-        selection: super::dto::MetricResultSelectionDto {
-            metric_key: def.key().to_owned(),
-            entity: super::dto::MetricResultsEntityDto {
-                r#type: String::new(),
-                ids: Vec::new(),
-            },
-            period: super::dto::MetricResultsPeriodDto {
-                from: String::new(),
-                to: String::new(),
-            },
-            filters: Vec::new(),
-        },
+        selection,
🤖 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/builder.rs` around
lines 286 - 298, Update build_metric_result to accept the validated selection or
request and filters as an argument, then populate MetricResultSelectionDto from
those values instead of empty-string placeholders. Update query_metric_results,
the sole production caller, to pass the validated data through so every result
carries the canonical entity type and ISO period values without relying on later
replacement.
🤖 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_definitions/validator.rs`:
- Around line 464-562: The observation-since query in
evidence_granularities_match currently scans all historical metric_date values
before applying the evidence window, allowing read limits to fail. Bound this
freshness probe to a recent metric_date range before computing max(metric_date),
reusing the existing probe-window configuration and preserving the subsequent
evidence-window matching behavior.

In
`@src/backend/services/analytics/src/migration/m20260727_000001_metric_evidence.rs`:
- Around line 58-78: The replace_evidence_constraints function currently drops
existing checks with DROP CHECK; update its generated drop DDL to use DROP
CONSTRAINT IF EXISTS for each constraint name, preserving the subsequent
constraint creation flow.

---

Outside diff comments:
In `@src/backend/services/analytics/src/domain/metric_drilldown/mod.rs`:
- Around line 108-117: Remove the extra blank line immediately before the
db_error function so only one blank line separates it from the preceding code,
allowing cargo fmt --check to pass.

---

Nitpick comments:
In `@src/backend/services/analytics/src/domain/metric_definitions/repository.rs`:
- Around line 638-665: Update update_source_status to capture the execute
result, inspect rows_affected, and emit the same stale-revision trace used by
update_evidence_status when no row matches; preserve the existing SQL,
parameters, and return behavior.

In `@src/backend/services/analytics/src/domain/metric_results/builder.rs`:
- Around line 286-298: Update build_metric_result to accept the validated
selection or request and filters as an argument, then populate
MetricResultSelectionDto from those values instead of empty-string placeholders.
Update query_metric_results, the sole production caller, to pass the validated
data through so every result carries the canonical entity type and ISO period
values without relying on later replacement.
🪄 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 Plus

Run ID: 743f0f68-9ba2-42c2-9119-38b59ef44f78

📥 Commits

Reviewing files that changed from the base of the PR and between 99697d1 and 2bb09fbafc759324da91905737691c7567815eb8.

📒 Files selected for processing (20)
  • docs/components/backend/analytics/openapi.json
  • docs/domain/metrics/specs/DESIGN.md
  • src/backend/services/analytics/src/api/metric_results.rs
  • 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_definitions/listing.rs
  • src/backend/services/analytics/src/domain/metric_definitions/live_tests.rs
  • src/backend/services/analytics/src/domain/metric_definitions/mod.rs
  • src/backend/services/analytics/src/domain/metric_definitions/repository.rs
  • src/backend/services/analytics/src/domain/metric_definitions/seeds.rs
  • src/backend/services/analytics/src/domain/metric_definitions/test_fixture.rs
  • src/backend/services/analytics/src/domain/metric_definitions/validator.rs
  • src/backend/services/analytics/src/domain/metric_drilldown/mod.rs
  • src/backend/services/analytics/src/domain/metric_results/builder.rs
  • src/backend/services/analytics/src/domain/metric_results/dto.rs
  • src/backend/services/analytics/src/domain/metric_results/mod.rs
  • src/backend/services/analytics/src/domain/metric_results/validation.rs
  • src/backend/services/analytics/src/domain/mod.rs
  • src/backend/services/analytics/src/migration/m20260727_000001_metric_evidence.rs
  • src/backend/services/analytics/src/migration/mod.rs

@aleksdotbar
aleksdotbar force-pushed the feat/metric-evidence-metadata branch from 2bb09fb to be02253 Compare July 30, 2026 16:10
@aleksdotbar
aleksdotbar requested a review from a team July 30, 2026 16:40
@aleksdotbar
aleksdotbar force-pushed the feat/metric-evidence-metadata branch from be02253 to 436ce21 Compare July 30, 2026 17:48

@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: 1

🧹 Nitpick comments (5)
docs/components/backend/analytics/openapi.json (1)

1237-1251: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Declare canonical period bounds as dates.

The handler serializes validated date bounds, but this schema advertises arbitrary strings. Add format: "date" for both fields (at the generation source if this file is generated).

Proposed schema update
 "from": {
+  "format": "date",
   "type": "string"
 },
 "to": {
+  "format": "date",
   "type": "string"
 }
🤖 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 `@docs/components/backend/analytics/openapi.json` around lines 1237 - 1251,
Update the MetricResultsPeriodDto schema definition so the from and to
properties declare the date format while retaining their string types and
required status. If this OpenAPI document is generated, apply the change at its
schema-generation source rather than editing only the generated output.
src/backend/services/analytics/src/domain/metric_results/builder.rs (1)

766-808: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the new response fields in the wire-shape test.

The test passes selection(...) but never verifies it serialized; also assert that the None drilldown is omitted.

Proposed test coverage
         assert_eq!(sum_json["metric_key"], "ai.accepted_lines");
         assert_eq!(sum_json["format"], "integer");
         assert!(sum_json.get("scale").is_none());
+        assert_eq!(sum_json["selection"]["metric_key"], "ai.accepted_lines");
+        assert_eq!(sum_json["selection"]["entity"]["type"], "person");
+        assert_eq!(sum_json["selection"]["period"]["from"], "2026-07-01");
+        assert!(sum_json.get("drilldown").is_none());
🤖 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/builder.rs` around
lines 766 - 808, Update metric_result_wire_shape_is_flat_with_computation_tag to
assert the serialized selection fields from selection(...) are present,
including metric_key, entity, period, and filters as appropriate, and verify
that the None drilldown field is omitted from the JSON. Keep the existing
computation, format, and scale assertions unchanged.
src/backend/services/analytics/src/domain/metric_definitions/validator.rs (1)

130-178: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Distinguish "no evidence configured" from "evidence_ref is invalid".

Both collapse into ValidationState::Unchecked. Drilldown still fails closed downstream, but an operator who typos evidence_ref (e.g. ai_evidence) gets the same status as a source that never opted into evidence, with no error code and no warning.

♻️ Proposed change
         let state = match (
             evidence_ref.and_then(EvidenceRelation::parse),
             ObservationRelation::parse(source_ref),
         ) {
@@
-            _ => Some(ValidationState::Unchecked),
+            _ if evidence_ref.is_some_and(|value| EvidenceRelation::parse(value).is_none()) => {
+                tracing::warn!(source_key, evidence_ref, "unparseable evidence relation");
+                Some(ValidationState::Error(MetricSchemaErrorCode::Unknown))
+            }
+            _ => Some(ValidationState::Unchecked),
         };
🤖 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_definitions/validator.rs`
around lines 130 - 178, Update the state match around EvidenceRelation::parse so
a missing evidence_ref remains ValidationState::Unchecked, while a present but
invalid evidence_ref returns an appropriate ValidationState::Error with the
existing schema error code and emits a warning identifying the invalid
reference. Preserve the existing validation flow for valid evidence references
and observation relations.
src/backend/services/analytics/src/domain/metric_drilldown/mod.rs (1)

11-14: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

ClickHouse query budgets live in the wrong module.

These four constants are consumed only by metric_definitions/validator.rs; metric_drilldown itself never issues a ClickHouse query. Consider hosting them with the validator (or a shared probe-budget module) so the drilldown module stays a pure DB/capability concern.

🤖 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_drilldown/mod.rs` around
lines 11 - 14, Move EVIDENCE_QUERY_TIMEOUT_SECS, EVIDENCE_QUERY_MEMORY_BYTES,
EVIDENCE_QUERY_READ_BYTES, and EVIDENCE_QUERY_RESULT_BYTES out of
metric_drilldown and colocate them with the consumer in
metric_definitions/validator.rs, or a shared probe-budget module if appropriate.
Update the validator imports/references to use their new location and leave
metric_drilldown focused on database and capability concerns.
src/backend/services/analytics/src/domain/metric_definitions/repository.rs (1)

635-662: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the uuid_value helper and move the pinning comment above both writers.

update_source_status hand-rolls the UUID Value::Bytes that uuid_value (Line 750) already provides, and update_evidence_status uses the helper. The comment reads "the status writers below" but the evidence writer sits above it, so both writers are only partially covered.

♻️ Proposed cleanup
-// `updated_at = updated_at` in the status writers below pins the column so
-// ON UPDATE CURRENT_TIMESTAMP(3) does not fire: updated_at tracks config
-// edits, not validator sweeps.
 pub async fn update_source_status(
@@
-                Value::Bytes(Some(Box::new(source_id.as_bytes().to_vec()))),
+                uuid_value(source_id),
                 Value::from(config_revision),

and place the pinning comment immediately above update_evidence_status so it documents both writers.

🤖 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_definitions/repository.rs`
around lines 635 - 662, Update update_source_status to reuse the existing
uuid_value helper for source_id instead of constructing a Value::Bytes manually.
Move the updated_at pinning comment from above update_source_status to
immediately above update_evidence_status so it documents both status writers.
🤖 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/migration/m20260727_000001_metric_evidence.rs`:
- Around line 84-93: Update the trg_metric_sources_evidence_ref_invalidate
trigger so it also detects changes to source_ref, alongside evidence_ref, and
resets evidence_schema_status, evidence_schema_checked_at, and
evidence_schema_error_code whenever either relation changes. Preserve the
existing invalidation behavior and trigger scope.

---

Nitpick comments:
In `@docs/components/backend/analytics/openapi.json`:
- Around line 1237-1251: Update the MetricResultsPeriodDto schema definition so
the from and to properties declare the date format while retaining their string
types and required status. If this OpenAPI document is generated, apply the
change at its schema-generation source rather than editing only the generated
output.

In `@src/backend/services/analytics/src/domain/metric_definitions/repository.rs`:
- Around line 635-662: Update update_source_status to reuse the existing
uuid_value helper for source_id instead of constructing a Value::Bytes manually.
Move the updated_at pinning comment from above update_source_status to
immediately above update_evidence_status so it documents both status writers.

In `@src/backend/services/analytics/src/domain/metric_definitions/validator.rs`:
- Around line 130-178: Update the state match around EvidenceRelation::parse so
a missing evidence_ref remains ValidationState::Unchecked, while a present but
invalid evidence_ref returns an appropriate ValidationState::Error with the
existing schema error code and emits a warning identifying the invalid
reference. Preserve the existing validation flow for valid evidence references
and observation relations.

In `@src/backend/services/analytics/src/domain/metric_drilldown/mod.rs`:
- Around line 11-14: Move EVIDENCE_QUERY_TIMEOUT_SECS,
EVIDENCE_QUERY_MEMORY_BYTES, EVIDENCE_QUERY_READ_BYTES, and
EVIDENCE_QUERY_RESULT_BYTES out of metric_drilldown and colocate them with the
consumer in metric_definitions/validator.rs, or a shared probe-budget module if
appropriate. Update the validator imports/references to use their new location
and leave metric_drilldown focused on database and capability concerns.

In `@src/backend/services/analytics/src/domain/metric_results/builder.rs`:
- Around line 766-808: Update
metric_result_wire_shape_is_flat_with_computation_tag to assert the serialized
selection fields from selection(...) are present, including metric_key, entity,
period, and filters as appropriate, and verify that the None drilldown field is
omitted from the JSON. Keep the existing computation, format, and scale
assertions unchanged.
🪄 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 Plus

Run ID: 443bf5fc-7c53-4a41-a80f-db4ff86a985c

📥 Commits

Reviewing files that changed from the base of the PR and between 2bb09fbafc759324da91905737691c7567815eb8 and 436ce21f054882022eae2591bbecd5163be36f99.

📒 Files selected for processing (20)
  • docs/components/backend/analytics/openapi.json
  • docs/domain/metrics/specs/DESIGN.md
  • src/backend/services/analytics/src/api/metric_results.rs
  • 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_definitions/listing.rs
  • src/backend/services/analytics/src/domain/metric_definitions/live_tests.rs
  • src/backend/services/analytics/src/domain/metric_definitions/mod.rs
  • src/backend/services/analytics/src/domain/metric_definitions/repository.rs
  • src/backend/services/analytics/src/domain/metric_definitions/seeds.rs
  • src/backend/services/analytics/src/domain/metric_definitions/test_fixture.rs
  • src/backend/services/analytics/src/domain/metric_definitions/validator.rs
  • src/backend/services/analytics/src/domain/metric_drilldown/mod.rs
  • src/backend/services/analytics/src/domain/metric_results/builder.rs
  • src/backend/services/analytics/src/domain/metric_results/dto.rs
  • src/backend/services/analytics/src/domain/metric_results/mod.rs
  • src/backend/services/analytics/src/domain/metric_results/validation.rs
  • src/backend/services/analytics/src/domain/mod.rs
  • src/backend/services/analytics/src/migration/m20260727_000001_metric_evidence.rs
  • src/backend/services/analytics/src/migration/mod.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/backend/services/analytics/src/domain/metric_results/mod.rs
  • docs/domain/metrics/specs/DESIGN.md

Signed-off-by: Aleksandr Barkhatov <pm@aleks.bar>
@aleksdotbar
aleksdotbar force-pushed the feat/metric-evidence-metadata branch from 436ce21 to 0862081 Compare July 30, 2026 18:23
@aleksdotbar
aleksdotbar added this pull request to the merge queue Jul 31, 2026
Merged via the queue into main with commit 6d56fc8 Jul 31, 2026
44 checks passed
@aleksdotbar
aleksdotbar deleted the feat/metric-evidence-metadata branch July 31, 2026 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stack:metric-drilldown Stacked PR series for metric evidence drilldown (#1603)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Evidence metadata and drilldown capability advertisement

2 participants