Jobs at least 30 days old with zero runs in the past 30 days
What does ZopNight detect here?
Zero recorded runs across 30 days, on a job at least 30 days old, marks a definition that is dead weight: stale notebooks, pinned libraries, list clutter. ZopNight requires both facts positively: an absent run count or an unknown age abstains, so a young monthly cron is never flagged.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-2330 · RC-2430 · RC-2230 |
| Category | orphan |
| Severity | low |
| Metric | none — pure configuration read |
| Source | orphan_job.go |
Where it applies
Dead definitions accumulate silently
An unused job burns no compute, which is exactly why nobody deletes it. The costs are quieter: a jobs list where the living are indistinguishable from the dead, notebooks and library versions pinned by a workflow nobody owns, and the occasional heart-stopping moment when someone re-enables the wrong schedule. This is an orphan-cleanup finding with a savings figure of 0 by design. The value is a shorter, truthful jobs list, not a line on the bill.
Two facts, both required, both positive
The rule fires only when the discoverer’s runCount30d for the job is present and
exactly 0, and the job’s age is known and at least 30 days. The age guard is what
keeps the rule honest: a job created 10 days ago with a monthly or quarterly schedule
legitimately shows zero runs; it has simply never reached its first fire. Age comes
from a pre-derived age field or, failing that, from the job’s raw creation timestamp.
When neither the run count nor the age can be established, the rule abstains; an
orphan flag on a guess is worse than no flag.
The coverage gap, stated plainly
Today only the Azure-side discoverer stamps job age. On GCP workspaces no producer emits an age field yet, so this rule abstains there entirely rather than false-flag a young cron for deletion. That asymmetry is a data gap, not a judgment that GCP jobs cannot be orphaned. Expect findings to appear once the age producer lands.
Check the run history yourself
databricks api get '/api/2.1/jobs/runs/list?job_id=123456789&limit=5' | jq ' .runs[]? | {run_id, start_time, state: .state.result_state}'An empty result over a month, on a job whose created_time is older than the month,
is this finding reproduced by hand.
Pause first, delete second
The remediation is deliberately a two-step hedge. Pause or remove the schedule first, which is reversible and proves nobody downstream notices. Delete after a quiet interval, and clean up what the job kept alive: pinned clusters, init scripts, library versions held only for its benefit. Anything genuinely seasonal deserves a comment in the job definition saying so, which is what prevents its next appearance on this list.