Skip to content

feat: column roles gate all value-distribution detectors (1.1.0)#63

Merged
copyleftdev merged 2 commits into
mainfrom
feat/roles-all-detectors
Jun 1, 2026
Merged

feat: column roles gate all value-distribution detectors (1.1.0)#63
copyleftdev merged 2 commits into
mainfrom
feat/roles-all-detectors

Conversation

@copyleftdev

@copyleftdev copyleftdev commented Jun 1, 2026

Copy link
Copy Markdown
Owner

What

Extends column-role awareness from point.modz alone to every value-distribution detector. ctx.seasonal, coll.cusum, dist.ks / dist.psi / dist.chi2, and mv.mahalanobis now skip identifier and sequence columns (mv excludes them from its feature matrix). A seasonal subseries, level-shift, drift test, or joint distance over arbitrary ids or a monotonic ramp is noise, not signal.

This closes the gap noted in 1.0.1: on real syslog, coll.cusum still flagged a shift in the procid column. Now it doesn't.

Out of scope (deliberately): struct.schema stays role-agnostic — null-rate and schema-diff are meaningful for any column — and cad.regularity only ever operates on the explicitly-named --cadence column.

A shared Role::skips_value_detection() (Identifier | Sequence) centralizes the rule; point was refactored onto it too.

Contract

Changes detector output when column_roles = true, so the config_version fingerprint is bumped anomalyx-cfg/8 → /9 (per the 0.8.0 precedent). Envelope shape and PROTOCOL unchanged; --no-column-roles restores pre-roles behavior across all detectors. Goldens re-blessed for the new fingerprint (the only diffs: config_version, and mv's absence reason now that the id column isn't a feature — caught by the golden tripwire).

Gate

proptest + cargo-mutants 0 missed across all 6 changed files (roles.rs 37 caught; ctx/coll/mv 109; point/dist 187 + 10 loop-bound ks_statistic timeouts). Added a role-skip test per detector (each: roles-on skips, --no-column-roles assesses).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Detectors now skip identifier and sequence columns when column_roles is enabled, changing analysis scope and outputs
    • Added --no-column-roles command-line option to restore previous detection behavior
  • Chores

    • Bumped version to 1.1.0
    • Updated configuration version fingerprint; outputs may differ from prior versions

Role-based skipping now applies to every value-distribution detector, not just
point.modz: ctx.seasonal, coll.cusum, dist.ks/psi/chi2, and mv.mahalanobis skip
identifier/sequence columns (mv excludes them from the feature matrix). A
seasonal subseries / level-shift / drift test / joint distance over arbitrary
ids or a monotonic ramp is noise — this closes the gap noted in 1.0.1 where
coll.cusum still flagged a syslog procid shift. struct.schema stays role-agnostic
(null-rate/schema-diff meaningful for any column); cad.regularity uses only the
explicit --cadence column. Shared Role::skips_value_detection() centralizes it.

Changes detector output for column_roles=true → config_version bumped
anomalyx-cfg/8→/9. Envelope/PROTOCOL unchanged; --no-column-roles restores
pre-roles behavior everywhere. Goldens re-blessed for the new fingerprint.

Gates: proptest + cargo-mutants 0-missed on all 6 changed files (roles 37 caught;
ctx/coll/mv 109; point/dist 187 + 10 loop-bound timeouts). Added role-skip tests
per detector.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@copyleftdev, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 48 minutes and 2 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b0602452-ff72-4406-a9b6-2667c45ac1d6

📥 Commits

Reviewing files that changed from the base of the PR and between f5ffbad and 8f50106.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • crates/ax-normalize/tests/robustness.rs
📝 Walkthrough

Walkthrough

This PR introduces role-aware column filtering across value-distribution detectors. A new Role::skips_value_detection() method gates identifier and sequence columns, systematically applied to drift detectors (KS, PSI, chi-square), single-column detectors (Cusum, Point, Contextual), and the Mahalanobis multivariate detector. The config version fingerprint is bumped from 8 to 9, with golden tests and documentation updated accordingly.

Changes

Column Role-Aware Detector Gating

