Webhook icon
Schedule icon
WorkingDirectory icon
Commands icon
Docker icon
Script icon
If icon
SlackIncomingWebhook icon
Log icon

Detect Shape and Label Drift Between Dataset Revisions Before a Retrain

Compare rows, columns, and label shares across two dataset revisions, flag every feature past your tolerance, and alert Slack before retraining.

Categories
Data

How it works

  1. post_revision_stats (io.kestra.plugin.core.trigger.Webhook, keyed) accepts the revision pair POST from the dataset monitor. nightly_drift_sweep (io.kestra.plugin.core.trigger.Schedule) ships disabled: true as a fallback net once an operator switches it on.
  2. drift_workspace (io.kestra.plugin.core.flow.WorkingDirectory) opens one shared directory so the writer and the comparer read the same file, because default tasks are stateless and the temp directory is purged when a task completes.
  3. write_revision_stats (io.kestra.plugin.scripts.shell.Commands on the io.kestra.plugin.scripts.runner.docker.Docker runner, image python:3.12-slim) writes the posted body, or the revision_stats input default on manual runs, into revision_stats.json with a quoted heredoc.
  4. compare_revisions (io.kestra.plugin.scripts.python.Script on python:3.12-slim) measures the row count change against max_row_delta_pct, set-diffs the column lists, and walks the union of label shares against max_label_delta_pct, collecting one feature string per breach and the largest delta across everything it measured.
  5. check_drift (io.kestra.plugin.core.flow.If) branches on the verdict. Drift runs notify_drift, the Slack incoming webhook that names every drifted feature and the largest delta. Unreadable stats run check_drift_error, a second If whose alert_unreadable_stats branch pages Slack so a broken feed never reads as a stable dataset, and only a clean pair reaches log_stable.
  6. The errors block alerts Slack whenever the flow itself breaks, because a dead comparer must never look like a stable revision pair.

What you get

  • A per-feature drift report covering row counts, column additions and removals, and every label share shift between the two revisions.
  • A Slack alert that names the drifted features and the largest delta, delivered as soon as the pair is compared.
  • Separate tolerances for label shares and row counts, so a noisy label histogram does not mask a real size change.
  • A separate unreadable payload branch, so a malformed POST escalates instead of quietly passing as stable.
  • Gateable outputs, verdict, drift_features, max_delta, rows_delta_pct, and column_changes for any parent training pipeline.

Who it's for

  • ML platform teams that pin dataset revisions for training and eval jobs and need proof the snapshot still matches the approved one.
  • Data engineers who maintain labeling pipelines and want share shifts caught before a retrain consumes them.
  • Reviewers who approve dataset revisions and want the drift evidence attached to the execution that checked it.

Why orchestrate this with Kestra

A distribution comparison is a few arithmetic operations, but a gate needs the state around it, a keyed webhook for the monitor, a hermetic Python runtime pinned in the flow file, tolerances that separate escalation from the all-clear, and an execution record proving the exact revision pair was checked. Kestra supplies all of that declaratively, with Slack routing, an error handler, and a branch structure any scheduler already understands. A notebook run by hand gives you none of that, it only protects the people who remember to rerun it.

Prerequisites

  • A worker with Docker access, both the writer and the comparer run in python:3.12-slim.
  • A Slack incoming webhook for drift alerts, unreadable payload pages, and failure alerts.
  • A dataset monitor that POSTs revision stats shaped as a dataset name with baseline and candidate objects carrying revision, rows, columns, and a labels share map.

Secrets

  • HF_DRIFT_WEBHOOK_KEY: key segment guarding the webhook URL, anyone holding it can trigger a comparison.
  • SLACK_WEBHOOK_URL: Slack incoming webhook URL used for the drift alert, the unreadable payload page, and failures.

Quick start

  1. Add the secrets above to your Kestra namespace.
  2. Run the flow once with the default inputs and confirm revision_stats.json lands in the workspace and the outputs carry verdict, max_delta, and drift_features.
  3. Bring the candidate rows within 20 percent of the baseline and align the label shares, re-run, and watch verdict flip to stable with an empty drift_features list.
  4. Point the dataset monitor at /api/v1/{tenant}/executions/webhook/{namespace}/hf-dataset-drift/{HF_DRIFT_WEBHOOK_KEY} once its POST body matches the revision stats shape.

How to extend

  • Gate the retrain itself by having a parent flow read verdict and stop on drift_detected instead of only alerting.
  • Compare many datasets by wrapping this flow in a Subflow per dataset and aggregating the verdicts in a parent flow.
  • Walk each drifted feature with io.kestra.plugin.core.flow.Loop over drift_features to open one ticket per breach.
  • Archive both revision stats snapshots to object storage with io.kestra.plugin.aws.s3.Upload so drift history stays reviewable.
  • Add a io.kestra.plugin.git.Clone of the labeling repository when label definitions, not just shares, must be diffed against the baseline.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.