Repository navigation
fix(kanban): carry the module argv's import root to the worker env - #122420
liuhao1024 wants to merge 1 commit into
Conversation
The dispatcher's _resolve_hermes_argv proves hermes_cli importable in the gateway process, where a store-python shim has the repo root on sys.path in-process; the spawned bare 'sys.executable -m hermes_cli.main' child runs from the task workspace with a scrubbed PYTHONPATH and cannot import the package, dies before any work, and the board auto-blocks (NousResearch#122299). Keep the module-over-PATH ordering (da18c20, NousResearch#111569) and instead propagate the running install's package root onto the worker's PYTHONPATH; a resolved shim path keeps owning its own imports. Fixes NousResearch#122299
|
Independent verification on the PR head (46e36e2): kanban-db suite 54/54 green on Linux, 1 skipped. Carrying the module argv import root to the worker env keeps worker imports resolving. No findings. |
|
Thanks @whyyagswhy for the independent verification on Linux — much appreciated. That complements the macOS side nicely: locally I also ran the real-subprocess probe (fresh process, neutral cwd, clean env with only |
|
E2E-verified this fix on a real PM/source install (macOS 27.0, Apple Silicon, store Python 3.14.7 with
One scope note for anyone landing on this issue: the propagated root is the dispatcher's own checkout root. On our install the child then activates the committed generation via This fix resolves the Kanban half of #122487 on our configuration. Thanks for the clean, well-tested patch. |
|
Thanks @connerstirne-gh — this is a great E2E confirmation, especially since it runs the real worker argv from the env Your scope note matches the intended boundary: the propagated root is the dispatcher's own checkout root, and the child activates the committed generation via its own bootstrap — which is why no site-packages propagation was added. The Bot-DM delivery runner ( Two independent verifications now (Linux suite + this macOS E2E matrix) — appreciated. |
|
E2E confirmation on a live Linux PM/source install (CachyOS, kernel 7.2, store Python 3.14.7,
Thanks for the fix. It would be great to get this merged: on this install the kanban board was fully dead after the 2026-09-25 update. |
|
Thanks @megastruktur — a third independent confirmation, and the first one capturing the full failure arc end to end: the dispatcher spawn dying twice with With the two new regression tests passing on your install on top of the Linux suite run and the macOS E2E matrix upthread, the fix now has coverage on three platforms. Glad the board is alive again after the 2026-09-25 update. |
|
I'll add another independent confirmation for my Windows 11 machine: Component: I have some left over tests tasks from V0.21.5 that were failing. Checked out your pr branch and they have run just fine. Retested with a new batch of tasks and they are working fine now too. From my test task showing initially running into the problem (-22min), it self diagnosing (-22 min), and then resolving correctly on this PR branch (-6 min). |
|
Thanks @dummey — this is the first Windows-side confirmation, so it completes the platform matrix (Linux + macOS + now Windows 11), which matters here because the propagation is exactly the kind of thing that can drift per-OS. The timeline you captured is a particularly clean before/after: the pre-fix card dying twice with Appreciate you testing on the real managed-tools interpreter path ( |
#122299, #122487, #122500, salvage #122420) _resolve_hermes_argv proves hermes_cli importable in the GATEWAY, where the store-python shim / launcher bootstrap put the repo root on sys.path in-process. The worker env scrub (build_subprocess_env / served_profile_child_env) strips Hermes-owned PYTHONPATH entries, so the bare `sys.executable -m hermes_cli.main` child could not import the package the parent just proved importable and every worker died at birth (ModuleNotFoundError: hermes_cli) -> crashed x2 -> gave_up. Reuse cron's pin_hermes_tree_on_pythonpath (#112729) on the module argv only: a resolved shim path owns its imports. hermes_cli.main's bootstrap then activates the committed PM dependency generation as usual, so a store Python with an empty site-packages still boots. Same class in the Bot Chat delivery runner (cron/scheduler_delivery.py), which builds the module argv after served_profile_child_env.
#122299, #122487, #122500, salvage #122420) _resolve_hermes_argv proves hermes_cli importable in the GATEWAY, where the store-python shim / launcher bootstrap put the repo root on sys.path in-process. The worker env scrub (build_subprocess_env / served_profile_child_env) strips Hermes-owned PYTHONPATH entries, so the bare `sys.executable -m hermes_cli.main` child could not import the package the parent just proved importable and every worker died at birth (ModuleNotFoundError: hermes_cli) -> crashed x2 -> gave_up. Reuse cron's pin_hermes_tree_on_pythonpath (#112729) on the module argv only: a resolved shim path owns its imports. hermes_cli.main's bootstrap then activates the committed PM dependency generation as usual, so a store Python with an empty site-packages still boots. Same class in the Bot Chat delivery runner (cron/scheduler_delivery.py), which builds the module argv after served_profile_child_env.
#122299, #122487, #122500, salvage #122420) _resolve_hermes_argv proves hermes_cli importable in the GATEWAY, where the store-python shim / launcher bootstrap put the repo root on sys.path in-process. The worker env scrub (build_subprocess_env / served_profile_child_env) strips Hermes-owned PYTHONPATH entries, so the bare `sys.executable -m hermes_cli.main` child could not import the package the parent just proved importable and every worker died at birth (ModuleNotFoundError: hermes_cli) -> crashed x2 -> gave_up. Reuse cron's pin_hermes_tree_on_pythonpath (#112729) on the module argv only: a resolved shim path owns its imports. hermes_cli.main's bootstrap then activates the committed PM dependency generation as usual, so a store Python with an empty site-packages still boots. Same class in the Bot Chat delivery runner (cron/scheduler_delivery.py), which builds the module argv after served_profile_child_env.
|
Closing — this fix has been salvaged into main: 7e3b34c landed the module-argv import-root propagation from this PR, and 5392a83 later refined it to reuse cron's pin_hermes_tree_on_pythonpath (#112729) on the module argv only, covering #122299/#122487/#122500 and the dispatcher crash reported in #125649. Nothing further to carry here — thanks for the salvage. |
What does this PR do?
On a store-python (PM) install, the kanban dispatcher resolves the worker's spawn argv through the module form (
sys.executable -m hermes_cli.main) becausefind_spec("hermes_cli")succeeds in the gateway process — but that importability comes from the shim's in-processsys.pathinjection, which is invisible to the spawned child. The child runs the bare interpreter from the task workspace with aPYTHONPATHthe subprocess-env factory has scrubbed of Hermes-owned entries, fails withModuleNotFoundError: No module named 'hermes_cli'before doing any work, trips the dispatcher's circuit breaker, and the board auto-blocks (#122299; four independent reproductions across Linux, Windows and macOS installs).The fix keeps the module-over-PATH ordering that
da18c20226introduced for safety (#111569 — a PATHhermescould be attacker-planted) and instead makes the selected module form actually resolvable for the child: when the argv leads with-m hermes_cli.main, the dispatcher prepends the running install's package root onto the worker'sPYTHONPATH. This propagates exactly the context that madefind_specsucceed in the parent. It is version-safe because the child re-execs this same interpreter — the PYTHONPATH entries the scrub removes are dangerous only for a different interpreter's compiled modules. Oncehermes_cli.mainis importable, its own bootstrap owns dependency activation as usual, so no site-packages are propagated (unlike the cron-side fix in #122238, whose-m cron.schedulerchild imports third-party packages directly). A resolved shim path is left untouched: a shim owns its own imports.Related Issue
Fixes #122299
Type of Change
Changes Made
hermes_cli/kanban_db_dispatch.py: added_propagate_module_import_root()(module-form guard + case-normalized dedup + prepend of the package root derived from the running module's own location); called it in_default_spawnright after_worker_argvbuilds the command, before the systemd restart-safe wrapper.tests/hermes_cli/test_kanban_db.py: two regression tests — helper semantics (module form prepends the root, existing entries survive, no duplication, shim paths untouched) and a real-subprocess check that a bare interpreter launched from a neutral cwd with only the propagatedPYTHONPATHcan resolvehermes_cli.How to Test
pytest tests/hermes_cli/test_kanban_db.py -q— 53 passed, 1 skipped for the file (test_infrastructure_spawn_refusal_never_charges_the_cardfails identically on a cleanupstream/maincheckout on this macOS host — systemd user-bus probe surface — and is untouched by this diff; it passes in CI).pytest tests/hermes_cli/test_kanban_db.py -k "puts_package_root or importable_from_scrubbed"— the new tests pass; observed result:2 passed.cd /tmp && <store-python> -m hermes_cli.main --versionfails withModuleNotFoundError; the same interpreter withPYTHONPATH=<repo>succeeds — which is exactly what the dispatcher now sets for the child. Observed result: the subprocess probe test replicates the green half of this mechanically.Checklist
Code
fix(scope):,feat(scope):, etc.)cron/scheduler_worker_env.py— different subsystem, no file overlap)pytest tests/ -qand all tests pass (full file run: 53 passed / 1 skipped; the one failure noted above is pre-existing on cleanupstream/mainlocally and outside this change's path)os.pathsep/os.path.normcasefor WindowsDocumentation & Housekeeping
docs/, docstrings) — or N/A (docstring on the new helper documents the invariant)cli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/A