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.
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_constantsreloads: 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_uvand_subprocess_compat: the historical Windows installer calls_subprocess_compat.run.REVIEWED_DYNAMIC_LOADSretains 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.