From afc450d17845fd8d8cc52ad41ea42dccbec1edb0 Mon Sep 17 00:00:00 2001 From: Halldrix Date: Sat, 26 Sep 2026 02:30:58 -0500 Subject: [PATCH] fix(cron): read the committed generation for Windows cron scripts (#122183) _windows_cron_python_invocation selected the dependency tree with selected_venv, which falls back to base_venv and answers the leftover pre-PM /venv when no generation is recorded. That tree belongs to whichever interpreter created it, so on a PM-managed install the managed store Python 3.14 got a cp311 site-packages on PYTHONPATH and every cron script died with "No module named 'pydantic_core._pydantic_core'" -- the cron sibling of the gateway crash in #122183, which janviernine flagged there and left out of scope. committed_venv never answers with the in-tree venv. With nothing committed this install provisioned no tree, so overlay none and let the child keep the interpreter it was handed rather than borrowing a foreign ABI. Every other selected_venv caller (tools/environments/local_pythonpath, hermes_cli/_early_recovery, pm/extras, pm/environments_adopt) already gates on runtime_facts_path().is_file(); this was the only unguarded one. (cherry picked from commit dd2b7181ab0aec671ff1f8d0946e0d963cb50f52) --- cron/scheduler_script.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/cron/scheduler_script.py b/cron/scheduler_script.py index dc3528b87d..7dd49c5094 100644 --- a/cron/scheduler_script.py +++ b/cron/scheduler_script.py @@ -131,16 +131,27 @@ def _windows_cron_python_invocation(python_exe: str) -> tuple[str, dict[str, str interpreter = sibling from hermes_cli._launchers import resolve_store_python - from pm.environments import selected_venv, site_packages as dependency_site + from pm.environments import committed_venv, site_packages as dependency_site repo = Path(__file__).resolve().parents[1] managed_python = resolve_store_python(repo) if managed_python is not None: # A packaged caller may hand us the old venv launcher; select bytes # from the install record rather than interpreting relocated pyvenv.cfg. - dependencies = dependency_site(selected_venv(repo)) - - return str(managed_python), {"PYTHONPATH": os.pathsep.join([str(repo), str(dependencies)])} + # + # ``committed_venv``, not ``selected_venv``: with no generation recorded the + # latter falls back to ``base_venv`` and answers the leftover pre-PM + # ``/venv``, which is built for whichever interpreter created it. Overlaying + # that on the managed store Python loads a cp311 ``pydantic_core`` on 3.14 and + # every script dies with ``No module named 'pydantic_core._pydantic_core'`` — the + # cron sibling of the gateway crash in #122183/#123650. With no generation + # committed this install provisioned no tree, so overlay none: the child keeps + # the interpreter it was handed instead of borrowing a foreign ABI. + environment = committed_venv(repo) + pythonpath = [str(repo)] + if environment is not None: + pythonpath.append(str(dependency_site(environment))) + return str(managed_python), {"PYTHONPATH": os.pathsep.join(pythonpath)} cfg = _read_windows_pyvenv_cfg(venv_dir) home = cfg.get("home", "")