Skip to content

fix: per-dimension alert descriptions when multiple dimensions fail#971

Open
joostboon wants to merge 3 commits intomasterfrom
worktree-fix-dimension-alerts
Open

fix: per-dimension alert descriptions when multiple dimensions fail#971
joostboon wants to merge 3 commits intomasterfrom
worktree-fix-dimension-alerts

Conversation

@joostboon
Copy link
Contributor

@joostboon joostboon commented Mar 13, 2026

Summary

  • When multiple dimension values fail in a dimension_anomalies test, the alert description previously only showed the last row's description (one dimension's info), ignoring all others
  • Now when ≤5 dimensions fail, each failing dimension's full description is shown (joined by |)
  • When >5 dimensions fail, a count summary is shown: "N dimension values are anomalous. Showing first 5: dim1, dim2, ..., and M more."

Root cause

In store_anomaly_test_results.sql, test_results_description was always set to rows_with_score[-1].anomaly_description — a single row. All dimension values are grouped into one test result (grouped by full_table_name, column_name, metric_name), so multiple failing dimensions were silently discarded from the description.

Changes

  • macros/edr/data_monitoring/anomaly_detection/store_anomaly_test_results.sql: Move the failures loop before description computation so anomalous_rows is available; build dimension-aware description with a 5-dimension threshold
  • integration_tests/tests/test_dimension_anomalies.py: Add two tests for the new description format (≤5 and >5 failing dimensions)

Test plan

  • Existing dimension_anomalies integration tests still pass (logic unchanged for non-dimension tests and single-dimension failures)
  • test_dimension_anomalies_alert_description_few_failures: 3 spiking dimensions → each appears in description
  • test_dimension_anomalies_alert_description_many_failures: 6 spiking dimensions → summary count message appears

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements

    • Anomaly alert descriptions now list failing dimension values and cap long lists with a concise "and N more" summary for readability.
  • Tests

    • Added integration tests verifying alert descriptions when few vs. many dimension values fail.
  • Bug Fixes

    • Fixed numeric serialization edge cases to ensure correct handling of special numeric exponent values.

When a dimension_anomalies (or volume_anomalies with dimensions) test
detects failures across multiple dimension values, the alert description
previously only showed the last row's description. Now it shows each
failing dimension's details individually (up to 5), or a count summary
with a sample of dimension values when more than 5 dimensions fail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

👋 @joostboon
Thank you for raising your pull request.
Please make sure to add tests and document all user-facing changes.
You can do this by editing the docs files in the elementary repository.

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

📝 Walkthrough

Walkthrough

Adds two tests for dimension-anomaly alert descriptions, refactors anomaly result description generation to cap shown dimension values (max 5) and summarize excess, and tweaks Decimal exponent handling in adapter serialization. Duplicate test blocks appear in the diff context.

Changes

Cohort / File(s) Summary
Dimension Anomaly Tests
integration_tests/tests/test_dimension_anomalies.py
Adds two tests verifying alert description content for few (lists values) vs many (count-based summary) failing dimensions. Note: the new test function blocks appear duplicated in the diff context.
Anomaly Result Description Logic
macros/edr/data_monitoring/anomaly_detection/store_anomaly_test_results.sql
Replaces single-row description with aggregated logic: collects anomalous rows, introduces max_dimension_alerts = 5, lists up to the cap of dimension values or shows a "and N more" summary, and falls back to last description or "Not enough data..." when appropriate.
Decimal Serialization Fix
integration_tests/tests/adapter_query_runner.py
Computes Decimal exponent into a variable and handles string exponents (Infinity/NaN) by converting to float before numeric comparisons to ensure correct int/float casting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I nibble on anomalies as numbers prance,

Five I will name, or "and more" at a glance.
Tests hop to check each peculiar score,
Decimals tamed, descriptions no more.
A rabbit applauds this tidy advance!

