Files
hermes-agent/tests/compat
ethernet 5e4a2a3d24 refactor(pm): remove legacy dependency and launch managers
Competing installers and checkout-local venv assumptions bypassed PM
selection, install consent, and generation lifetimes. Route consumers
through PM and installation-bound launchers. Refresh source launchers
before obsolete Python entries can be collected.

Remove Node, browser, and CUA acquisition engines, obsolete venv-holder
handling, detached sync, and unused PM APIs. Keep historical updater
exports inert and preserve external tool ownership and native integration.

Share product freshness and prepared inputs across builders. Align plugin
admission, Docker provisioning, setup instructions, and behavioral tests.

Verified targeted Python and JavaScript tests, desktop and web typechecks,
scoped lint, real product builds, and the Docker frontend smoke test.
The missed post-setup test cleanup is included and verified.

Native Windows/macOS execution, full Rust compilation, and the complete
repository suite remain unverified. Historical compatibility requirements
were preserved and extended, not fully rescanned.
2026-09-12 14:57:38 -04:00
..

Running updater compatibility

An updater can retain old Python modules after replacing its checkout. Its next lazy import reads the new files. Current-tree tests alone cannot protect that boundary.

old_updater_surface.json records historical imports union current imports. Regenerate it from a full clone:

python3 scripts/audit-old-updater-imports.py --freeze tests/compat/old_updater_surface.json

The walker pins origin/main once. The JSON records that exact commit, the history roots, discovered entrypoints, selected paths, and parse recoveries. It inventories all reachable commits, including merge parents. It follows historical filenames, deleted helpers, extraction imports, and rename edges. A shallow clone cannot regenerate the file. Shallow CI checks the frozen names and that the current imports remain a subset of the freeze.

The surface deliberately over-approximates reachability. Matching update entrypoints and same-named functions can include unrelated callers. Do not trim those entries by hand. A historical name is cheaper than a missed live import. The resolver requires module-scope bindings, not names inside functions or classes. It does not execute module bodies or prove every conditional export.

Runtime behavior

Retired dependency entrypoints stop with a relaunch message. Returning None can activate old pip fallback code. Other shims retain conservative return shapes without installs, downloads, marker writes, or PM delegation. Each shim explains why it exists. Current application code must use the live implementation, not these historical exports.

A fresh source launch checks PM's existing successful dependency facts. It synchronizes stale state and switches to the managed interpreter before activating application dependencies. No new incomplete-marker protocol is used.

old_updater_dependencies.py retains historical caller functions with their lazy imports intact. The shim tests execute those callers against the new tree. tests/pm/test_source_update_launch.py exercises real worker publication, failed-build retention, and fresh-process bootstrap.

Manual review of dynamic edges

Complete history enumeration is not a complete Python call-graph proof. The JSON retains unresolved_dynamic rather than silently dropping those edges. The reviewed categories are:

  • hermes_constants reloads: fixed first-party module, present and audited. Reload execution still depends on the running interpreter and process state.
  • managed_scope, main_dashboard, and browser module objects: fixed modules passed between helpers. The modules exist. Arbitrary attribute dispatch is not a statically proven contract.
  • managed_uv and _subprocess_compat: the historical Windows installer calls _subprocess_compat.run. REVIEWED_DYNAMIC_LOADS retains that named call with its witness commit. Its shim stops before invoking an installer.
  • PM operations and build operations: fixed dispatch modules, seeded explicitly with the other post-swap helpers. PM registry import names can also come from package definitions outside the checkout.
  • Plugin configuration hooks and deferred tool registration: import targets depend on enabled plugins and runtime manifests. A core-tree freeze cannot enumerate names supplied by independently installed plugins.

These limits remain visible in the generated file. The static gate proves that its recorded imports still resolve structurally. Real updater and launch tests prove the exercised runtime paths, not every historical platform combination.