[BUG] Make dependency resolution transactional so a corrected cyclic graph resumes without manual apm_modules deletion#2142
[BUG] Make dependency resolution transactional so a corrected cyclic graph resumes without manual apm_modules deletion#2142danielmeppiel wants to merge 3 commits into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR makes dependency resolution transactional by tracking and rolling back only the apm_modules/ paths that a failed resolution attempt staged or replaced (not a blanket cache deletion). This specifically addresses cyclic-graph failures leaving behind stale snapshots that poison subsequent installs.
Changes:
- Adds
ResolutionStagingSession+transactional_resolutiondecorator to back up/restore per-path mutations underapm_modules/. - Wraps the resolve phase so resolution writes are rolled back on resolution-time exceptions (including circular dependency rejection).
- Adds regression tests and updates troubleshooting docs to reflect resumable retries after fixing a cycle.
Show a summary per file
| File | Description |
|---|---|
src/apm_cli/install/resolution_staging.py |
Introduces a per-install staging session that backs up replaced paths and can rollback/commit atomically. |
src/apm_cli/install/phases/resolve.py |
Wraps dependency resolution in the transactional staging boundary and prepares install paths before mutation. |
tests/unit/install/test_resolution_transactionality.py |
Adds regression coverage for rollback correctness and for “fix cycle then rerun” without manual cache deletion. |
docs/src/content/docs/troubleshooting/install-failures.md |
Documents that cyclic-graph retries no longer require manual apm_modules/ deletion. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 2
- Review effort level: Low
apm-spec-waiver: Transactional resolution staging enforces existing install atomicity expectations; no new OpenAPM artifact or wire behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Superseded by #2155. The reliability campaign consolidated all 13 point fixes into a single architectural cure PR that re-homes each fix under its canonical owner module and adds owner-invariant guards. The fix for #2140 is folded into #2155 and re-verified there (full CI green). Closing this point PR in favor of the consolidated cure; the branch is preserved and this can be reopened if #2155 is not merged. |
fix(install): make dependency resolution transactional
TL;DR
A failed cyclic dependency resolution now rolls back only the
apm_modules/paths staged or replaced by that attempt. After the user fixes the source graph, a normalapm installsucceeds without manually deletingapm_modules/, while valid pre-existing cache entries remain protected.Note
Fixes #2140. This deliberately does not use a blanket delete-all recovery path.
Problem (WHY)
apm_modules/.rm -rf apm_modules, discarding unrelated valid cache entries.Approach (WHAT)
Implementation (HOW)
src/apm_cli/install/resolution_staging.pyResolutionStagingSessionand transaction decorator. Existing paths are atomically moved to session backups; rollback restores them in reverse order.src/apm_cli/install/phases/resolve.pytests/unit/install/test_resolution_transactionality.pydocs/src/content/docs/troubleshooting/install-failures.mdapm_modules/deletion.Diagram
Legend: dashed nodes are the new transaction boundary around existing resolution and validation.
flowchart LR S[Source manifests] --> P[Prepare touched path] P --> M[Materialize package snapshot] M --> V{Graph valid} V -->|yes| C[Discard session backups] V -->|no| R[Remove new snapshots and restore backups] R --> X[Correct source and retry] classDef new stroke-dasharray: 5 5; class P,C,R new;Trade-offs
apm_modules/; unrelated valid cache entries are preserved.apm_modules/over copying the full cache; path replacement stays atomic without cache-sized copy cost.Benefits
Validation
Scenario evidence
apm_modules/; install succeeds.tests/unit/install/test_resolution_transactionality.py::test_corrected_local_cycle_resumes_without_manual_cache_deletion(regression-trap for #2140)tests/unit/install/test_resolution_transactionality.py::test_resolution_rollback_restores_replaced_cache_pathTest and lint evidence
Base regression run before production changes:
Regression after the fix:
Targeted install suite:
CI lint mirror:
How to test
apm install --target copilot --verboseand expect exit 1 with no A/B snapshots retained.apm_modules/.apm.lock.yamland.github/instructions/package-a.instructions.mdexist.Fixes #2140
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com