Layer / File(s) Summary
Role API for skipping value detection
crates/ax-core/src/roles.rs
Role::skips_value_detection() method marks Identifier and Sequence roles to skip value-distribution detection, tested across all role variants.
Config version fingerprint update
crates/ax-detect/src/config.rs
DetectConfig::version() fingerprint bumped from anomalyx-cfg/8 to anomalyx-cfg/9 to signal role-aware detector behavior.
Drift detectors with role-aware column filtering
crates/ax-detect/src/dist.rs
Shared numeric-column iterator for_paired_numeric refactored to skip role-marked columns; KS, PSI, and chi-square detectors integrated with the flag; test data and role-gating verification tests updated.
Point, Cusum, and Contextual detectors with role gating
crates/ax-detect/src/coll.rs, crates/ax-detect/src/point.rs, crates/ax-detect/src/ctx.rs
Column-role skipping applied to Cusum, Point (refactored to use new method), and Contextual detectors; unit tests verify skip behavior under role-gating and contrast with disabled roles.
Mahalanobis detector with role-aware feature extraction
crates/ax-detect/src/mv.rs
Feature extraction now accepts column_roles flag to exclude skipped columns from Mahalanobis feature matrix; test verifies absence when features fall below minimum after role filtering.
Golden test data and release metadata
crates/anomalyx/tests/golden/describe.json, crates/anomalyx/tests/golden/scan_basic.json, Cargo.toml, CHANGELOG.md
Golden test files updated to config version 9 and new detector absence messages; workspace version bumped to 1.1.0; CHANGELOG documents role-aware gating, config impact, and legacy behavior restoration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • copyleftdev/anomalyx#56: Introduces the initial column-roles plumbing and --no-column-roles CLI flag that this PR extends with role-aware skipping across value-distribution and Mahalanobis detectors.

Poem

🐰 A rabbit hops through columns with care,
Skipping the IDs that aren't really there,
From Mahalanobis to drifts that we seek,
Role-aware detectors grow sleek!
Version 1-1-O brings order so fair.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: extending column roles to gate all value-distribution detectors as part of version 1.1.0, matching the PR's core objective.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/roles-all-detectors

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/ax-detect/src/ctx.rs (1)

102-107: 💤 Low value

Suggest checking numeric type before role for efficiency.

The role check precedes the numeric type check, which means col.role() is computed for non-numeric columns even though they're ignored by the subsequent is_numeric() check. Since role() is computed on each call (not cached), this is a minor inefficiency.

For consistency with other detectors (e.g., dist.rs:209, coll.rs:64, mv.rs:46) and to avoid unnecessary computation, consider reordering:

 fn scan_all(det: &SeasonalDetector, rs: &RecordSet, cfg: &DetectConfig, out: &mut Report) -> bool {
     let mut assessed = false;
     for col in &rs.columns {
+        if !col.ty.is_numeric() {
+            continue;
+        }
         // Skip identifier/sequence columns: a seasonal subseries of arbitrary
         // labels or a monotonic ramp is meaningless. Roles still ship in the
         // envelope; `column_roles = false` disables this.
         if cfg.column_roles && col.role().skips_value_detection() {
             continue;
         }
-        if col.ty.is_numeric() {
-            assessed |= det.scan_column(col, cfg, out);
-        }
+        assessed |= det.scan_column(col, cfg, out);
     }
     assessed
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ax-detect/src/ctx.rs` around lines 102 - 107, Reorder the checks so
you skip non-numeric columns before calling the potentially-expensive role()
method: first check col.is_numeric() and continue if false, then (if
cfg.column_roles) call col.role() and use role().skips_value_detection() to
decide to continue; i.e., change the current conditional order around
cfg.column_roles, col.role(), and col.is_numeric() to call col.is_numeric()
before col.role().
🤖 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.

Nitpick comments:
In `@crates/ax-detect/src/ctx.rs`:
- Around line 102-107: Reorder the checks so you skip non-numeric columns before
calling the potentially-expensive role() method: first check col.is_numeric()
and continue if false, then (if cfg.column_roles) call col.role() and use
role().skips_value_detection() to decide to continue; i.e., change the current
conditional order around cfg.column_roles, col.role(), and col.is_numeric() to
call col.is_numeric() before col.role().

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9206c978-f406-49ce-a3eb-8d23f6a0ce41

📥 Commits

Reviewing files that changed from the base of the PR and between 77e37bb and f5ffbad.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • CHANGELOG.md
  • Cargo.toml
  • crates/anomalyx/tests/golden/describe.json
  • crates/anomalyx/tests/golden/scan_basic.json
  • crates/ax-core/src/roles.rs
  • crates/ax-detect/src/coll.rs
  • crates/ax-detect/src/config.rs
  • crates/ax-detect/src/ctx.rs
  • crates/ax-detect/src/dist.rs
  • crates/ax-detect/src/mv.rs
  • crates/ax-detect/src/point.rs

The magic-prefixed-garbage test fed crafted length fields to binary container
decoders (parquet/arrow/avro/orc/evtx/pcap) that delegate to crates trusting
those lengths — a fuzzed length could make the dependency attempt a ~21GB
allocation (intermittent CI OOM). That is a binary-format-parsing property, not
an anomalyx logic bug, and isn't boundable without forking the decoders. Scoped
MAGICS to sqlite (allocation bounded by the input buffer) and documented the
limitation; those parsers are still fuzzed via arbitrary bytes (rejected at the
magic check).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@copyleftdev copyleftdev merged commit b173338 into main Jun 1, 2026
2 checks passed
@copyleftdev copyleftdev deleted the feat/roles-all-detectors branch June 1, 2026 23:36
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