fix: harden global lifecycle state handling - #2655
Open
lkshrk (lkshrk) wants to merge 7 commits into
Open
Conversation
lkshrk (lkshrk)
requested review from
Daniel Meppiel (danielmeppiel) and
Sergio Sisternes (sergio-sisternes-epam)
as code owners
August 22, 2026 07:04
Contributor
There was a problem hiding this comment.
Pull request overview
Hardens global (user-scope) lifecycle state correctness by (1) making audit/CI checks understand deployment roots outside ~/.apm, (2) stabilizing Hermes as an explicit-only target (not experimental-flag gated), (3) tightening MCP stale-server cleanup to fail closed and preserve user-owned config, and (4) serializing workspace mutations with a cross-process lifecycle lock.
Changes:
- Add a cross-process lifecycle lock and apply it to most CLI state-mutating commands; make install transactions acquire/release the same lock safely across error paths.
- Fix global audit/drift to resolve and compare against external deployment roots (e.g.,
~/.agents,~/.hermes,~/.claude) without mutating those roots. - Make Hermes stable explicit-only (remove experimental flag gating) and extend MCP cleanup to cover Hermes YAML and Antigravity’s user-scope config location.
Reviewed changes
Copilot reviewed 56 out of 56 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_windows_compat_gate_workflow.py | Updates Windows compat gate contract to include one integration lock test path. |
| tests/unit/test_uninstall_engine_helpers.py | Adds failure-mode regression tests ensuring MCP cleanup failures don’t drop lock ownership. |
| tests/unit/test_uninstall_dev_dependencies.py | Updates expected uninstall output to reflect fail-closed MCP cleanup behavior. |
| tests/unit/test_prune_command.py | Adds prune regression test for MCP cleanup failure preserving lock/config bytes. |
| tests/unit/test_mcp_integrator_remove_stale.py | Adds coverage for atomic-failure preservation, Hermes YAML cleanup, and strict malformed shapes. |
| tests/unit/test_cli_consistency.py | Updates compile help assertions for explicit-only Hermes exclusion from all. |
| tests/unit/integration/test_targets.py | Updates Hermes target invariants and removes experimental-flag gating. |
| tests/unit/integration/test_antigravity_target.py | Adds Windows-compat atomic-write/mode preservation coverage for Antigravity MCP config. |
| tests/unit/install/test_workspace_locking.py | Unit contracts for lifecycle lock behavior and error-path release. |
| tests/unit/install/test_install_transaction.py | Adds multi-process serialization tests + interruption/abandonment/repeat-completion lock release coverage. |
| tests/unit/core/test_target_resolution_v2.py | Updates target filtering expectations to keep stable Hermes. |
| tests/unit/core/test_target_detection.py | Removes Hermes from experimental target set characterization. |
| tests/unit/core/test_target_catalog.py | Updates target-set characterization and Hermes profile expectations. |
| tests/unit/commands/test_uninstall_atomic_selection.py | Adds uninstall regression test ensuring MCP cleanup failure preserves lock/config bytes. |
| tests/integration/test_mcp_install_flow.py | Adds global manifest removal + prune flows validating Antigravity MCP cleanup semantics. |
| tests/integration/test_lifecycle_workspace_lock.py | Cross-command subprocess regression test ensuring lifecycle serialization across commands/scope. |
| tests/integration/test_hermes_target.py | Updates Hermes E2E tests for stable explicit-only behavior and MCP selection changes. |
| tests/integration/test_global_audit_deploy_root.py | New integration coverage: global audit resolves external roots read-only and detects drift. |
| src/apm_cli/policy/ci_checks.py | Resolves deployed-file paths for global scope and audits external target roots read-only. |
| src/apm_cli/integration/targets.py | Documentation tweak reflecting Hermes stable explicit-only status. |
| src/apm_cli/integration/mcp_integrator.py | Adds strict config-shape validation, atomic writes, and Hermes YAML MCP stale cleanup. |
| src/apm_cli/integration/mcp_integrator_install.py | Removes Hermes from auto-discovery/experimental opt-in gating. |
| src/apm_cli/install/transaction.py | Makes install transactions acquire/release lifecycle lock safely across failure paths. |
| src/apm_cli/install/phases/targets.py | Removes Hermes experimental enable-hint gate. |
| src/apm_cli/install/locking.py | New lifecycle locking module (FileLock-based) + decorator for command serialization. |
| src/apm_cli/install/drift.py | Adds user-scope replay and external-root drift comparisons with absolute-claim rebasing. |
| src/apm_cli/install/audit_target_roots.py | New helpers to project external target roots into audit scratch + rebase claims. |
| src/apm_cli/install/audit_replay.py | Threads user-scope into CI audit replay preparation and target resolution. |
| src/apm_cli/core/target_detection.py | Adds Hermes to accepted target vocabulary and updates description text. |
| src/apm_cli/core/target_catalog.py | Marks Hermes capability as explicit-only rather than experimental-flag gated. |
| src/apm_cli/core/scope.py | Adds helper to resolve workspace deploy root for user-scope metadata workspaces. |
| src/apm_cli/core/experimental.py | Removes Hermes experimental flag registration. |
| src/apm_cli/commands/update.py | Serializes apm update via lifecycle lock. |
| src/apm_cli/commands/uninstall/engine.py | Broadens stale MCP server set derivation and fails closed on cleanup write errors. |
| src/apm_cli/commands/uninstall/cli.py | Serializes uninstall and fails closed when MCP cleanup fails (prevents persisting dropped ownership). |
| src/apm_cli/commands/prune.py | Serializes prune and integrates MCP cleanup into prune-before-lock-write flow. |
| src/apm_cli/commands/plugin/init.py | Serializes plugin init via lifecycle lock. |
| src/apm_cli/commands/marketplace/plugin/remove.py | Serializes marketplace plugin remove via lifecycle lock. |
| src/apm_cli/commands/marketplace/plugin/add.py | Serializes marketplace plugin add via lifecycle lock. |
| src/apm_cli/commands/marketplace/init.py | Serializes marketplace init via lifecycle lock. |
| src/apm_cli/commands/marketplace/init.py | Serializes marketplace add/update/remove via lifecycle lock. |
| src/apm_cli/commands/lock.py | Serializes lock command execution via lifecycle lock. |
| src/apm_cli/commands/install.py | Serializes install and hardens root-redirect/transaction teardown ordering. |
| src/apm_cli/commands/init.py | Serializes project init via lifecycle lock. |
| src/apm_cli/commands/deps/cli.py | Serializes deps clean/update via lifecycle lock. |
| src/apm_cli/commands/approve.py | Serializes approve/deny via lifecycle lock. |
| src/apm_cli/adapters/client/gemini.py | Switches Gemini config writes to atomic writes with secure permissions. |
| docs/src/content/docs/reference/targets-matrix.md | Updates Hermes status and compilation guidance in targets matrix docs. |
| docs/src/content/docs/reference/manifest-schema.md | Reclassifies Hermes as stable in manifest schema docs. |
| docs/src/content/docs/reference/environment-variables.md | Updates HERMES_HOME semantics for explicit-only Hermes. |
| docs/src/content/docs/reference/cli/experimental.md | Removes Hermes from experimental-flag list. |
| docs/src/content/docs/reference/cli/deps.md | Updates deps target docs for Hermes stable explicit-only behavior and all exclusion. |
| docs/src/content/docs/producer/compile.md | Removes Hermes from experimental-target list in compile docs. |
| docs/src/content/docs/integrations/hermes.md | Updates Hermes integration page to stable explicit-only and MCP behavior. |
| docs/astro.config.mjs | Renames Hermes nav label to non-experimental. |
| .github/workflows/ci.yml | Expands Windows compat gate to include lifecycle subprocess integration contract. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Contributor
Author
|
@microsoft-github-policy-service agree |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
lkshrk (lkshrk)
force-pushed
the
fix/omni-apm-blockers
branch
from
August 23, 2026 12:36
7658e73 to
d5cbf05
Compare
lkshrk (lkshrk)
added a commit
to lkshrk/omni
that referenced
this pull request
Aug 28, 2026
Vanilla apm has no lifecycle serialization of its own (microsoft/apm#2655), so concurrent global installs corrupt the shared workspace.
# Conflicts: # src/apm_cli/install/transaction.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes four global lifecycle correctness issues discovered during Omni's APM hard migration:
Closes #2608.
Safety properties
Validation