diff --git a/cron/scheduler_script.py b/cron/scheduler_script.py index 074f4fa987..e78b933c92 100644 --- a/cron/scheduler_script.py +++ b/cron/scheduler_script.py @@ -288,7 +288,13 @@ def _resolve_script_path(script_path: str) -> tuple[Optional[Path], Optional[str f"({scripts_dir_resolved}): {script_path!r}" ) if not path.exists(): - return None, f"Script not found: {path}" + # Scripts resolve against THIS profile's scripts/ dir by design (profiles never share files), + # which is the usual reason a copied job cannot find a script that exists elsewhere (#94821). + return None, ( + f"Script not found: {path}. Cron scripts are looked up only in this profile's folder " + f"({scripts_dir_resolved}); if the job was copied from another profile, copy the script " + f"there too, or edit the job with `hermes cron edit`." + ) if not path.is_file(): return None, f"Script path is not a file: {path}" return path, None diff --git a/tests/cron/test_cron_script.py b/tests/cron/test_cron_script.py index 597fbeed3d..29bb3b1fa9 100644 --- a/tests/cron/test_cron_script.py +++ b/tests/cron/test_cron_script.py @@ -107,6 +107,16 @@ class TestRunJobScript: assert success is True assert output == "relative works" + def test_missing_script_names_the_profile_folder(self, cron_env): + """Scripts resolve per profile (#4707); the runtime error must say so (#94821).""" + from cron.scheduler_script import _run_job_script + + success, output = _run_job_script("copied-from-other-profile.py") + assert success is False + assert "Script not found" in output + assert str(cron_env / "scripts") in output and "profile" in output + assert "hermes cron edit" in output + def test_script_subprocess_env_sanitized(self, cron_env, monkeypatch): """Cron scripts must not inherit Hermes provider env (SECURITY.md ยง2.3)."""