diff --git a/cron/scheduler.py b/cron/scheduler.py index a3686ca7fa79f..57a89e06c1367 100644 --- a/cron/scheduler.py +++ b/cron/scheduler.py @@ -4879,12 +4879,17 @@ def run_one_job( else: deliver_content = final_response if success else _summarize_cron_failure_for_delivery(job, error) if drift_skip and not success: - # Drift-skip alert: strip the internal marker from the - # user-facing text (the summarizer passes the message - # through its generic tail). - deliver_content = re.sub( - r"\[drift_skip[^\]]*\]\s*", "", deliver_content + # Drift-skip alert: bypass the generic summarizer's + # 180-char truncation (it would eat the remediation + # command) and strip the internal marker — deliver the + # guard's own actionable message intact. + _drift_text = re.sub( + r"\[drift_skip[^\]]*\]\s*", "", str(error) ).strip() + deliver_content = ( + f"⚠️ Cron '{job.get('name') or job['id']}' skipped: " + f"{_drift_text}" + ) # Treat whitespace-only final responses the same as empty # responses: do not deliver a blank message, and let the # empty-response guard below mark the run as a soft failure. diff --git a/tests/cron/test_cron_drift_alert_once.py b/tests/cron/test_cron_drift_alert_once.py index 4a1ad8820f735..f555f829a364b 100644 --- a/tests/cron/test_cron_drift_alert_once.py +++ b/tests/cron/test_cron_drift_alert_once.py @@ -92,6 +92,10 @@ class TestDriftAlertOnce: blob = deliveries[0].lower() assert "drift" in blob assert "pin" in blob + # The single alert must carry the complete remediation command — + # the generic summarizer's 180-char truncation must not eat it. + assert "cronjob action=update" in deliveries[0] + assert "[drift_skip" not in deliveries[0] def test_healed_drift_clears_bit_and_redrift_realerts(self, tmp_path): job = _job()