🚥 Pre-merge checks | ✅ 3
✅ 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 'fix: per-dimension alert descriptions when multiple dimensions fail' directly summarizes the main change: improving alert descriptions for dimension anomalies tests to show per-dimension information rather than only the last failing dimension.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch worktree-fix-dimension-alerts
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@integration_tests/tests/test_dimension_anomalies.py`:
- Around line 357-389: Reformat the anomalous_dimensions list in
test_dimension_anomalies_alert_description_many_failures to satisfy Black
line-length rules (split items across multiple lines) and add runtime
diagnostics to debug why not all six heroes are flagged: before the final
assertion log the test_result["test_results_description"] and inspect the
anomaly scoring output used by the anomaly detection routine (check where
sensitivity is applied and the score->anomalous threshold is computed) for the
heroes in anomalous_dimensions; verify whether sensitivity=2 is appropriate or
whether the scoring calculation is suppressing scores below the anomalous
threshold and adjust the scoring or threshold logic accordingly so the macro
condition (">5") correctly triggers for six failing dimensions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: de59188d-8e4e-499a-a477-fac1b7d05334

📥 Commits

Reviewing files that changed from the base of the PR and between f820e11 and 57ccbb0.

📒 Files selected for processing (2)
  • integration_tests/tests/test_dimension_anomalies.py
  • macros/edr/data_monitoring/anomaly_detection/store_anomaly_test_results.sql

Comment on lines +357 to +389
def test_dimension_anomalies_alert_description_many_failures(
test_id: str, dbt_project: DbtProject
):
"""When >5 dimension values fail, description shows a count summary."""
utc_today = datetime.utcnow().date()
test_date, *training_dates = generate_dates(base_date=utc_today - timedelta(1))

# 6 dimension values all spike on test_date (>5 threshold)
anomalous_dimensions = ["Batman", "Superman", "Spiderman", "IronMan", "Thor", "Hulk"]

data: List[Dict[str, Any]] = [
{TIMESTAMP_COLUMN: test_date.strftime(DATE_FORMAT), "superhero": hero}
for hero in anomalous_dimensions
for _ in range(10)
]
data += [
{TIMESTAMP_COLUMN: cur_date.strftime(DATE_FORMAT), "superhero": hero}
for cur_date in training_dates
for hero in anomalous_dimensions
]

test_args = {
"timestamp_column": TIMESTAMP_COLUMN,
"dimensions": ["superhero"],
"sensitivity": 2,
}
test_result = dbt_project.test(test_id, DBT_TEST_NAME, test_args, data=data)
assert test_result["status"] == "fail"

description = test_result["test_results_description"]
# Should show the count summary for many failures
assert "dimension values are anomalous" in description, (
f"Expected summary message in description: {description}"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if the macro threshold logic is correct
rg -n "max_dimension_alerts" --type sql

# Verify the condition uses > not >=
rg -n "anomalous_rows.*length.*max_dimension_alerts" --type sql -A 2 -B 2

# Check if there are any existing tests that verify >5 threshold behavior
rg -n "dimension values are anomalous" integration_tests/

Repository: elementary-data/dbt-data-reliability

Length of output: 2518


🏁 Script executed:

#!/bin/bash

# Get more context of the test function
sed -n '340,395p' integration_tests/tests/test_dimension_anomalies.py

# Look at the anomaly detection macro logic in detail
cat -n macros/edr/data_monitoring/anomaly_detection/store_anomaly_test_results.sql | sed -n '80,110p'

# Check if there's a specific dimension anomaly detection macro
fd -t f "dimension" macros/ | head -20

Repository: elementary-data/dbt-data-reliability

Length of output: 4172


🏁 Script executed:

#!/bin/bash

# Find the dimension anomalies test macro
cat -n macros/edr/tests/test_dimension_anomalies.sql | head -100

# Check what DBT_TEST_NAME is in the test file
rg -n "DBT_TEST_NAME" integration_tests/tests/test_dimension_anomalies.py -B 5 | head -20

# Check if the test data generation uses helpers
rg -n "generate_dates\|DATE_FORMAT\|TIMESTAMP_COLUMN" integration_tests/tests/test_dimension_anomalies.py | head -20

Repository: elementary-data/dbt-data-reliability

Length of output: 5313


Fix Black formatting and investigate anomaly detection failure.

Two issues found:

  1. Black formatting violation (line 362): The anomalous_dimensions list must be reformatted to comply with Black's line length rules.

  2. Test assertion failure (lines 385-389): The test expects "dimension values are anomalous" in the description but it's not present. The macro logic is correct (threshold is 5, condition uses >), so the issue is that the anomaly detection algorithm is not detecting all 6 dimensions as anomalous despite the clear spike pattern. With sensitivity=2, investigate whether:

    • The sensitivity value is too strict for the data pattern
    • The anomaly scoring calculation is not generating high enough scores for all dimensions to exceed the anomalous threshold

Add a debug print before the assertion to see how many dimensions are actually detected:

print(f"DEBUG: description={description}")

Then inspect the anomaly scores being generated for each of the 6 dimensions during test execution to determine why some are not being flagged as anomalous.

Fix Black formatting
     # 6 dimension values all spike on test_date (>5 threshold)
-    anomalous_dimensions = ["Batman", "Superman", "Spiderman", "IronMan", "Thor", "Hulk"]
+    anomalous_dimensions = [
+        "Batman",
+        "Superman",
+        "Spiderman",
+        "IronMan",
+        "Thor",
+        "Hulk",
+    ]
🧰 Tools
🪛 GitHub Actions: Run pre-commit hooks

[error] 362-366: Black formatting: file reformatted by hook and changes applied. Run 'pre-commit run --all-files' to reproduce locally.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@integration_tests/tests/test_dimension_anomalies.py` around lines 357 - 389,
Reformat the anomalous_dimensions list in
test_dimension_anomalies_alert_description_many_failures to satisfy Black
line-length rules (split items across multiple lines) and add runtime
diagnostics to debug why not all six heroes are flagged: before the final
assertion log the test_result["test_results_description"] and inspect the
anomaly scoring output used by the anomaly detection routine (check where
sensitivity is applied and the score->anomalous threshold is computed) for the
heroes in anomalous_dimensions; verify whether sensitivity=2 is appropriate or
whether the scoring calculation is suppressing scores below the anomalous
threshold and adjust the scoring or threshold logic accordingly so the macro
condition (">5") correctly triggers for six failing dimensions.

