Skip to content

[BUG] apm install --update writes duplicate deployed_files entries and churns unrelated lockfile deps #1558

@danielmeppiel

Description

@danielmeppiel

Summary

Running apm install -g <pkg>#<ref> --update against ~/.apm/apm.yml mutates the lockfile in two unwanted ways:

  1. Duplicate entries in deployed_files for packages whose deployment path is currently double-walked. Same package's deployed_hashes map has only one entry per path -- so the asymmetry shows the dedup is half-implemented.
  2. Unrelated-dep churn: passing --update for one named CLI package re-resolves and re-writes lockfile entries for other packages too, even when their refs haven't changed upstream.

Together this makes apm install -g ... --update non-deterministic for state-correctness review (e.g. git diff ~/.apm/apm.lock.yaml) and inflates the diff a maintainer has to scan to confirm a change was safe.

Repro

State: ~/.apm/apm.yml lists obra/superpowers (unpinned), github/awesome-copilot/plugins/azure-cloud-development (unpinned), and a few others. ~/.apm/apm.lock.yaml already at HEAD for all.

$ apm install -g 'danielmeppiel/genesis#main' --update
[*] Installed 6 APM dependencies in 29.9s.

Lockfile diff (obra/superpowers entry only -- I did not touch it):

+  - .copilot/hooks/scripts/superpowers/hooks/run-hook.cmd
+  - .copilot/hooks/scripts/superpowers/hooks/run-hook.cmd       # ← dup
+  - .copilot/hooks/superpowers-hooks-cursor.json
+  - .copilot/hooks/superpowers-hooks-cursor.json                # ← dup
+  - .copilot/hooks/superpowers-hooks.json
+  - .copilot/hooks/superpowers-hooks.json                       # ← dup

The corresponding deployed_hashes: block has one entry per path:

deployed_hashes:
  .copilot/hooks/scripts/superpowers/hooks/run-hook.cmd: sha256:d3d9c619...
  .copilot/hooks/superpowers-hooks-cursor.json: sha256:53d8ceb3...
  .copilot/hooks/superpowers-hooks.json: sha256:a510fbce...

So deployed_files is the only field with the dup; the integrity-tracking field is consistent. That's smoking-gun evidence the duplicate is a list-append bug in whatever populates deployed_files, not a legitimate per-target deployment.

Separately, awesome-copilot got + .codex/agents/azure-*.toml lines added -- not because Codex deployment changed, but because the prior lockfile predates the dep's Codex coverage and --update re-walked all integrators across all deps.

Why this matters

  • State-correctness review hygiene. A maintainer running apm install -g <one-pkg> --update reasonably expects the lockfile diff to scope to that one package + its transitives. Scope creep across unrelated deps makes "did this CLI invocation do what I expected?" much harder to verify.
  • apm doctor-style consistency checks that compare deployed_files to actual on-disk files will tolerate dups today but degrade reliably over time -- bug surface is one rename / one normalization away.
  • Reproducibility of --frozen installs depends on lockfile content being canonical; duplicate entries break "two valid lockfiles for the same state are byte-identical".

Suggested fix

  1. Dedup deployed_files at write time -- mirror the dedup that's already happening in deployed_hashes. Likely a single sorted(set(...)) at lockfile-serialization time.
  2. Scope --update re-walk to packages whose ref or content actually changed (or to the explicit CLI arg list when one is passed) -- don't re-emit lockfile entries for unrelated deps just because they share an integrator.
  3. Add a regression test that runs apm install -g <pkg> --update twice with no upstream changes and asserts git diff apm.lock.yaml is empty after the second run.

Environment

Related

Metadata

Metadata

Assignees

Labels

type/bugSomething does not work as documented.

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions