From d473e7c9385e04c975b32d2d2cde3a02ba7d4f47 Mon Sep 17 00:00:00 2001 From: Cornna <96944678+ymylive@users.noreply.github.com> Date: Thu, 28 May 2026 18:48:42 +0800 Subject: [PATCH] fix(cron): exclude jobs.json registry from disk-cleanup pattern Closes #32164 --- plugins/disk-cleanup/disk_cleanup.py | 9 +++++- tests/plugins/test_disk_cleanup_plugin.py | 34 +++++++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/plugins/disk-cleanup/disk_cleanup.py b/plugins/disk-cleanup/disk_cleanup.py index b7f748e7f..8d984273e 100755 --- a/plugins/disk-cleanup/disk_cleanup.py +++ b/plugins/disk-cleanup/disk_cleanup.py @@ -481,7 +481,14 @@ def guess_category(path: Path) -> Optional[str]: }: return None if top == "cron" or top == "cronjobs": - return "cron-output" + # Only files under the disposable ``output/`` subtree are + # cleanup candidates. Top-level cron control-plane state + # (e.g. ``jobs.json``, ``.tick.lock``) must never be + # auto-tracked — deleting it wipes the live scheduler + # registry. See issue #32164. + if len(rel.parts) >= 2 and rel.parts[1] == "output": + return "cron-output" + return None if top == "cache": return "temp" except ValueError: diff --git a/tests/plugins/test_disk_cleanup_plugin.py b/tests/plugins/test_disk_cleanup_plugin.py index e1463bced..4f7f66e02 100644 --- a/tests/plugins/test_disk_cleanup_plugin.py +++ b/tests/plugins/test_disk_cleanup_plugin.py @@ -129,12 +129,40 @@ class TestGuessCategory: def test_cron_subtree_categorised(self, _isolate_env): dg = _load_lib() - cron_dir = _isolate_env / "cron" - cron_dir.mkdir() - p = cron_dir / "job_output.md" + # Only files under ``cron/output/`` are disposable run artifacts. + output_dir = _isolate_env / "cron" / "output" / "job_123" + output_dir.mkdir(parents=True) + p = output_dir / "run.md" p.write_text("x") assert dg.guess_category(p) == "cron-output" + def test_cron_jobs_json_not_tracked(self, _isolate_env): + """Regression for #32164: the cron registry must never be tracked.""" + dg = _load_lib() + cron_dir = _isolate_env / "cron" + cron_dir.mkdir() + p = cron_dir / "jobs.json" + p.write_text("[]") + assert dg.guess_category(p) is None + + def test_cron_tick_lock_not_tracked(self, _isolate_env): + """Regression for #32164: cron tick-lock is control-plane state.""" + dg = _load_lib() + cron_dir = _isolate_env / "cron" + cron_dir.mkdir() + p = cron_dir / ".tick.lock" + p.write_text("") + assert dg.guess_category(p) is None + + def test_cronjobs_top_level_not_tracked(self, _isolate_env): + """The legacy ``cronjobs`` alias is also control-plane at the top.""" + dg = _load_lib() + cron_dir = _isolate_env / "cronjobs" + cron_dir.mkdir() + p = cron_dir / "jobs.json" + p.write_text("[]") + assert dg.guess_category(p) is None + def test_ordinary_file_returns_none(self, _isolate_env): dg = _load_lib() p = _isolate_env / "notes.md"