Slackbot
03/25/2026, 6:47 PMkapa.ai
03/25/2026, 6:47 PMon-run-end hook taking several minutes is not unique to your setup — many Elementary users experience this.
Looking at your logs, the hook itself ran for ~211 seconds (~3.5 minutes), and there was also a ~3.5-minute gap before the hook started (from 183926 to 184257). This pre-start delay is actually the hook compiling, during which Elementary performs all its logic — the logs can be a bit misleading in this regard. [on-run-end delay] Why does it take so long? The on-run-end hook is responsible for several tasks: [on-run-end hooks]
• Uploading metadata about all resources in your project (models, tests, sources, etc.) to your warehouse
• Uploading run results (execution times, statuses, errors)
• Uploading invocation details
The duration correlates with the size of your project (number of models, tests, etc.), since it uploads all artifacts to the warehouse. [project size impact] How to reduce the duration Here are some options to improve performance:
1. Disable column auto-upload — this has been reported to be a major culprit, sometimes causing 30-minute runtimes:# in dbt_project.yml vars
disable_dbt_columns_autoupload: true[column upload fix]
2. *Disable artifact auto-upload and run it manually only on deployment:*# in dbt_project.yml vars
disable_dbt_artifacts_autoupload: trueThen run manually when needed:dbt run --select elementary.edr.dbt_artifacts[manual artifact upload]
3. Disable Elementary in non-production targets to avoid slowdowns during local developmentmodels
elementary:
+schema: "elementary"
+enabled: "{{ target.name == 'prod' }}"[prod-only setup]
> ⚠️ Note: Disabling artifact collection will affect features like edr report and edr monitor, so it's not recommended to disable everything unless necessary. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/25/2026, 6:49 PMkapa.ai
03/25/2026, 6:49 PMnow() or var()), the cache can be invalidated on every run, causing full re-uploads each time. [dynamic expressions]
So I'd recommend running Elementary a second time with no project changes and comparing the duration — that will give you a good baseline for what to expect going forward. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/25/2026, 6:53 PMkapa.ai
03/25/2026, 6:53 PMvolume_anomalies, column_anomalies, etc.) write historical metrics to the data_monitoring_metrics table as part of the test execution itself — not as part of the on-run-end hooks. This means even if you disable all upload hooks, those tests will still write to the database. [on-run-end hooks] What you can safely disable If you don't use edr report or alerts, you can disable all four upload hooks:
# dbt_project.yml
vars:
disable_dbt_artifacts_autoupload: true
disable_run_results: true
disable_tests_results: true
disable_dbt_invocation_autoupload: true
With these set:
• ✅ Elementary tests (anomaly detection, schema changes, etc.) will still run and execute normally
• ✅ Metrics needed for anomaly detection are still collected (written by the tests themselves)
• ❌ Test results won't be stored in Elementary tables for reporting
• ❌ edr report won't work correctly (but you said you don't use it) [on-run-end hooks] Important caveat You still need to have run dbt run -s elementary at least once to create the required Elementary tables (like data_monitoring_metrics). Without those tables existing, the tests themselves will fail. [Slack discussion]
So in summary: disabling the hooks is fine for your use case, but the Elementary tables must exist and the tests themselves will still perform their own database writes. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/25/2026, 6:56 PM# dbt_project.yml 2vars: 3 disable_dbt_artifacts_autoupload: true 4 disable_run_results: true 5 disable_tests_results: true 6 disable_dbt_invocation_autoupload: true
so i will reduce hook running time and my dynamic tests will still work ?kapa.ai
03/25/2026, 6:56 PMdata_monitoring_metrics) will still be collected — this happens as part of the test execution itself, not the hooks [Slack discussion]
• ❌ Test results won't be stored in Elementary tables for reporting/alerts
• ❌ edr report won't work correctly (which you've said you don't need)
One practical tip: instead of hardcoding true, you can use a target-based condition so hooks still run in production if needed in the future:
vars:
disable_dbt_artifacts_autoupload: "{{ target.name != 'prod' }}"
disable_run_results: "{{ target.name != 'prod' }}"
disable_tests_results: "{{ target.name != 'prod' }}"
disable_dbt_invocation_autoupload: "{{ target.name != 'prod' }}"
[limit hooks to prod]
Just remember: the Elementary tables (like data_monitoring_metrics) must already exist in your warehouse. If you haven't done so yet, run dbt run -s elementary once before disabling the hooks. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/27/2026, 7:12 AMproject_name parameters:
facebook_ad_insights has one dbt unique_id regardless of which project runs it
When you build for "Project 1", Elementary records metrics (row count, spend distribution) against that model ID
• When you next build for "Project 2", Elementary records different metrics against the same model ID
• The statistical baseline becomes a noisy mix of all projects: Project1 50k rows, then Project 2 2k rows, then Project 3 8k rows...
• Anomaly detection sees wild swings on every run and either: (a) fires false positives constantly, or (b) learns to accept wild variance and misses real anomalies
This is why you see Elementary failures in CI — the baselines are polluted.
Your options:
• Accept the noise and use Elementary tests as "soft" guardrails (set severity: warn instead of error so they don't block builds)
• Disable Elementary anomaly tests entirely if they're not providing signal — keep only standard dbt tests (unique, not_null, etc.)
• Per-project Elementary schemas (as you mentioned) — but this only helps if you also ensure each project's builds are isolated and consistent
so is it really safe to have 1 schema ?kapa.ai
03/27/2026, 7:12 AMdata_monitoring_metrics — e.g., project_1.orders vs project_2.orders. In that case, the metrics rows are separate and don't pollute each other. [anomaly tests discussion]
However, the concern raised in the answer you shared is specifically about a single dbt model unique_id being shared across all parameterized runs. If Elementary keys its metrics in data_monitoring_metrics by the dbt model's unique_id (rather than the actual output table name), then yes — metrics from project_1.orders, project_2.orders, etc. could be written under the same identifier, mixing baselines and making anomaly detection unreliable. What the knowledge sources do NOT confirm The knowledge sources do not explicitly clarify whether data_monitoring_metrics keys metrics by:
• The dbt model unique_id, or
• The actual resolved output table/schema name
This is the critical detail that determines whether your setup is safe. The knowledge sources only state that the table is incremental and that anomaly tests "do not rely on historical results but on historical metrics they already collected on the underlying monitored tables / columns." [anomaly tests discussion] Bottom line I cannot confidently confirm that a single Elementary schema is fully safe for your parameterized use case at scale, given this ambiguity. The concern about polluted baselines is legitimate and not ruled out by the available knowledge sources. I'd recommend:
1. Testing with a small number of parameterized runs and inspecting data_monitoring_metrics directly to see how rows are keyed.
2. Reaching out to the Elementary team directly for a definitive answer on this specific scenario. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/27/2026, 7:27 AMkapa.ai
03/27/2026, 7:27 AMdata_monitoring_metrics table, which is written to by the tests themselves during execution — not by the on-run-end hooks. As confirmed by Elementary support:
> _"Anomaly tests do not rely on historical results but on historical metrics they already collected on the underlying monitored tables / columns. These are stored in data_monitoring_metrics."_ [anomaly tests discussion]
So disabling these four vars has zero impact on anomaly detection accuracy or test execution. [on-run-end hooks] What you actually lose by disabling them Since you've said you don't use edr report or alerts, none of these affect your use case. [reduce on-run-end time] Summary • You don't need to disable them — tests work either way.
• If you do disable them, your anomaly tests remain fully accurate.
• The only reason to disable them is to reduce hook runtime, which based on your earlier logs was ~3.5 minutes. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
03/27/2026, 9:29 AMkapa.ai
03/27/2026, 9:29 AManomaly_sensitivity as a global var in `dbt_project.yml`:
vars:
anomaly_sensitivity: 3
This is confirmed as a supported approach. [anomaly_sensitivity global]
However, for min_training_set_size, the knowledge sources do not explicitly confirm it works reliably at the global vars level. What is confirmed is that it works at the test level:
models:
- name: your_model
tests:
- elementary.volume_anomalies:
min_training_set_size: 7 Important caveat on global vars There are known limitations with certain Elementary configs at the global vars level. Specifically, training_period and detection_period are documented as only reliably supported at the test level due to bugs. [training_period limitation]
The configuration priority order Elementary follows is: [tests configuration]
1. Test arguments (most specific, always wins)
2. Tests path config in dbt_project.yml
3. Model configuration
4. Path config under models in dbt_project.yml
5. Global vars in dbt_project.yml (least specific)
Bottom line: anomaly_sensitivity as a global var is confirmed to work. For min_training_set_size, to be safe, set it at the test level or model config level rather than relying on global vars, as the knowledge sources don't explicitly confirm it works globally. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/27/2026, 9:30 AMkapa.ai
03/27/2026, 9:30 AMdisable_dbt_invocation_autoupload says "Test outcomes stored in Elementary tables" but it should say "dbt invocation metadata". Here's the corrected version:
vars:
# Elementary: disable upload hooks (not needed since we don't use edr reporting)
disable_dbt_artifacts_autoupload: true # Auto-upload of project metadata (models, tests, sources)
disable_run_results: true # Model execution results stored in Elementary tables
disable_tests_results: true # Test outcomes stored in Elementary tables
disable_dbt_invocation_autoupload: true # dbt invocation metadata upload
# Elementary: anomaly detection configuration
anomaly_sensitivity: 3 # Sensitivity level for anomaly detection (1-5)
min_training_set_size: 7 # Minimum number of data points required for training
[on-run-end hooks] [reduce on-run-end time]
One caveat on min_training_set_size: as mentioned in our previous exchange, anomaly_sensitivity as a global var is confirmed to work, but min_training_set_size at the global vars level is not explicitly confirmed in the knowledge sources. If you notice it's not being respected, fall back to setting it at the test or model config level. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/27/2026, 9:32 AM--show-all-deprecations flag. You may also need to
run with --no-partial-parse as some deprecations are only encountered duringkapa.ai
03/27/2026, 9:32 AMelementary_column_anomalies_google_ads_insights_spend_in_usd__day__1__spend_date failed with 2 results — meaning Elementary detected 2 anomalous data points in the spend_in_usd column of your google_ads_insights model. What "Got 2 results" means This is expected Elementary behavior — it's not a bug. As confirmed by Elementary support:
> "1 result means that there is one anomalous value, 3 results means that there are 3. When there are 0 results == no anomalies == the test passes." [Slack discussion]
So Elementary found 2 time buckets (days) where spend_in_usd deviated significantly from the historical baseline. Possible causes 1. Genuine anomaly — your spend actually changed significantly on those 2 days compared to the training period average.
2. First few runs / insufficient training data — if this is an early run, the training baseline may not be stable yet. Elementary requires at least 7 data points (your configured min_training_set_size) to calculate anomalies. [Not enough data]
3. High sensitivity — with anomaly_sensitivity: 3 (your global config), the threshold is 3 standard deviations. If your spend data is naturally volatile, this may produce false positives. How to investigate Query the Elementary tables to see what's happening:
SELECT
metric_name,
latest_metric_value,
training_avg,
training_stddev,
anomaly_score,
is_anomaly
FROM your_schema.metrics_anomaly_score
WHERE full_table_name LIKE '%google_ads_insights%'
ORDER BY bucket_end DESC;
[Anomaly troubleshooting] Quick mitigations • Reduce false positives from small changes: add ignore_small_changes to your test config:- elementary.column_anomalies:
column_anomalies:
- sum
ignore_small_changes:
spike_failure_percent_threshold: 10
drop_failure_percent_threshold: 10
• Downgrade to warning while you tune the baseline:- elementary.column_anomalies:
config:
severity: warn
Also note: the hook now only took 26 seconds — a big improvement from your earlier 211-second run, likely because the disable vars you configured are working correctly. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/27/2026, 10:31 AMmin_training_set_size is effectively a dead parameter in the dbt macros.
Here's the evidence:
1. 1. It's accepted but never used in get_anomalies_test_configuration — the macro accepts min_training_set_size as a parameter (line 11) but never processes it or includes it in the returned test_configuration dict (lines 109-127).
2. 2. The SQL hardcodes the threshold at 1 — in get_anomaly_scores_query.sql, the only check is:
when {{ elementary.edr_normalize_stddev('training_stddev') }} is null then null
when training_set_size = 1 then null -- Single value case - no historical context for anomaly detection
when {{ elementary.edr_normalize_stddev('training_stddev') }} = 0 then 0 -- Stationary data case - valid, all values are identical
else (metric_value - training_avg) / ({{ elementary.edr_normalize_stddev('training_stddev') }})
It only returns null (skip anomaly detection) when training_set_size = 1. For training_set_size >= 2, it always computes the z-score. There is no check like when training_set_size < 7 then null.
3. 3. The "Not enough data" for Applovin — that only happened because Applovin had zero rows of data (the table was empty: CREATE TABLE (0.0 rows)), so there were literally no metrics to score. It wasn't because of min_training_set_size.
Bottom line: Setting min_training_set_size: 7 in dbt_project.yml or in test arguments does nothing in Elementary v0.23.0. The parameter is logged in runtime config but never enforced in the anomaly SQL.
Your actual options to fix this:
1. 1. Set severity: warn on all Elementary anomaly tests so they don't block builds while baselines stabilize:
- elementary.column_anomalies:
severity: warn
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
2. 2. Wait for baselines to build — after 14+ daily runs per project, the stddev will stabilize and the z-scores will normalize. Right now with only 2-3 data points, any variance produces extreme z-scores.
3. 3. Check if a newer version of Elementary actually enforces min_training_set_size in the SQL layer (this looks like it might be implemented in the Python CLI / edr side only, which you don't use).
Switch to Agent mode and I can add severity: warn to all Elementary anomaly tests across your YAML files.kapa.ai
03/27/2026, 10:31 AMmin_training_set_size is a documented and intended configuration parameter, and that Elementary support staff have referenced it as a real control:
> _"`min_training_set_size` is by default 14. As we truncate to full months, 426 days probably result in 13 buckets. You can change the default."_ [min_training_set_size discussion]
The knowledge sources also show a community member observing that with min_training_set_size: 3, the anomaly score was calculated on the 2nd run (not the 3rd), which was flagged as potentially unexpected behavior — consistent with your finding that enforcement may not work as documented. [volume anomalies discussion] What I cannot confirm My knowledge sources do not include Elementary v0.23.0 source code, so I cannot independently verify or refute your specific code-level findings about get_anomalies_test_configuration or get_anomaly_scores_query.sql. I won't speculate beyond what the sources say. What I'd recommend Your practical suggestion is well-grounded regardless:
- elementary.column_anomalies:
config:
severity: warn
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
Setting severity: warn while baselines stabilize is a confirmed best practice. [severity warn]
For the specific question of whether min_training_set_size is enforced in v0.23.0, I'd recommend raising this directly with the Elementary team — it's a version-specific implementation question that goes beyond what my knowledge sources can confirm.
> Note: I'm not able to switch to "Agent mode" or modify your YAML files — I'm a Q&A assistant only. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/28/2026, 7:26 AMkapa.ai
03/28/2026, 7:27 AMdetection_delay is exactly the right parameter for this. How to configure it Add detection_delay to your test:
data_tests:
- elementary.column_anomalies:
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
min_training_set_size: 7
anomaly_sensitivity: 3 How it works detection_delay retracts the detection window by the specified period. With count: 1 and period: day, Elementary will:
• Skip the most recent day (2026-03-08, today's potentially incomplete data)
• Evaluate anomalies on the day before that (2026-03-07, your last fully loaded day)
[detection_delay docs]
> "The duration for retracting the detection period. That's useful in cases which the latest data should be excluded from the test. For example, this can happen because of scheduling issues — if the test is running before the table is populated for some reason."
Note that detection_delay only works for tests that have a timestamp_column configured, which you already have. It does not affect training_period or detection_period. [detection_delay docs] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/28/2026, 7:33 AMkapa.ai
03/28/2026, 7:33 AMnull_count, null_percent
• String: min_length, max_length, average_length, missing_count, missing_percent
• Numeric: min, max, average, zero_count, zero_percent, standard_deviation, variance
It's a column-level test — multiple metrics tracked per column. Summary In your configs specifically, the volume_anomalies test will tell you if the number of rows per day in your table is anomalous, while the column_anomalies test will tell you if the values within a specific column (e.g., nulls, averages) are anomalous — they complement each other rather than overlap. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
03/28/2026, 7:52 AMcolumn_anomalies, volume_anomalies, freshness_anomalies) needs severity: warn right now. Without it, they'll keep failing your Airflow DAGs with false positives while the baseline builds up.
After 2-3 weeks of daily runs, you can remove severity: warn (or switch to severity: error) and the tests will work properly with a solid baseline.
Also while you're at it, add detection_delay: {period: day, count: 1} to column_anomalies and volume_anomalies tests — this is a permanent fix (not just baseline-related) to prevent incomplete current-day data from triggering false positives.
Switch to Agent mode and I'll do both changes across all ~60 tests in one pass.kapa.ai
03/28/2026, 7:52 AMseverity: warn on all Elementary anomaly tests
This prevents false positives from blocking your Airflow DAGs while the baseline stabilizes:
- elementary.column_anomalies:
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
config:
severity: warn
- elementary.volume_anomalies:
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
config:
severity: warn
[severity warn]
Alternatively, you can apply it globally in dbt_project.yml (though per-test is more reliable):
tests:
elementary:
+severity: warn
[global severity]
2. Keep detection_delay as a permanent fix for incomplete current-day data — this is unrelated to baseline stabilization and should stay long-term. [detection_delay docs] How long until the baseline stabilizes? Elementary needs at least 14 data points by default (min_training_set_size: 14) before anomaly detection is reliable. With daily runs, that's ~2 weeks. You've set min_training_set_size: 7, so it may stabilize faster, but the statistical baseline (stddev) will still be noisy with only a few data points. [min_training_set_size]
Once you have 2+ weeks of stable runs, you can switch back to severity: error for tests where you want hard failures.
> Note: I'm not able to switch to "Agent mode" or modify your YAML files directly — I'm a Q&A assistant only. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/28/2026, 7:55 AMmin_training_set_size: 7 does nothing in Elementary v0.23.0. It's a dead parameter. The SQL never checks it. Even if you wait a month, the parameter itself won't change behavior.
What actually matters is how many daily metric data points Elementary has accumulated in the data_monitoring_metrics table. Each time a test runs, it stores one metric row per day-bucket. The more historical rows, the more stable the rolling average and standard deviation become.
Here's the timeline:
• Day 1-3 (now): Z-scores are wildly unstable, almost everything triggers false positives
• Day 7-10: Baselines start to stabilize, most false positives disappear
• Day 14+: Solid baseline (Elementary's default days_back is 14), tests work reliably
You don't need to "wait" for anything to change in the code. The tests will naturally stop firing false positives as more metric history accumulates. The problem is that right now they're failing your Airflow DAGs and blocking pipelines.
That's why severity: warn is needed — it lets the tests run and collect metrics (building the baseline) without blocking your pipelines. After ~2 weeks, switch back to severity: error.
Switch to Agent mode and I'll handle all the YAML changes.kapa.ai
03/28/2026, 7:55 AMwhen training_set_size = 1 then null. For training_set_size >= 2, it always computes the z-score."_ [source code analysis]
So yes — setting min_training_set_size: 7 in your config currently does nothing in v0.23.0. On the timeline for baseline stabilization The knowledge sources confirm the general timeline:
• Elementary requires at least 7 training data points before anomaly calculations begin (hardcoded minimum) [Anomaly troubleshooting guide]
• The default training window is 14 days — after 14+ daily runs, the stddev stabilizes and z-scores normalize [source code analysis] What to do The recommended approach from the knowledge sources is:
1. Set severity: warn now to stop blocking pipelines while the baseline builds
2. Wait ~2 weeks for the baseline to stabilize
3. Switch back to severity: error once tests are reliable
- elementary.column_anomalies:
config:
severity: warn
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
The severity: warn approach is explicitly recommended by the Elementary team for exactly this situation. [source code analysis] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/28/2026, 7:57 AMmin_training_set_size really dead ???kapa.ai
03/28/2026, 7:57 AMtraining_set_size >= 2, it always computes the z-score. There is no check like when training_set_size < 7 then null."_ [source code analysis]
Additionally, another community member observed that with min_training_set_size: 3, the anomaly score was calculated on the 2nd run (not the 3rd), which is inconsistent with the documented behavior. [volume anomalies discussion] Evidence that it is (or was) a real parameter Elementary support staff have referenced it as a legitimate, working config:
> _"`min_training_set_size` is by default 14. You can change the default."_ [min_training_set_size discussion]
The official docs also document it as a supported configuration. [Anomaly troubleshooting guide] Bottom line The knowledge sources cannot definitively confirm or deny whether it works in your specific version. The code-level finding is from a community member, not the Elementary team. The safest path is:
1. Don't rely on min_training_set_size to prevent false positives — use severity: warn instead while the baseline builds.
2. Raise this directly with the Elementary team on GitHub or Slack, as it's a version-specific implementation question that warrants an official response. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 6:32 AM+schema: elementary, `+materialized: tableprofiles.yml`OKDedicated elementary profile pointing to kilo-dw.elementary datasetTest materialization overrideOK`macros/elementary_materialization.sql` correctly delegates to elementary.materialization_test_default() for dbt 1.8+Elementary tests in YAMLOK`freshness_anomalies`, volume_anomalies, column_anomalies configured across 15+ models
Critical Issues Found
Issue 1: All Elementary data collection is disabled
vars:
# elementary variables to disable the upload of artifacts and results to Elementary because we dont use edr reporting
disable_dbt_artifacts_autoupload: true
disable_run_results: true
disable_tests_results: true
disable_dbt_invocation_autoupload: true
This means:
Elementary anomaly detection tests do run and will pass/fail in dbt
But no historical results are persisted to Elementary tables (elementary_test_results, dbt_run_results, etc.)
You cannot use the Elementary dashboard, Slack alerts, or edr CLI for historical trend analysis
• The anomaly detection tests themselves rely on querying the source tables directly for their training data (not Elementary's own tables), so the tests themselves will still function. However, you lose all observability over test result trends over time.
Recommendation: At minimum, re-enable disable_tests_results: false so you get a persistent audit trail of anomaly detections. The elementary_test_results table is the foundation for any reporting.
Issue 2: No edr CLI / reporting pipeline exists
There is zero Elementary reporting infrastructure:
• No edr task in any Airflow DAG
• No Slack/email alert configuration
• No Elementary Cloud connection
• No scheduled report generation
The tests run silently — if an anomaly test fails, it only shows up as a dbt test failure in the Cosmos task logs. Nobody gets proactively notified.
Issue 3: Elementary profile lives in profile/profiles.yml (non-standard path)
dbt looks for profiles.yml in ~/.dbt/ by default, or the project root. Your file is at profile/profiles.yml. This works if Cosmos or your CI explicitly passes --profiles-dir profile/, but verify this is correctly configured in your Airflow Cosmos ProfileConfig.
3. Multi-Tenant / Templated Model Problem
How It Works Today
Your architecture runs the same model code per project via different `--vars`:
1. Airflow DAGs pass project_name=X (or shopify_project_name, amazon_project_name)
2. project_meta_data(X) resolves schema, backend_type, etc.
3. dynamic_source() builds raw table references from the registry
4. dynamic_source_exists() returns LIMIT 0 empty results when a source table doesn't exist
The Problem Scenario
Project A uses Facebook + Google Ads + LiveIntent. Project B uses only Google Ads. When the spend DAG runs for Project B:
1. facebook_ad_insights_stg compiles with dynamic_source_exists("facebook_ads_raw", "ad_insights") — if no Facebook connector exists for Project B, the stg model returns empty results
2. facebook_ad_insights builds on top — also empty
3. product_spend UNIONs everything — Facebook portion is empty, which is correct
4. But: the elementary.freshness_anomalies test on facebook_ad_insights will still run for Project B and detect "no fresh data" — triggering a false positive anomaly
Recommended Solutions (in order of preference)
Option 1: Conditional test enabling via config:enabled (Best for your setup)
Add a macro that checks whether a project actually uses a given platform:
{% macro project_uses_platform(platform) %}
{%- set project_name = var("project_name") -%}
{# Define platform-to-project mapping #}
{%- set platform_map = {
"facebook": ["RHEA", "RHEA Shopify", "BurnBox", "InnerFlo", ...],
"liveintent": ["RHEA", "BurnBox"],
"applovin": ["InnerFlo", "MindWalking", "Wordletic"],
...
} -%}
{{ return(project_name in platform_map.get(platform, [])) }}
{% endmacro %}
Then in your YAML:
data_tests:
- elementary.freshness_anomalies:
config:
enabled: "{{ project_uses_platform('facebook') }}"
arguments:
timestamp_column: spend_date
Option 2: Add platform flags to get_project_meta_data()
Extend your registry with explicit platform lists:
"RHEA": {
"schema_name": "rhea",
"backend_type": "ecommerce",
"marketing_platforms": ["facebook", "google_ads", "liveintent"],
...
}
Then tests can reference:
config:
enabled: "{{ 'facebook' in project_meta_data().get('marketing_platforms', []) }}"
This is the cleanest approach because platform configuration lives next to all other project metadata.
Option 3: Use where clauses on Elementary tests + min_training_set_size
For models where emptiness is expected, increase min_training_set_size so the test skips itself when there isn't enough data:
- elementary.freshness_anomalies:
min_training_set_size: 14 # Won't fire until 14 days of data exist
This is a lighter-weight workaround but less explicit.
Option 4: Source freshness overrides per project
Since your sources already use freshness: with error_after, you could set freshness: null dynamically for sources that don't apply to a project. However, source freshness is separate from Elementary anomaly tests, so this only partially solves the problem.kapa.ai
03/30/2026, 6:32 AMedr report won't work. However, they also confirm that anomaly detection tests themselves still function — metrics are written to data_monitoring_metrics by the tests directly, not by the hooks. [on-run-end hooks]
Elementary schema config
The recommended dbt_project.yml schema config is confirmed: [Elementary dbt package]
models:
elementary:
+schema: elementary
Multi-tenant / templated model problem
The knowledge sources explicitly confirm this is a known, unsupported pattern. Elementary artifacts are fully reloaded on each run, so parameterized runs sharing one Elementary schema will overwrite each other's artifacts. [multi-project schema] The baseline pollution issue described (Project A 50k rows, Project B 2k rows mixed under same model ID) is also confirmed as a real concern. [multi-tenant discussion]
severity: warn as a mitigation
Setting severity: warn on anomaly tests to avoid blocking builds while baselines stabilize is a confirmed best practice: [severity config]
- elementary.freshness_anomalies:
config:
severity: warn What I cannot confirm from my knowledge sources • Option 1 (conditional config: enabled via custom macro) — the knowledge sources do not explicitly confirm that config: enabled with a Jinja macro works reliably for Elementary tests specifically. This is a dbt-native feature, but I can't confirm Elementary-specific behavior here.
• min_training_set_size as a workaround (Option 3) — as established in our earlier conversation, this parameter appears to be ineffective in v0.23.0 based on community source code analysis. [source code analysis] The Cursor answer itself acknowledges this is a "lighter-weight workaround" — I'd treat it as unreliable.
• The edr CLI / reporting gaps and profiles path analysis — these are project-specific observations I cannot validate without access to your actual files. Key takeaway The most actionable and knowledge-source-backed recommendations are:
1. Keep severity: warn on all Elementary anomaly tests while baselines build
2. Be aware that the multi-tenant pattern is fundamentally problematic for Elementary — per-project schemas or accepting noisy baselines are your real options
3. Don't rely on min_training_set_size as a guard against false positives in v0.23.0
For the conditional test enabling strategy (Option 1/2), I'd recommend testing it in a non-prod environment first, as the knowledge sources don't explicitly confirm this pattern works as expected with Elementary tests. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 8:24 AMelementary profile pointing to kilo-dw.elementary dataset`elementary_materialization.sql`OKCritical override for dbt 1.8+ — correctly delegates to `elementary.materialization_test_default()`Disable-upload varsIntentionalAll four disable_* vars set to true
Your Question About edr Reports with Templates
You are partially right, but not entirely. Here is the nuance:
Why you disabled edr: You set these four vars in `dbt_project.yml`:
disable_dbt_artifacts_autoupload: true
disable_run_results: true
disable_tests_results: true
disable_dbt_invocation_autoupload: true
This means Elementary's internal tables (elementary_test_results, dbt_run_results, etc.) are empty. The edr CLI and Elementary Cloud both read from those tables, so they would show nothing. Your anomaly tests still run and pass/fail correctly within dbt test — they query the underlying data tables directly, not the Elementary results tables. So yes, your tests work correctly.
But you could have one report across all projects. Here's why: each of your Airflow DAGs runs with different --vars (different project_name, category_name). The tests execute against different schemas (e.g., rhea_shopify.orders_standardized vs burnbox.orders_standardized). If you re-enabled the result storage vars, Elementary would accumulate results from ALL runs into the single elementary dataset. An edr report would then show all projects' test results in one consolidated view, which is actually useful for a multi-tenant setup — you'd see "freshness_anomalies on bottom_line for Breakneck passed, but failed for Nefolld" in one place.
The practical challenge is that your DAGs run at different times, so a report generated mid-cycle would show stale results for categories that haven't run yet. The fix is simple: add a final Airflow task (after all DAGs) that runs edr report or edr send-report.
My recommendation: Re-enable at minimum disable_tests_results: false. The cost is negligible (small writes to Elementary tables), and it gives you:
Historical test result trends (was this anomaly new or recurring?)
• Slack/email alerting via edr send-report --slack-webhook
• The ability to add Elementary Cloud later if needed
Keep disable_dbt_artifacts_autoupload: true and disable_run_results: true if you don't need model execution metadata.kapa.ai
03/30/2026, 8:24 AMdisable_tests_results: false is well-grounded and supported by the knowledge sources. Here's what I can confirm: What the knowledge sources support Re-enabling only disable_tests_results is explicitly documented as a valid selective approach:
vars:
disable_dbt_artifacts_autoupload: true # keep disabled - not needed
disable_run_results: true # keep disabled - not needed
disable_tests_results: false # re-enable this one
disable_dbt_invocation_autoupload: true # keep disabled - not needed
This ensures only elementary_test_results is written to, while keeping the other uploads disabled. [on-run-end hooks]
Your anomaly tests will continue to work regardless — they depend on data_monitoring_metrics, not the results tables. [anomaly tests discussion] What I cannot confirm The claim that a single edr report would consolidate results across all your parameterized runs (different project_name vars) into one useful view is not explicitly confirmed in the knowledge sources. In fact, the knowledge sources warn that the multi-tenant/parameterized pattern causes artifact conflicts and is explicitly not supported by Elementary. [multi-project schema] My take The safe, incremental step is:
1. Re-enable disable_tests_results: false — low cost, gives you a historical audit trail of anomaly detections
2. Keep the other three vars disabled
3. Don't invest in edr report infrastructure yet until you've validated whether the multi-tenant results actually consolidate correctly in your setup — test it first with a small number of projects 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 8:26 AMkapa.ai
03/30/2026, 8:26 AMdbt_models, dbt_tests, dbt_sources, etc.) are fully reloaded on each run. So yes — if you run with project_1 vars, then project_2 vars, the second run overwrites the first. This is explicitly confirmed: [multi-project schema]
> "Some of our artifacts are tables which get reloaded each dbt run. The meaning of that is that if you have different models / tests / etc at your projects, running one will override the artifacts of the other." What does NOT get overwritten The results tables (elementary_test_results, dbt_run_results) are incremental — rows are appended, not replaced. So if you re-enable disable_tests_results: false, test results from project_1 and project_2 runs will both accumulate in the same table. [on-run-end hooks] The real caveat for your use case Since it's the same dbt project with the same model unique_id regardless of which --vars you pass, there's a risk of identifier clashes when trying to distinguish results per project in the consolidated table. The knowledge sources confirm this is a known issue and there's no clean built-in solution for it. [multi-tenant discussion] Bottom line • Re-enabling disable_tests_results: false does give you value — you get a persistent audit trail of pass/fail history across all runs
• But filtering by project in that audit trail will be difficult since all runs share the same model identifiers
• The artifact metadata tables will always reflect only the last run's project — no benefit there
So there is some benefit to re-enabling test results storage, but it's limited by the identifier clash problem inherent to your parameterized setup. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 8:29 AMkapa.ai
03/30/2026, 8:29 AM--vars per project, building into different schemas (e.g., project_1.orders, project_2.orders). The risk is that data_monitoring_metrics may mix metrics from different projects under the same model identifier, polluting the baseline. [multi-tenant discussion] What Actually Makes Anomaly Detection Work Elementary anomaly tests depend only on data_monitoring_metrics — not on any artifact or results tables. [anomaly tests discussion] So the quality of your anomaly detection comes down to:
1. Clean, isolated metric history per table — if project_1.orders and project_2.orders are stored as distinct entries in data_monitoring_metrics, detection works. If they're mixed under one ID, baselines are polluted.
2. Enough historical data points — at least ~14 daily runs for a stable baseline (the min_training_set_size parameter is ineffective in v0.23.0). [source code analysis] Recommended Test Configuration - elementary.volume_anomalies:
config:
severity: warn # keep as warn until ~2 weeks of baseline data
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1 # avoids false positives from incomplete current-day data
- elementary.column_anomalies:
config:
severity: warn
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
ignore_small_changes:
spike_failure_percent_threshold: 10
drop_failure_percent_threshold: 10 # reduces noise from minor fluctuations
[detection_delay docs] [anomaly params] The One Thing to Verify First Before anything else, query data_monitoring_metrics directly after running two different parameterized builds and check how rows are keyed — specifically whether project_1.orders and project_2.orders appear as distinct rows or share the same identifier. That single check will tell you whether a single Elementary schema is viable for your setup or not. The knowledge sources don't definitively confirm this either way for your specific pattern. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 8:33 AMkapa.ai
03/30/2026, 8:34 AManomaly_sensitivity and min_training_set_size can be set at:
1. Test level (most specific, always wins)
2. Model config level in schema.yml
3. Global vars level in dbt_project.yml (least specific)
[anomaly_sensitivity global]
Since you have one standardized model and one shared schema.yml, you can only define one value per parameter — there's no built-in way to say "use anomaly_sensitivity: 3 for project_1 and anomaly_sensitivity: 5 for `project_2`" within a single test definition. What might work (but is not confirmed) You could theoretically use env_var() inside test arguments:
- elementary.column_anomalies:
arguments:
anomaly_sensitivity: "{{ env_var('ANOMALY_SENSITIVITY', '3') | int }}"
Then set ANOMALY_SENSITIVITY per Airflow run via environment variables. However, the knowledge sources do not explicitly confirm that Jinja env_var() works inside Elementary test arguments — this is speculative and I cannot confirm it works. The honest answer The knowledge sources do not contain a supported solution for per-project test parameter differentiation when using a single shared schema.yml. This is a direct consequence of the multi-tenant/parameterized pattern that Elementary explicitly does not support cleanly. [multi-tenant discussion]
I'd recommend raising this specific question directly with the Elementary team on Slack or GitHub, as it requires an authoritative answer about whether env_var() is supported in test arguments. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 1:47 PMkapa.ai
03/30/2026, 1:47 PMelementary.freshness_anomalies splits your data into time buckets (daily in your config) and computes the maximum time without updates (in seconds) as the freshness value per bucket. It then compares recent buckets (the detection period, default last 2 days) against historical buckets (the training period, default 14 days) to detect anomalous delays. [freshness_anomalies docs]
In your config, it will:
1. Look at spend_date values over the last 14 days
2. Split into daily buckets
3. Compute max gap between updates per bucket
4. Flag the last 2 days as anomalous if the gap is significantly larger than historical norms Key difference from dbt source freshness [freshness comparison] Important caveat for your setup Since elementary.freshness_anomalies is anomaly-based, if liveintent_spend stops receiving data and that becomes the "new normal" across the training window, the test may eventually stop flagging it. It's best suited for detecting changes in update behavior (e.g., a daily feed suddenly stops), not for enforcing strict SLAs. [freshness behavior] Notes on your specific config • min_training_set_size: 7 — as discussed in our earlier conversation, this parameter appears to be ineffective in v0.23.0 based on community source code analysis.
• No detection_delay on freshness_anomalies — you've added it to column_anomalies but not to freshness_anomalies. If spend_date data for the current day is incomplete when the test runs, consider adding it here toodetection delay
period: day
count: 1
• Default anomaly_direction: spike — the test only alerts on delays (freshness getting worse), not on data arriving earlier than expected. This is the correct default for your use case. [freshness_anomalies docs] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
03/30/2026, 2:58 PMkapa.ai
03/30/2026, 2:58 PMelementary.freshness_anomalies would behave with your setup. How it works step by step 1. Data is split into daily buckets With time_bucket: period: day, count: 1, Elementary groups your data by userid_created_at into 1-day buckets. [freshness_anomalies docs] 2. Freshness metric is computed per bucket For each daily bucket, Elementary computes the maximum time gap without updates (in seconds) within that bucket. This is the "freshness value" for that day. [freshness_anomalies docs] 3. Training period builds the baseline The last 14 days of daily buckets (default training_period) are used to calculate the expected range — the average and standard deviation of the freshness metric across those days. 4. Detection delay shifts the window back With detection_delay: period: day, count: 1, Elementary skips the most recent day (today's potentially incomplete data) and evaluates anomalies on the day before that. [detection_delay docs] 5. Detection period is checked for anomalies The default detection period is the last 2 days (shifted back by 1 day due to your delay). If the freshness value in that window is more than 3 standard deviations (anomaly_sensitivity: 3) above the training average, the test fails. 6. Only spikes are flagged The default anomaly_direction: spike means the test only alerts on delays (freshness getting worse — longer gaps between updates), not on data arriving earlier than expected. [freshness_anomalies config] Practical example If your table normally updates every day with a max gap of userid_created_at values or row counts per day), I can give you a more concrete walkthrough of what Elementary would compute. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 3:39 PM# elementary variables to disable the upload of artifacts and results to Elementary because we dont use edr reporting
disable_dbt_artifacts_autoupload: true # Auto-upload of project metadata (models, tests, sources)
disable_run_results: true # Model execution results stored in Elementary tables
disable_tests_results: true # Test outcomes stored in Elementary tables
disable_dbt_invocation_autoupload: true # Test outcomes stored in Elementary tables
can be related with SELECT
*
FROM elementary.data_monitoring_metrics
last data that i have is from 2026-03-25
today is 2026-03-30
if i dont have tada in that table, how i should know whats wrong with my tests ?kapa.ai
03/30/2026, 3:40 PMdata_monitoring_metrics. [on-run-end hooks]
As confirmed by Elementary support:
> _"Inserts to data_monitoring_metrics are a part of the anomaly tests - they cannot be disabled if you wish to use elementary anomaly tests... you will still see the post-run-end hook running, as its all running in the same hook, but the dbt artifacts will not be uploaded."_ [Slack discussion]
So if data_monitoring_metrics has no data since 2026-03-25, the disable vars are not the cause. Why data_monitoring_metrics might be stale More likely causes:
1. Your Elementary anomaly tests haven't been running since 2026-03-25 — check if your Airflow DAGs have been executing dbt test successfully.
2. The Elementary tables got into a bad state — try a full refresh:dbt run --select elementary --full-refresh --vars '{ "elementary_full_refresh": true }'[incremental fix]
3. The on-run-end hook failed before writing metrics — check your dbt.log for lines like Elementary: Uploading test results. If missing, the hook didn't complete. [on-run-end behavior] How to diagnose test failures without data_monitoring_metrics Since disable_tests_results: true is set, you also won't have data in elementary_test_results. Your only visibility into test failures right now is dbt run logs (e.g., Airflow task logs showing FAIL results).
This is exactly why re-enabling disable_tests_results: false was recommended in our earlier conversation — it gives you a persistent audit trail of anomaly detections without affecting test execution or the other disabled uploads. [on-run-end hooks] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 3:43 PMkapa.ai
03/30/2026, 3:43 PMcolumn_anomalies test on item_amount_in_usd detected 1 anomalous data point and returned 1 result — which dbt treats as a test failure (any result != 0 = fail). Cosmos then propagates that dbt failure as a task exception.
This is expected Elementary behavior, not a bug. As confirmed by Elementary support:
> "1 result means that there is one anomalous value. When there are 0 results == no anomalies == the test passes." [Slack discussion] Why it's likely a false positive As we discussed earlier, your tests were pushed to prod recently and the baseline is still stabilizing. With only a few days of data, the standard deviation is unstable and almost any variance produces extreme z-scores. [source code analysis] The immediate fix Change severity to warn so the test still runs and collects metrics (building the baseline) without blocking your Airflow DAG:
- elementary.column_anomalies:
config:
severity: warn
arguments:
timestamp_column: created_at
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
min_training_set_size: 7
anomaly_sensitivity: 3
With severity: warn, Cosmos will log the anomaly as a warning but won't raise a CosmosDbtRunError, so your DAG won't fail.
After ~2 weeks of daily runs, the baseline will stabilize and you can switch back to severity: error for tests where you want hard failures. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 3:47 PMkapa.ai
03/30/2026, 3:47 PMcompiled code at target/compiled/dwh_core/models/staging/amazon/items/_amazon_items_model.yml/elementary_column_anomalies_am_a622ab5e25174dbb319830f800209951.sql
If you have access to the filesystem where dbt runs, you can open that file directly. [compiled code location] 2. elementary_test_results table — test_results_query column SELECT test_results_query
FROM your_schema.elementary_test_results
WHERE test_name LIKE '%column_anomalies_amazon_items%'
ORDER BY created_at DESC
LIMIT 1;
This column contains the SQL query used for the test result. [test_results_query]
> ⚠️ Caveat: Since you have disable_tests_results: true, this table won't have data. You'd need to re-enable it first. 3. metrics_anomaly_score view — see the actual values This is the most useful for understanding why the test failed:
SELECT
metric_name,
metric_value,
training_avg,
training_stddev,
zscore,
severity
FROM your_schema.metrics_anomaly_score
WHERE table_name LIKE '%amazon_items%'
ORDER BY detected_at DESC;
This shows you the actual metric value, the historical average, standard deviation, and the z-score that triggered the failure. [anomaly troubleshooting] 4. data_monitoring_metrics — raw historical metrics SELECT
metric_timestamp,
metric_value,
metric_name
FROM your_schema.data_monitoring_metrics
WHERE table_name LIKE '%amazon_items%'
AND column_name = 'item_amount_in_usd'
ORDER BY metric_timestamp DESC;
This shows you the time series of collected values, so you can see if the anomaly is a genuine spike or just baseline instability. [anomaly troubleshooting] Given that data_monitoring_metrics had no data since 2026-03-25 (as you mentioned earlier), I'd start with option 1 (the compiled file) to see the SQL, and then check option 3 (metrics_anomaly_score) to understand the actual values driving the failure. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/30/2026, 3:49 PMkapa.ai
03/30/2026, 3:49 PMelementary_test_results, dbt_run_results, and dbt_invocations are empty — those are controlled by the hooks. However, as I clarified in my previous message, data_monitoring_metrics is NOT affected by those vars.
Here's the breakdown: This is confirmed by Elementary support:
> _"Inserts to data_monitoring_metrics are a part of the anomaly tests - they cannot be disabled if you wish to use elementary anomaly tests."_ [Slack discussion]
So if data_monitoring_metrics has no data since 2026-03-25, the cause is something else — most likely your anomaly tests haven't been running since that date, or the Elementary tables got into a bad state. Check your Airflow DAG run history to confirm whether dbt test has been executing successfully since then. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
03/30/2026, 5:19 PMkapa.ai
03/30/2026, 5:20 PM- elementary.column_anomalies:
config:
severity: warn
arguments:
timestamp_column: spend_date
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
column_anomalies:
- null_count
- null_percent
- sum
- zero_count
- zero_percent
[column_anomalies docs] [column monitors config] Why these specific monitors What you can safely skip for revenue The key insight from the docs is that sum is the most meaningful monitor for revenue but requires explicit opt-in since it's not in the default set. [column monitors config] 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
03/30/2026, 5:56 PMkapa.ai
03/30/2026, 5:56 PM2026-03-28 00:00 → 2026-03-29 00:00, Elementary measured a freshness gap of 119,184 seconds (~33 hours) without updates. The training average is only 25,952 seconds (~7.2 hours), giving an anomaly score of 3.25 — just above your anomaly_sensitivity: 3 threshold.
• Root cause: Your table normally updates every ~7 hours, but on 2026-03-27 the last update was at 14:53 UTC, meaning the rest of that day had no new data — a genuine or near-genuine anomaly. Parameters you can tune 1. Raise anomaly_sensitivity to reduce false positives Your score was 3.25 with a threshold of 3.0 — very close to the boundary. Raising sensitivity slightly will absorb minor deviations:
- elementary.freshness_anomalies:
arguments:
timestamp_column: userid_created_at
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
anomaly_sensitivity: 4 # was 3, raises the threshold
[anomaly_sensitivity docs] 2. Add ignore_small_changes to tolerate moderate spikes If a 33-hour gap is acceptable for your use case, you can set a percent threshold:
- elementary.freshness_anomalies:
arguments:
timestamp_column: userid_created_at
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
anomaly_sensitivity: 3
ignore_small_changes:
spike_failure_percent_threshold: 50 # only fail if freshness spikes >50% above expected
[ignore_small_changes docs] 3. Change time_bucket to match your actual update frequency Since your table updates every ~7 hours, using a daily bucket means a single late update can look like a 33-hour gap. Switching to hourly buckets would give Elementary a more granular and accurate baseline:
time_bucket:
period: hour
count: 6 # or count: 8 to match ~7h update cadence
[time_bucket docs]
> ⚠️ Note from a community member: if you use detection_delay with hourly buckets, make sure the detection_delay unit also matches — mixing period: day delay with period: hour buckets can cause unexpected behavior. [Slack discussion] 4. Set severity: warn while tuning While you're adjusting parameters, keep severity: warn to avoid blocking your Airflow DAGs:
config:
severity: warn My recommendation: Start with anomaly_sensitivity: 4 — your score was only 3.25, so this is the least invasive change. If the table genuinely shouldn't go 33 hours without updates, the alert may actually be correct and you should investigate the upstream data pipeline instead. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
03/31/2026, 7:06 AMkapa.ai
03/31/2026, 7:06 AM--vars (e.g., category_name: project_1, project_2, etc.). Elementary treats all these runs as the same project because they share the same dbt_project.yml and the same model `unique_id`s. [multi-tenant discussion] 2. Artifact tables are overwritten on every run The metadata tables (dbt_models, dbt_tests, dbt_sources) are fully reloaded on each run — so whichever parameterized run executes last overwrites all previous ones. This means an edr report would only reflect the last project that ran, not all projects. [multi-project schema] 3. You've disabled all result uploads With your current vars:
disable_dbt_artifacts_autoupload: true
disable_run_results: true
disable_tests_results: true
disable_dbt_invocation_autoupload: true
The edr report would show nothing — all the tables it reads from are empty. [on-run-end hooks] 4. Identifier clashes prevent per-project separation Since all parameterized runs share the same model unique_id, even if you re-enabled result uploads, you couldn't reliably filter results by project in the report — there's no built-in mechanism to distinguish project_1.orders from project_2.orders when they share the same dbt identifier. [multi-tenant discussion] 5. The community workaround doesn't scale to your case The suggested workaround (separate Elementary schema per run + union_elementary_schema) was described as "cumbersome" even for 5 projects, and explicitly flagged as not scaling to 500 projects. [community workaround] What You Can Do Bottom line: For your scale and architecture, edr reports per project are not practically viable with Elementary OSS. Your current approach — using Elementary purely for anomaly detection tests without edr reporting — is the most realistic path forward. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementskapa.ai
03/31/2026, 7:08 AMproject_1.orders, project_2.orders). What Changes With Distinct Schemas and Unique IDs Your clarification is important. If each parameterized run produces genuinely distinct table identifiers (different schemas, different table names), then the artifact overwrite problem is partially mitigated for data_monitoring_metrics — metrics rows are keyed per table/column, so project_1.orders and project_2.orders would coexist as separate rows. [anomaly tests discussion]
However, the dbt model unique_id is still derived from the project name and model name in dbt_project.yml — not from the output schema. Since you have one model definition, all parameterized runs share the same dbt unique_id, regardless of where the output table lands. Why edr Reports Per Project Still Don't Work 1. Artifact metadata tables are still overwritten dbt_models, dbt_tests, dbt_sources are fully reloaded on each run and reflect only the last project that ran. The edr report reads lineage and model metadata from these tables — so it would only ever show one project's context. [multi-project schema] 2. No per-project filtering in the report UI Even if you re-enabled result uploads, the edr report has no built-in mechanism to filter by --vars or parameterized run. The sidebar separates by project name — and since all your runs share the same dbt_project.yml project name, they'd all appear as one. [multi-tenant discussion]
The only suggested mitigation — making the project name dynamic in `dbt_project.yml`:
name: 'my_project_{{ env_var("category_name") }}'
— was flagged by Elementary staff as a workaround with its own maintenance overhead and is not officially supported. [multi-tenant discussion] 3. You've disabled all result uploads With your current vars, edr report tables are empty regardless. Re-enabling them is a prerequisite, but not sufficient on its own. [on-run-end hooks] 4. The union workaround doesn't scale The community workaround (separate Elementary schema per run + UNION ALL into a consolidated schema) was described as "cumbersome" for just 5 projects and explicitly not scalable to your volume. [community workaround] Summary Table Bottom line: Your current approach — Elementary for anomaly detection tests only, no edr reporting — remains the most practical path for your parameterized, multi-project architecture with Elementary OSS. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
03/31/2026, 7:09 AMkapa.ai
03/31/2026, 7:10 AMdbt build --vars '{"category_name": "project_1"}' produces:
• A distinct output table (e.g., project_1.orders, project_2.orders) — different schemas
• But all runs share the same dbt unique_id derived from the single model definition in dbt_project.yml
This distinction matters for different parts of Elementary. Why edr Reports Per Project Still Don't Work 1. Artifact metadata tables are overwritten on every run dbt_models, dbt_tests, dbt_sources are fully reloaded on each run and reflect only the last project that ran. The edr report reads lineage and model metadata from these tables — so it would only ever show one project's context at a time. [multi-project schema] 2. No per-project filtering in the report UI The edr report sidebar separates by dbt project name — and since all your parameterized runs share the same dbt_project.yml project name, they all appear as one. There is no built-in mechanism to filter by --vars or parameterized run. [multi-tenant discussion]
The only suggested mitigation is making the project name dynamic:
name: 'my_project_{{ env_var("category_name") }}'
But Elementary staff explicitly flagged this as unsupported and carrying its own maintenance overhead. [multi-tenant discussion] 3. You've disabled all result uploads With your current vars, all edr report tables are empty. Re-enabling them is a prerequisite, but not sufficient on its own. [on-run-end hooks] 4. The union workaround doesn't scale The community workaround (separate Elementary schema per run + UNION ALL) was described as "cumbersome" for just 5 projects and explicitly not scalable to your volume. [community workaround] What Your Distinct Schemas DO Help With Since each parameterized run produces genuinely distinct table identifiers, data_monitoring_metrics rows are keyed per table/column — so project_1.orders and project_2.orders coexist as separate rows without overwriting each other. This is why your anomaly tests work correctly today even with a single Elementary schema. [anomaly tests discussion] Summary Bottom line: Your current approach — Elementary for anomaly detection tests only, no edr reporting — is the most practical and realistic path for your parameterized architecture with Elementary OSS. The distinct schemas per project help your tests work correctly, but they don't solve the edr report limitations. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
04/07/2026, 8:28 AMkapa.ai
04/07/2026, 8:28 AMtest_result_samples is likely stored as part of the elementary_test_results table, which you currently have disabled (disable_tests_results: true). If that's the case, the feature won't work at all until you re-enable it.
• Since your parameterized runs produce distinct table identifiers per project (e.g., project_1.orders, project_2.orders), result rows written to elementary_test_results would be keyed per those distinct tables — meaning a single schema could accumulate samples from all projects without overwriting. [on-run-end hooks]
• However, since all runs share the same dbt unique_id, filtering or attributing samples per project in any report UI would still be problematic. [multi-tenant discussion]
My recommendation:
Check the test result samples docs directly to confirm which table this feature writes to, then cross-reference with whether that table is affected by your disable vars. If it's part of elementary_test_results, re-enabling disable_tests_results: false would be the prerequisite.
I'd also recommend asking the Elementary team directly on Slack for a definitive answer on this specific feature in a parameterized/multi-project setup. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
04/07/2026, 8:29 AMkapa.ai
04/07/2026, 8:30 AMproject_1.orders, project_2.orders), the data_monitoring_metrics table — which is the only one that matters for your anomaly tests — will not be overwritten. Each project's metrics coexist as separate rows.
The artifact metadata tables (dbt_models, etc.) will be overwritten, but since you don't use edr reports, this doesn't affect you. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
04/07/2026, 8:34 AMkapa.ai
04/07/2026, 8:34 AMtest_result_rows table as JSON, with each row containing:
SELECT
id, -- Unique identifier for the sample row
test_result_id, -- Links to elementary_test_results
result_row, -- The actual failing row data, stored as JSON
detected_at,
created_at
FROM your_schema.test_result_rows;
[test_result_rows docs] Key Behavior • Default: 5 sample rows per failed test
• Anomaly tests: Store an aggregate per time bucket (not individual failing rows)
• Non-anomaly tests: Store actual failing rows as JSON
[Test Result Samples] Important for Your Setup Since you have disable_tests_results: true, the test_result_rows table will be empty — samples are written as part of the same on-run-end hook that populates elementary_test_results. You'd need to re-enable disable_tests_results: false to see any samples.
The knowledge sources don't include a concrete screenshot or data example of what the JSON in result_row looks like for a specific test type, so I can't show you a precise sample output beyond what's described above. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.Rokas Marcinkevičius
04/20/2026, 2:32 PMkapa.ai
04/20/2026, 2:32 PM- elementary.column_anomalies:
config:
severity: warn
arguments:
timestamp_column: spend_date
time_bucket:
period: day
count: 1
detection_delay:
period: day
count: 1
column_anomalies:
- sum
- null_count
- zero_count
ignore_small_changes:
spike_failure_percent_threshold: 30
drop_failure_percent_threshold: 30
This tells Elementary to only flag anomalies where the value changed by more than 30% relative to the expected range — absorbing gradual scaling without missing real data issues. [ignore_small_changes docs] 2. Raise anomaly_sensitivity to reduce borderline triggers Your current anomaly_sensitivity: 3 means anything beyond 3 standard deviations triggers an alert. For volatile revenue/spend data, raising this reduces noise:
anomaly_sensitivity: 4 # or 5 for very volatile products
[anomaly_sensitivity docs] 3. Use config: enabled with a disabled_features variable for products that stop spending You're already using this pattern in your YAML:
- elementary.freshness_anomalies:
config:
enabled: "{{ 'liveintent_spend' not in var('disabled_features', []) }}"
Extend this to handle products that go inactive — when a product stops spending, add it to disabled_features in your Airflow DAG vars to suppress tests until it resumes. This is the cleanest approach for start/stop events. 4. Keep severity: warn as a permanent safety valve For products that are known to be volatile or in a scaling phase, keeping severity: warn means anomalies are logged but don't block your pipelines:
config:
severity: warn
[severity warn] 5. Use detection_delay to avoid incomplete-day false alarms You already have this in some tests — make sure it's on all anomaly tests to avoid triggering on partial current-day data:
detection_delay:
period: day
count: 1
[detection_delay docs] What You Cannot Easily Do Since you have one shared schema.yml for all projects, you cannot set different anomaly_sensitivity values per product without a workaround (e.g., env_var() passed per Airflow run — but this is not confirmed to work in Elementary test arguments). [multi-tenant discussion] Summary Priority 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help., with interactive elementsRokas Marcinkevičius
04/20/2026, 3:04 PM"monitoring": {
"enabled": true,
"lifecycle_state": "stable",
"monitor_from_date": "2024-10-15",
"expected_seasonality": "weekly",
"volume_sensitivity": 4,
"freshness_sensitivity": 5,
"column_sensitivity": 5,
"training_days": 35,
"exclude_weekends": false,
"business_hours_only": false,
"warn_only": true
}
to each product and then elementary would took everything individualy for each productkapa.ai
04/20/2026, 3:05 PMvolume_sensitivity, freshness_sensitivity, training_days, etc. to individual test configurations per product. What Elementary Actually Supports Elementary reads test parameters from:
1. Test-level arguments in schema.yml
2. Model config level (config: elementary: ...) in schema.yml
3. Global vars in dbt_project.yml
There is no built-in mechanism to define a custom metadata block per product/project that Elementary would automatically pick up and apply to its tests. [anomaly tests discussion] Why This Is Especially Hard in Your Setup Since you use one standardized model and one shared schema.yml for all projects, you can only define one value per parameter. The knowledge sources confirm there is no supported solution for per-project test parameter differentiation in a single shared schema.yml. [multi-tenant discussion] What You Could Theoretically Do (Unconfirmed) You could build a custom macro that reads from a metadata registry (similar to your existing get_project_meta_data() pattern) and injects values via env_var() or `var()`:
- elementary.volume_anomalies:
config:
severity: "{{ 'warn' if var('warn_only', true) else 'error' }}"
arguments:
timestamp_column: created_at
anomaly_sensitivity: "{{ var('volume_sensitivity', 3) }}"
Then pass per-product values via Airflow --vars. However, the knowledge sources do not explicitly confirm that Jinja expressions work inside Elementary test arguments for all parameters — this is speculative. [multi-tenant discussion] Honest Bottom Line The metadata-driven monitoring config you're describing is a product-level feature that Elementary OSS does not currently support. The knowledge sources suggest this kind of per-asset automated monitoring configuration is available in Elementary Cloud (automated monitors on all assets), but not in the OSS dbt package. [cloud monitors]
I'd recommend raising this as a feature request directly with the Elementary team on GitHub or Slack. 👍 0 button 👎 0 button ℹ️ Tip: Mention @elementary.ai in the thread for follow-ups or DM the app for 1-to-1 help.