Files
hermes-agent/tests/cron/test_run_error_diagnostics.py
Teknium e1a161538a fix(cron): make failed runs diagnosable without verbose delivery errors
Persist a redacted chained traceback in the private run output and expose
redacted last_error in tool and slash listings, including historical errors.
Keep the run_job concise error return unchanged for delivery classification.

Slim redo of liuhao1024's earliest #104545; adds forced redaction and keeps
formatting in a topical sibling. Local SDK/socket A/B verifies diagnosis
visibility plus healthy-script, clearing, and private-file controls.
Canonical tests queued under the campaign lock at commit time.

Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
2026-09-07 08:18:56 -07:00

41 lines
2.3 KiB
Python

"""Failure detail belongs in the local audit, not the delivery summary."""
from cron import jobs, scheduler
def test_run_error_persists_redacted_cause_but_returns_summary(tmp_path, monkeypatch):
def fail_setup(*args):
try:
raise ConnectionError("https://user:password@localhost/api?token=secret-token")
except ConnectionError as cause:
raise RuntimeError("Connection error.") from cause
monkeypatch.setattr(scheduler, "_resolve_cron_agent_setup", fail_setup)
with jobs.use_cron_store(tmp_path):
job = jobs.create_job(prompt="Check status", schedule="every 1h", model="local-probe", deliver="local")
success, output, response, error = scheduler.run_job(job)
saved = jobs.save_job_output(job["id"], output).read_text(encoding="utf-8")
assert not success and response == "" and error == "RuntimeError: Connection error."
assert "Traceback (most recent call last)" in saved and "fail_setup" in saved
assert "ConnectionError" in saved and "localhost" in saved
assert "password" not in saved and "secret-token" not in saved
def test_list_exposes_run_error_and_clears_it_after_success(tmp_path, capsys):
from hermes_cli.cli_commands_mixin import CLICommandsMixin
from tools.cronjob_job_args import _format_job
with jobs.use_cron_store(tmp_path):
job = jobs.create_job(prompt="Check status", schedule="every 1h", model="local-probe", deliver="local")
reason = "RuntimeError: https://user:password@localhost/api?token=secret-token"
jobs.mark_job_run(job["id"], False, error=reason)
displayed = _format_job(jobs.get_job(job["id"]))
assert displayed["last_error"].startswith("RuntimeError:") and "localhost" in displayed["last_error"]
assert "password" not in displayed["last_error"] and "secret-token" not in displayed["last_error"]
assert displayed["last_delivery_error"] is None and displayed["last_fire_error"] is None
CLICommandsMixin._cron_list(object(), "list", {"all": False})
console = capsys.readouterr().out
assert f"error: {displayed['last_error']}" in console
assert "password" not in console and "secret-token" not in console
jobs.mark_job_run(job["id"], True)
assert _format_job(jobs.get_job(job["id"]))["last_error"] is None