Repository navigation
Description
Describe the bug
A user-scope install of an absolute local parent package silently drops that parent's existing relative local child dependency. The CLI exits 0 and reports a successful one-package install, while the child is absent from both the lockfile and native deployments.
This is an outcome/graph-completeness defect, not a request to silently relax the existing rejection of direct relative paths at user scope.
To Reproduce
Use a disposable fixture root and isolated HOME. All paths below labeled /ABS/R must be replaced with the actual absolute fixture root.
- Create
/ABS/R/packages/parent/apm.yml:
name: parent
version: 0.1.0
targets: [cursor]
dependencies:
apm:
- path: ../child- Create
/ABS/R/packages/child/apm.yml:
name: child
version: 0.1.0
targets: [cursor]- Give each package a distinct command source:
parent/.apm/prompts/parent.prompt.mdandchild/.apm/prompts/child.prompt.md, each with a valid description frontmatter and distinct body. For example:
---
description: Local dependency reproduction
---
# Parent command- Create the isolated user's
~/.apm/apm.yml:
name: consumer
version: 0.1.0
targets: [cursor]
dependencies:
apm:
- path: /ABS/R/packages/parent- From a separate consumer directory, run the installed CLI:
apm install --global --target cursor --no-policy --parallel-downloads 0- Inspect
~/.apm/apm.lock.yamland~/.cursor/commands/: only the parent is installed/locked/deployed.
Matched controls, each in a fresh isolated fixture:
| Scope | Parent's child reference | Exit | Locked/deployed packages |
|---|---|---|---|
| Project | ../child |
0 | 2 |
| User | absolute /ABS/R/packages/child |
0 | 2 |
| User | ../child |
0 | 1 |
The fixture verifies that the relative reference resolves against the parent's source directory to an existing child manifest before running APM.
Expected behavior
A successful install must not silently omit a declared dependency. Either resolve the transitive child against its declaring local parent if that behavior is supported, or reject it with a nonzero exit and an actionable diagnostic. Whether to support anchored transitive references while retaining rejection of direct user-relative paths is an explicit contract decision.
Environment (please complete the following information):
- OS: macOS
- Python Version: 3.12.10, locked development dependencies
- APM Version: 0.29.1, source commit
23e921750e5bdb25d02c7b0c71a6b97bd7b851ac, editable installed CLI - VSCode Version (if relevant): N/A
Logs
Representative observed output:
[i] Installing to user scope (~/.apm/)
[>] Resolving /ABS/R/packages/parent...
[>] Resolving ../child...
[+] /ABS/R/packages/parent (local)
|-- 1 commands integrated -> .cursor/commands/
[*] Installed 1 APM dependency in 0.1s.
Exit status is 0. The child lock entry and command file are missing.
Additional context
Discovered while independently hardening the APMLifecycle interaction campaign after #2809 / during rework of #2813. Reproduced by both the implementation engineer and coordinating engineer. A focused unskipped regression with the three controls exists in the current, not-yet-published test-only worktree: tests/integration/test_primitive_target_covering_array.py::test_local_transitive_command_scope_parity.
Source evidence at the tested commit: src/apm_cli/install/phases/resolve.py:557-570 rejects every relative local ref at USER scope before the declaring-parent source anchor at lines 580-583. This path records a callback failure but the observed overall command still succeeds. The locally available origin/main at 7f36da6e61fd5cebe29c16ced77fb4351823ec06 had an identical src tree; this is not a claim about subsequently fetched main.
Generalized properties: outcome.status_matches_state, dependency-graph completeness. This report does not authorize production changes or Phase 3 transaction redesign.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
test(architecture): register local scope admission in fixed inventory
github-actions commentedon Sep 9, 2026
Triage decision
accept
Proposed labels
Milestone
null -- open-milestone read failed (401 from milestones API); no milestone assigned this run.
Suggested next action
Decide and implement the explicit contract for anchored local transitive references at user scope (resolve against the declaring parent, or reject with nonzero exit and diagnostic), then close the silent-success gap in resolve.py:557-583.
Suggested issue comment
Per-lens notes (collapsed)
DevX UX Expert -- User-Need Reviewer
A user-scope install reporting success while silently dropping a declared dependency directly violates the outcome.status_matches_state contract users rely on to trust
apm install's exit code.Supply Chain Security Expert -- Risk-Surface Reviewer
No new risk surface; this is a completeness/consistency defect in dependency resolution, not a trust boundary change.
OSS Growth Hacker -- Contributor-Tone Reviewer
Not activated -- danielmeppiel is a maintainer-level reporter with many prior interactions on this repo.
Python Architect -- Architecture Reviewer
The issue explicitly frames an open contract decision (anchor transitive references against the declaring parent vs. reject with diagnostic) -- this is exactly the kind of interface decision Python Architect should weigh in on, but since the issue is already status/accepted and in active shepherding, I'm not overriding that status; flagging the contract choice in the next action instead of forcing needs-design over an already-in-flight fix.
Doc Writer -- Documentation Reviewer
Not activated -- this is an internal resolution-graph contract fix; no new user-facing doc surface is implied beyond existing dependency reference docs.
APM CEO -- Triage Arbiter
Already accepted and actively shepherded -- ratifying the existing status, adding theme/portability + area/lockfile for taxonomy completeness and status/triaged to exit the untriaged queue. No milestone change (milestone read failed this run; existing state left untouched).
{ "decision": "accept", "decision_detail": "Already status/accepted and in shepherding; taxonomy labels added.", "theme": "theme/portability", "areas": ["area/lockfile"], "type": "type/bug", "status": "status/accepted", "priority": null, "preserved_labels": [], "milestone": null, "next_action": "Decide and implement the explicit contract for anchored local transitive references at user scope (resolve against the declaring parent, or reject with nonzero exit and diagnostic), then close the silent-success gap in resolve.py:557-583.", "comment_markdown": "Already accepted and in shepherding per existing labels -- adding theme/portability and area/lockfile for the taxonomy sweep, plus status/triaged so this doesn't re-enter the daily untriaged queue. The outcome/graph-completeness framing (successful exit must not silently omit a declared dependency) matches how we've been tracking this class of defect." }github-actions commentedon Sep 10, 2026
Triage decision
accept
Proposed labels
Milestone
null
Suggested next action
Fix graph-completeness so a relative local child dependency of an absolute local parent is resolved and recorded at user scope, and add a regression test asserting exit code 0 implies both packages are present in lockfile and native deployment.
Suggested issue comment
Per-lens notes (collapsed)
DevX UX Expert -- User-Need Reviewer
Silent success with missing dependencies is one of the worst DX failure modes for a package manager -- users trust exit 0 to mean "everything installed." The report is careful to scope this as a completeness bug, not a request to relax existing local-path security rules, which keeps the fix narrow and safe.
Supply Chain Security Expert -- Risk-Surface Reviewer
Touches lockfile graph resolution (area/lockfile). The existing rejection of direct relative local paths at user scope is a deliberate trust boundary and must be preserved exactly as-is; only the completeness of resolving an already-authorized parent's child should change.
OSS Growth Hacker -- Contributor-Tone Reviewer
Not activated -- author_association is COLLABORATOR.
Python Architect -- Architecture Reviewer
Not activated -- this is a bounded graph-resolution completeness fix within existing dependency-resolution code, not a new interface or schema change.
Doc Writer -- Documentation Reviewer
Not activated -- no doc surface change implied; this is an internal correctness fix to existing documented behavior.
APM CEO -- Triage Arbiter
Clear, well-isolated correctness bug from a trusted collaborator with a full repro and exact commands. Accepting as theme/portability, area/lockfile, type/bug.
{ "decision": "accept", "decision_detail": "", "theme": "theme/portability", "areas": ["area/lockfile"], "type": "type/bug", "status": "status/accepted", "priority": null, "preserved_labels": [], "milestone": null, "next_action": "Fix graph-completeness so a relative local child dependency of an absolute local parent is resolved and recorded at user scope, and add a regression test asserting exit code 0 implies both packages are present in lockfile and native deployment.", "comment_markdown": "Confirmed as an outcome/graph-completeness defect, not a request to relax the existing relative-path rejection at user scope. A user-scope install of an absolute local parent should still resolve and record its relative local child rather than silently dropping it while exiting 0. This is accepted; a regression test asserting lockfile + native deployment completeness alongside exit code 0 should accompany the fix." }danielmeppiel commentedon Sep 12, 2026
At the lead maintainer's direction, the current acceptance of this item is withdrawn as part of APM's roadmap and contribution reset. Previous acceptance labels or comments must not be treated as approval to start or continue substantive implementation for inclusion in APM.
Thank you for the work and ideas already contributed. Our small maintainer team needs to agree supported scope and review capacity before inviting more implementation. This is not a rejection of the proposal or a judgment of your work, and it does not undo completed work or erase its history.
Please follow the contribution rules: a responsible human maintainer needs to record the bounded scope, acceptance criteria and review contact on the issue before substantive work resumes. Existing issue discussion, assignments and contributions remain available for that decision. Trivial typo and broken-link corrections retain their standing preapproval.
danielmeppiel commentedon Oct 20, 2026
Decision: approve
Area: project
Scope: Repair truthful failure reporting for the demonstrated local-dependency install cases without expanding admission. A rejected or unresolved required local dependency must produce a nonzero exit and an actionable diagnostic instead of a complete-success summary for an incomplete graph. Keep relative local children unsupported at user/global scope in this repair; preserve existing successful project-relative and absolute-global local workflows. Update practical guidance to distinguish local authoring from author-prepared portable releases using existing package references.
Done when: Real installed-CLI APMLifecycle coverage asserts nonzero exit, named parent/dependency and reason for the global relative-child omission case, direct-relative user-manifest rejection and missing-child failures; matched successful project-relative and absolute-global controls retain the expected lock entries and actual native output. A clean-consumer regression fixture proves the documented existing remote-package route without the producer workspace. Preserve remote-repository containment, local-copy symlink and destination boundaries, policy, ownership and unrelated user files. Explain that global scope selects deployment location rather than publication or portability; do not recommend producer-specific absolute paths as a production fix or claim uniform publication validation.
Out of scope: New global relative-child support or direct/unanchored user-relative admission; removal of existing supported local features; cwd/HOME/apm_modules or upstream-source fallback; automatic dependency publication or rewriting, workspace versioning, new path syntax, symlink modes, source adapters or mandatory registry adoption; uniform registry publication validation; weakened safety or policy boundaries; cross-scope lookup, general resolver or audit redesign, broad transaction/rollback work or atomic-failure guarantees; assignment changes, reopening #2919, approval or restart of #2820, release promises, automated implementation dispatch or restarting blocked delivery.
Review contact: Daniel Meppiel (@danielmeppiel)
danielmeppiel commentedon Oct 20, 2026
Accepting a narrowed correctness repair: fail clearly when a required local dependency is rejected or cannot be resolved; do not add global relative-child support in this issue.
For the reported example, installing an absolute local parent globally when it declares
../childmust return a nonzero exit and explain the unsupported child reference. Reporting a complete one-package installation while silently omitting the child is the bug. Existing successful project-relative and absolute-global local workflows remain supported.Local development and distribution are different contracts. For example:
frontend-teamcan reference the sibling../company-basics.company-basicsavailable and prepares the released manifest with an existing reference such asacme/company-basics#v1.2.0.--globalselects user-level deployment; it does not publish dependencies or make local paths portable. Replacing a relative reference with/Users/alice/work/company-basicsis not a production portability solution. Existing supported bundles and contained same-repository remote dependencies remain valid; APM will not guess package identities, publish children or rewrite arbitrary paths.The tradeoff is deliberate: this scope retains the project/global asymmetry while correcting false success. Uniform publication validation, including the separate experimental registry publishing path, is not covered or claimed solved here. That needs its own bounded decision.
Completion requires installed-CLI failure and successful-control cases with exit status, useful diagnostics, lock entries and actual native output, plus the clean-consumer fixture and practical guidance in the scope record. Preserve containment, policy and ownership. No transaction/rollback guarantee is added.
This is fresh bounded scope after the September 12 withdrawal, not approval of the earlier broader recommendations. Keep the issue open for this repair and preserve the existing assignment. It does not restart #2919, #2820 or blocked delivery.