test(data): spike check for collab activity vs per-user trailing baseline (#1321)#1355
test(data): spike check for collab activity vs per-user trailing baseline (#1321)#1355SharedQA wants to merge 6 commits into
Conversation
…line (constructorfabric#1321) Follow-up to the non-negative business-rule test. Adds a data_quality catalog check for the "too high" case the non-negative test cannot catch: a count that is plausible on its own but wildly out of line with the same user's own recent history (e.g. a feeder double-count turning a few hundred views into millions). Deliberately not a fixed upper limit. The baseline is derived per (tenant, user, product, metric) from each series' own trailing 28 observed days (excluding the current day). A day is flagged only when all hold: >=14 prior observations (cold-start guard), non-zero baseline spread, value > mean + 5*sd, and value > 10*mean. The z-score and the relative-jump condition together keep it to genuinely large spikes. severity=warn + store_failures (advisory, monitored, non-blocking) per the data_quality convention, so a noisy or mis-tuned threshold can never fail a build while we calibrate it. Reads FINAL. Note: thresholds are conservative starting points, not yet calibrated against real tenant data (no warehouse available locally to run dbt). They are meant to be tuned from the first scheduled-run findings. Signed-off-by: Kenan Salim <kenan.salim@gmail.com>
…onstructorfabric#1321) Addresses two review points on the trailing-baseline spike check: - Performance: cap the input to the last 120 days (new `recent` CTE) and the output to the last 3 days. Filtering only the output would stop re-alerting on old spikes but the window function still sorts/scans all history; bounding the input is what actually keeps the cost flat as history grows. 120 days comfortably covers a 28-observed-day baseline for any active user; a user with <14 active days in the window isn't evaluated (the prior_n guard). - Stale baseline: the window is ROWS-based (observed days, not calendar days), so a user returning from a long leave would be compared against a months-old baseline. Add `date - prev_date <= 35` (prev_date = most recent prior observed day) so the baseline must itself be recent, removing that false-positive class. Still advisory (severity=warn) and uncalibrated; thresholds to be tuned from the first scheduled-run findings. Signed-off-by: Kenan Salim <kenan.salim@gmail.com>
|
Good catches — applied both, with one adjustment on the performance fix. 1. Full-table-scan / re-alerting. Filtering only the final
A user with fewer than 14 active days inside the 120-day window simply isn't evaluated, which the 2. Observed vs calendar days. You're right that Still |
|
Warning Review limit reached
More reviews will be available in 56 minutes and 52 seconds. Learn how PR review limits work. To continue reviewing without waiting, enable usage-based billing in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses rolling per-developer review limits. Reviews become available again as older review attempts age out of the rolling limit window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughA new dbt SQL test ChangesCollaboration Document Spike Detection Test
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/ingestion/dbt/tests/collaboration/assert_collab_document_counts_no_spike.sql`:
- Line 115: In the WHERE clause of the spike detection query in
assert_collab_document_counts_no_spike.sql, replace the filter condition that
uses activity date (the line with AND date >= today() - 3) with a filter on the
collection timestamp instead. Change the filter to use collected_at >= today() -
3 to ensure late-arriving backfill data is properly included in the spike
detection window. If collected_at is not available in the silver schema, use
_version >= today() - 3 as an alternative to capture the ReplacingMergeTree
update timestamp.
- Around line 43-96: The spike detection test is missing `insight_source_id`
from its partitioning grain, which allows activity from different M365 source
instances within the same tenant to share a contaminated baseline. Add
`insight_source_id` to the SELECT clause in each of the three CTEs (recent,
unpivoted, and baselined) and include it in the PARTITION BY clause of the
WINDOW w definition alongside the existing partition keys (tenant_id,
person_key, product, data_source, metric). This ensures each source instance
maintains its own isolated adaptive baseline for accurate spike detection.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 250adc65-335a-4768-959d-0ec51ee3c04e
📒 Files selected for processing (1)
src/ingestion/dbt/tests/collaboration/assert_collab_document_counts_no_spike.sql
…ion time (constructorfabric#1321) Address CodeRabbit review on PR constructorfabric#1355: - Add insight_source_id to the spike-detection grain (recent/unpivoted/ baselined CTEs, WINDOW PARTITION BY, and stored-failure output). Without it, multiple M365 source instances for one tenant share a contaminated baseline and failure rows can't identify which source to inspect. - Cap output by collected_at (row arrival) instead of activity date, so a late-arriving backfill landing today for an older activity date is still flagged — exactly the feeder/backfill anomaly class this check targets — rather than being silently dropped by the date filter. Both columns are present in class_collab_document_activity FINAL (insight_source_id is a documented not_null column; collected_at flows through from the m365 feeders via SELECT *). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ion time (constructorfabric#1321) Address CodeRabbit review on PR constructorfabric#1355: - Add insight_source_id to the spike-detection grain (recent/unpivoted/ baselined CTEs, WINDOW PARTITION BY, and stored-failure output). Without it, multiple M365 source instances for one tenant share a contaminated baseline and failure rows can't identify which source to inspect. - Cap output by collected_at (row arrival) instead of activity date, so a late-arriving backfill landing today for an older activity date is still flagged — exactly the feeder/backfill anomaly class this check targets — rather than being silently dropped by the date filter. Both columns are present in class_collab_document_activity FINAL (insight_source_id is a documented not_null column; collected_at flows through from the m365 feeders via SELECT *). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Kenan Salim <kenan.salim@rolos.com>
1033dc4 to
40065c7
Compare
…ion time (constructorfabric#1321) Address CodeRabbit review on PR constructorfabric#1355: - Add insight_source_id to the spike-detection grain (recent/unpivoted/ baselined CTEs, WINDOW PARTITION BY, and stored-failure output). Without it, multiple M365 source instances for one tenant share a contaminated baseline and failure rows can't identify which source to inspect. - Cap output by collected_at (row arrival) instead of activity date, so a late-arriving backfill landing today for an older activity date is still flagged — exactly the feeder/backfill anomaly class this check targets — rather than being silently dropped by the date filter. Both columns are present in class_collab_document_activity FINAL (insight_source_id is a documented not_null column; collected_at flows through from the m365 feeders via SELECT *). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Kenan Salim <kenan.salim@gmail.com>
…ion time (constructorfabric#1321) Address CodeRabbit review on PR constructorfabric#1355: - Add insight_source_id to the spike-detection grain (recent/unpivoted/ baselined CTEs, WINDOW PARTITION BY, and stored-failure output). Without it, multiple M365 source instances for one tenant share a contaminated baseline and failure rows can't identify which source to inspect. - Cap output by collected_at (row arrival) instead of activity date, so a late-arriving backfill landing today for an older activity date is still flagged — exactly the feeder/backfill anomaly class this check targets — rather than being silently dropped by the date filter. Both columns are present in class_collab_document_activity FINAL (insight_source_id is a documented not_null column; collected_at flows through from the m365 feeders via SELECT *). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Kenan Salim <kenan.salim@gmail.com>
3a97e98 to
d7e676a
Compare
Follow-up to the silver non-negative business-rule test. It guards the "too high" case the non-negative check can't see: a count that looks fine on its own but is wildly out of line with the same user's own recent history — the kind of jump a feeder double-count or a unit change produces.
Not a fixed limit. The baseline is computed per
(tenant, user, product, metric)from each series' own trailing 28 observed days (excluding the current day). A user-day is flagged only when all of these hold:value > mean + 5*stddev(z-score outlier)value > 10*mean(massive relative jump)The z-score and the relative-jump condition together keep it to genuinely large spikes, so it stays quiet on normal variation.
Safe by construction. It joins the
data_qualitycatalog asseverity=warn+store_failures— advisory and monitored, never blocks a build. ReadsFINAL.Why draft. The thresholds (28-day window, 14-day minimum, 5σ, 10×) are conservative starting points, not yet calibrated against real tenant data — there's no warehouse available locally to run dbt. The intent is to tune them from the first scheduled-run findings before marking ready. Review welcome on the method and the threshold choices.
Summary by CodeRabbit