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 <root>/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)
This commit is contained in:
Halldrix
2026-09-26 02:30:58 -05:00
committed by kshitij
parent 3eea0fe1e1
commit afc450d178

View File

@@ -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
# ``<root>/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", "")