Commit Graph

12 Commits

Author SHA1 Message Date
ethernet
1991e100b5 fix(pm): lease the PM runtime generation before spawning its child
runtime_python() released .prepare.lock on return and the worker/CLI child
only leased its generation once its own code ran. A publish plus `pm gc` in
that window could remove the generation the child was starting from.

The resolving process now leases the generation it returns while still
holding .prepare.lock (which the collector also takes), once per generation
for the life of the process, so the child is covered until it holds its own.
2026-09-24 14:08:21 -04:00
ethernet
b728fdd627 refactor(pm): own the lock/atomic-write primitives in pm.filesystem
pm imported runtime_state's private helpers (_lock, _atomic_bytes, _bytes,
_digest) at a dozen sites while runtime_state imports pm.environments at
module top. The primitives are pm's: move them into the stdlib-only
pm.filesystem as lock_fd, durable_write_bytes, read_bytes_or_none and
file_digest, and repoint every pm caller.

runtime_state keeps the private names only as import aliases: it still
calls them through its own globals, and pre-PM updaters load them by these
names mid-swap (tests/compat/old_updater_surface.json).

Boot-subset test fixtures now copy pm/filesystem.py, since runtime_state
imports it at process boot; worker-injection tests patch the name
pm.publication now reads.
2026-09-24 14:08:03 -04:00
ethernet
87d0fadded fix(pm): resolve the install stamp in pm.paths so sealed stages can read it
b207701287 routed PM's stamp reads through hermes_cli.steward.install_stamp_path.
The Docker runtime base runs PM before hermes_cli ships (only __init__ and
runtime_state are copied), so ensure() died with No module named
'hermes_cli.steward'. The resolver is an install-root path built only on
pm.paths.install_root/repo_root; move it there and point every reader at it.
2026-09-24 11:12:27 -04:00
ethernet
3c3f6d9688 fix: better install logs 2026-09-24 10:53:27 -04:00
ethernet
b207701287 fix: resolve PM stamp reads through installation root 2026-09-24 09:20:50 -04:00
ethernet
15335df680 fix(pm): collect superseded and aborted PM runtime generations
pm-runtime/generations/<uuid> trees were never collected: a kill -9 during
staging orphaned a venv permanently and every input change left the old
runtime behind. `hermes pm gc` now sweeps them under .prepare.lock with the
same lease model as application generations: entry points (worker.py,
launch.py) pin their own runtime, prepare_runtime marks new generations
lease-managed, and the collector removes unpublished stages outright,
superseded generations only once no worker holds a lease, and never a
pre-lease generation.
2026-09-21 19:01:36 -04:00
ethernet
f6a30447de refactor(pm): one install_root() in pm.paths replaces six HERMES_INSTALL_ROOT ladders
post_update._install_root, boot_bootstrap.default_project_root,
update_channel._default_root, version_info._CODE_ROOT + _resolve_stamp_file,
_launchers.publish_launchers and pm.runtime each re-derived "HERMES_INSTALL_ROOT
or the code root". pm.paths.install_root() is the one place now; pm.store reuses
the downloader's User-Agent instead of carrying a second one.
2026-09-18 20:08:16 -04:00
ethernet
bbec973514 refactor(pm): pm owns the dependency-environment layout and interpreter paths
hermes_cli.runtime_paths (venv generations, selection, activation) moves to
pm.environments, and gains venv_bin_dir / venv_python / project_python. Every
in-tree caller asks pm for an interpreter now; pm no longer reaches back into
hermes_cli for its own environment layout (pm.packages, pm.extras, pm.ensure,
pm.paths imported hermes_cli.runtime_paths). The three open-coded
"Scripts/python.exe or bin/python" ladders in pm collapse onto venv_python.

hermes_constants.venv_python_path / venv_bin_dir and hermes_cli.runtime_paths
stay as frozen-updater-surface shims only (tests/compat/old_updater_surface.json).

To keep the boot path light, pm/__init__ resolves its facade lazily (PEP 562)
and pm.registry loads the built-in package definitions on first read instead of
at import: `import hermes_bootstrap` now loads pm + pm.environments only (25ms,
was 37ms with the eager facade dragging in the downloader). The stripped-payload
fixtures that ship only pre-import files keep working for the same reason.

Also restores two frozen-surface re-exports the F401 sweep dropped
(banner._github_compare_behind, cua_backend.resolve_cua_driver_cmd).
2026-09-18 20:02:36 -04:00
ethernet
062b7138e7 fix(pm): isolate worker control stdin and share bootstrap cache 2026-09-12 18:41:04 -04:00
ethernet
01821b8e14 refactor(pm): consolidate private Python environment engine 2026-09-11 18:00:04 -04:00
ethernet
018d2b39d8 fix(pm): prepare platform trust before bootstrap downloads
Standalone Python cannot locate the system CA bundle on this NixOS host.
Use the shell-staged uv to prepare the independent PM runtime before PM
fetches managed Python. Declare and lock truststore in that runtime, then
activate it before CLI and worker imports construct HTTPS clients.

Make setup's awk pin reader follow object nesting rather than indentation.
Use the same reader for tool versions and artifact fields.

Verified cold activation with CA overrides removed, pinned Python and uv
downloads, pm doctor, and a public worker HTTPS install. The targeted suite
passed 56 tests with one Windows-only skip. The TLS regression fails when
truststore is installed but entrypoint activation is removed. Bash syntax
and Ruff checks passed. The full suite was not run.

Two additional setup-toolchain tests fail on unchanged HEAD because their
fixtures reach the real home before home isolation. CI bootstrap unification
is not part of this change.
2026-09-11 13:31:41 -04:00
ethernet
284dbaf537 fix(pm): isolate bootstrap dependencies and unify YAML on ruamel
Activation reaches plugin discovery before the application dependencies
exist. Give PM its own locked Python project and runtime so it can install
or repair the application without importing that dependency tree.

Keep PM outside the application workspace. A shared uv workspace resolves
the application graph and cannot provide this isolation. Route mutations
through an isolated worker and preserve transaction callbacks, cancellation,
custom package registrations, and correlated receipts.

Use the same runtime builder for source installs and packaged payloads.
Keep offline wheelhouse support in that builder. Nix builds the independent
PM lock as a separate derivation. Refuse lazy-disabled bootstrap before
installing tools or dependencies.

Move first-party YAML readers and writers to ruamel. Keep the application
lock's transitive PyYAML requirements for third-party packages.

Verification:
- Focused canonical Python suite: 177 passed, 1 host-gated skip.
- Electron backend probes: 12 passed. Electron typecheck passed.
- Both uv locks, scoped lint, Bash syntax, and whitespace checks passed.
- Cold activation, corrupt-app repair, offline staging, and relocation ran.
- Built and exercised the Nix PM runtime and standalone YAML merge script.

Six broader caller test files retain the same 24 failing test IDs as an
archive of HEAD. The existing real-home guard blocks those tests before
they can exercise the affected paths. No full-suite pass is claimed.
Native Windows signing and full Bionic package execution remain unverified.
2026-09-11 12:23:51 -04:00