- Reformat anomalous_dimensions list to satisfy Black 88-char line limit
- Fix TypeError in adapter_query_runner when Vertica returns Decimal
  special values (Infinity/NaN): as_tuple().exponent is a string ('F'/'n')
  for those cases, not an int, causing '>= not supported between str and int'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@joostboon
Copy link
Contributor Author

Thanks for the review! Fixed both issues in the latest commit:

  1. Black formatting: reformatted the anomalous_dimensions list in test_dimension_anomalies_alert_description_many_failures to stay within Black's 88-char line limit.

  2. Vertica TypeError: fixed adapter_query_runner.pyDecimal.as_tuple().exponent returns a string ('F' for Infinity, 'n' for NaN) rather than an int for special values, so the >= 0 comparison was raising TypeError. Added an isinstance(exponent, str) guard to convert those to float directly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
integration_tests/tests/test_dimension_anomalies.py (1)

395-397: ⚠️ Potential issue | 🟡 Minor

Apply Black’s assert formatting here to fix pre-commit.

The hook is still reformatting this assert block; commit the formatter output so CI stops failing.

Suggested formatting change
-    assert "dimension values are anomalous" in description, (
-        f"Expected summary message in description: {description}"
-    )
+    assert "dimension values are anomalous" in description, f"Expected summary message in description: {description}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@integration_tests/tests/test_dimension_anomalies.py` around lines 395 - 397,
Reformat the failing assert to match Black’s formatting and commit the change:
update the assert that checks for "dimension values are anomalous" in
description so the assertion message (f"Expected summary message in description:
{description}") is wrapped in parentheses and placed on its own line per Black’s
multiline assert style (i.e., the assert containing the literal "dimension
values are anomalous" and the f-string message should use Black’s
wrapped/multiline layout), then run Black or pre-commit and commit the resulting
file.
🧹 Nitpick comments (1)
integration_tests/tests/test_dimension_anomalies.py (1)

393-397: Strengthen the >5 summary assertion to validate count semantics.

Right now this only checks a generic substring. It should also assert the expected count/remainder text for this 6-dimension fixture.

Suggested assertion tightening
     description = test_result["test_results_description"]
     # Should show the count summary for many failures
-    assert "dimension values are anomalous" in description, (
-        f"Expected summary message in description: {description}"
-    )
+    assert "6 dimension values are anomalous." in description, f"Expected count summary in description: {description}"
+    assert "Showing first 5:" in description, f"Expected capped list summary in description: {description}"
+    assert "and 1 more." in description, f"Expected remainder summary in description: {description}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@integration_tests/tests/test_dimension_anomalies.py` around lines 393 - 397,
The test currently only checks that test_result["test_results_description"]
(variable description) contains "dimension values are anomalous"; tighten it by
asserting the expected count semantics for this 6-dimension fixture—e.g., add an
assertion that description also contains the concrete count phrase such as "5 of
6" or "5/6" (or the exact wording your app emits like "5 anomalous, 1 normal")
so the message confirms 5 anomalous out of 6 dimensions rather than just the
generic substring.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@integration_tests/tests/test_dimension_anomalies.py`:
- Around line 395-397: Reformat the failing assert to match Black’s formatting
and commit the change: update the assert that checks for "dimension values are
anomalous" in description so the assertion message (f"Expected summary message
in description: {description}") is wrapped in parentheses and placed on its own
line per Black’s multiline assert style (i.e., the assert containing the literal
"dimension values are anomalous" and the f-string message should use Black’s
wrapped/multiline layout), then run Black or pre-commit and commit the resulting
file.

---

Nitpick comments:
In `@integration_tests/tests/test_dimension_anomalies.py`:
- Around line 393-397: The test currently only checks that
test_result["test_results_description"] (variable description) contains
"dimension values are anomalous"; tighten it by asserting the expected count
semantics for this 6-dimension fixture—e.g., add an assertion that description
also contains the concrete count phrase such as "5 of 6" or "5/6" (or the exact
wording your app emits like "5 anomalous, 1 normal") so the message confirms 5
anomalous out of 6 dimensions rather than just the generic substring.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 69af3958-2dbc-42fd-83c1-59e767708153

📥 Commits

Reviewing files that changed from the base of the PR and between 57ccbb0 and 0eecf7d.

📒 Files selected for processing (2)
  • integration_tests/tests/adapter_query_runner.py
  • integration_tests/tests/test_dimension_anomalies.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
integration_tests/tests/test_dimension_anomalies.py (1)

393-397: Strengthen the >5 assertion to validate the full summary contract.

Right now the test only checks one substring, so it can still pass if count/cap wording regresses. Consider asserting count + cap + remainder too.

Proposed assertion hardening
     description = test_result["test_results_description"]
-    # Should show the count summary for many failures
-    assert (
-        "dimension values are anomalous" in description
-    ), f"Expected summary message in description: {description}"
+    # Should show the count-based summary for many failures
+    assert "6 dimension values are anomalous" in description, (
+        f"Expected anomalous count in description: {description}"
+    )
+    assert "Showing first 5" in description, (
+        f"Expected capped preview text in description: {description}"
+    )
+    assert "and 1 more." in description, (
+        f"Expected remaining-count text in description: {description}"
+    )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@integration_tests/tests/test_dimension_anomalies.py` around lines 393 - 397,
The current assertion only checks a substring in description; strengthen it to
validate the full summary contract by asserting count, cap and remainder are
present and correct: extract the numeric values from test_result (e.g. total
anomalies, cap limit and remainder or derive remainder = total - cap) and then
assert description matches the full summary format (either via a constructed
expected string or a regex) instead of only checking "dimension values are
anomalous"; use the existing variables test_result and description to locate and
verify the values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@integration_tests/tests/test_dimension_anomalies.py`:
- Around line 393-397: The current assertion only checks a substring in
description; strengthen it to validate the full summary contract by asserting
count, cap and remainder are present and correct: extract the numeric values
from test_result (e.g. total anomalies, cap limit and remainder or derive
remainder = total - cap) and then assert description matches the full summary
format (either via a constructed expected string or a regex) instead of only
checking "dimension values are anomalous"; use the existing variables
test_result and description to locate and verify the values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fc1a7bec-c0ef-4378-b2d6-546349c7dc53

📥 Commits

Reviewing files that changed from the base of the PR and between 0eecf7d and 892db60.

📒 Files selected for processing (1)
  • integration_tests/tests/test_dimension_anomalies.py

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