Fix --skill to merge additively with existing skills in apm.yml#1786
Merged
danielmeppiel merged 3 commits intoJun 19, 2026
Merged
Conversation
When running `apm install repo --skill qa` on a package that already has `skills: [grill-me]` in apm.yml, the CLI now merges the new name into the existing list (producing `skills: [grill-me, qa]`) instead of replacing it. - Extract `normalize_and_merge_skill_subset()` helper into `package_resolution.py` to keep install.py within its line budget. - Add `get_existing_skill_subset()` to read persisted skills: from current_deps by identity. - Update test expectations: skill_subset is now always sorted (matches the existing `to_apm_yml_entry()` and `parse_from_dict()` contracts). - Add integration-level tests proving repeated --skill invocations are additive and that no duplicates are introduced. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes apm install ... --skill so it merges additively with any already-persisted skills: list in apm.yml (instead of replacing it), enabling incremental skill subset building across multiple installs.
Changes:
- Add
get_existing_skill_subset()+normalize_and_merge_skill_subset()helpers to read/merge persistedskills:for a dependency identity. - Update install resolution to set
dep_ref.skill_subsetvia the new merge helper when--skillis provided. - Add/adjust unit tests covering persisted-skill readback and additive merge behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/apm_cli/install/package_resolution.py |
Adds helpers to read existing skills: from the manifest and merge them with CLI --skill. |
src/apm_cli/commands/install.py |
Uses the new helper to make --skill additive for existing manifest entries. |
tests/unit/test_skill_subset_persistence.py |
Adds tests for reading existing persisted skills and validating additive merges in _resolve_package_references. |
tests/unit/commands/test_install_skill_subset.py |
Updates expected normalized ordering to match the now-sorted behavior. |
- Remove the intermediate normalized list that was never used in the return value; build only the seen set and return sorted(seen). - Update test docstring to say 'result is sorted' instead of 'preserving order' since the behaviour is now sorted output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
danielmeppiel
approved these changes
Jun 16, 2026
sergio-sisternes-epam
pushed a commit
that referenced
this pull request
Jun 19, 2026
Resolve strangler-fig conflicts: keep HEAD's relocated structure and fold main's #1786 additive-skill delta into install/pkg_resolution.py via normalize_and_merge_skill_subset. Shed mcp_integrator.py back under the 800-line gate by extracting _is_vscode_available into the new integration/mcp_vscode.py sibling (re-exported for the existing import and patch seams); repoint MCP shutil/Path patch targets to mcp_vscode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Was this released already? doesn't seem so from the latest version I am using so want to double check... |
danielmeppiel
added a commit
that referenced
this pull request
Jun 29, 2026
CI Stage-1 tightened the file-length guardrail to 2100 lines (was 2450); main's install.py already sits at 2099, so the additive --skill fix pushed it to 2116 and tripped the guard. Move the skill-pin handling into package_resolution.py -- the module that exists to keep the command module small: - cli_skill_subset(skill_names): normalize raw --skill names to a subset (None for absent / '*'), lifting the inline block out of install(). - apply_cli_skill_pin(...): attach/merge the additive pin (#1771) or reset to the full bundle on --skill '*' (#1786), deriving identity/canonical from the reference so the call site stays compact. install.py drops from 2116 to 2100 (== cap, passes the > comparison). Behaviour unchanged: parity suite + full install/commands unit dirs green (2817 passed); ruff, R0801, auth-signal, and file-length guards all clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
danielmeppiel
added a commit
that referenced
this pull request
Jun 29, 2026
The deployment/lockfile parity fix lands under install/ (an OpenAPM critical path) but introduces no net-new wire-format behaviour: the lockfile skill_subset field format and semantics are unchanged, and PR #1786 established the additive --skill contract without a spec requirement, so no anchor/manifest row applies. Re-triggers the spec-conformance workflow to re-read the PR-body waiver. apm-spec-waiver: bug fix to apm-CLI --skill additive deploy parity; no net-new OpenAPM wire-format surface -- lockfile skill_subset field/semantics unchanged; #1786 established the additive --skill contract without a spec requirement. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
danielmeppiel
added a commit
that referenced
this pull request
Jun 29, 2026
…llow-up) (#1955) * Fix: make --skill deployment additive, not just persistence (#1786 follow-up) PR #1786 made apm.yml/lockfile persistence of --skill subsets additive, but the deployment path still used the raw CLI subset. A second `apm install <bundle> --skill B` deployed only B and the stale-file cleanup deleted the previously deployed skill A from the target folder, so manifest and on-disk state diverged until the next bare install. Changes: - New shared helper `effective_deploy_skill_subset()` in package_resolution.py: deploy the UNION of the persisted apm.yml `skills:` and the current CLI `--skill` values; `--skill '*'` returns None (deploy all). - template.py: deploy via the helper instead of the raw CLI subset. - phases/lockfile.py: `_attach_skill_subset_override` now unions the CLI values with the persisted subset so the lockfile matches what was deployed. - install.py: `--skill '*'` now resets the apm.yml `skills:` pin back to the full bundle (the documented "reset to all skills" contract), so manifest and on-disk state agree after a reset. Adds regression tests covering the helper's union/reset semantics and an e2e suite (additive deploy-on-top, bare reinstall, --skill '*' reset, manifest reduction cleanup, uninstall removes the union). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fold review-panel follow-ups: additive --skill deploy parity Round-1 apm-review-panel returned ship_with_followups (zero blocking). Fold all five in-scope CEO-curated recommendations: - lockfile.py: pass ctx.skill_subset_from_cli to effective_deploy_skill_subset instead of hardcoded True (consistency with template.py; defensive against future non-CLI callers). [py-architect + supply-chain convergent] - template.py: hoist effective_skill_subset to a named local and emit a verbose breadcrumb naming retained (previously-pinned) skills when the additive union exceeds the CLI request. [cli-logging] - install.py: verbose breadcrumb on --skill '*' pin reset; expand --skill help text to document additive union + single-skill removal path. [cli-logging + devx-ux] - docs/install.md + apm-usage/commands.md: document --skill additive-across- installs union + removal path (doc-sync Rule 4). [doc-writer] - CHANGELOG: add Unreleased Fixed entry framed as user-promise restoration. [growth] Breadcrumbs are verbose-only (verbose_detail), ASCII-only; no change to default output. Parity suite 11 passed; full lint chain green. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Extract --skill pin helpers to keep install.py under the 2100-line cap CI Stage-1 tightened the file-length guardrail to 2100 lines (was 2450); main's install.py already sits at 2099, so the additive --skill fix pushed it to 2116 and tripped the guard. Move the skill-pin handling into package_resolution.py -- the module that exists to keep the command module small: - cli_skill_subset(skill_names): normalize raw --skill names to a subset (None for absent / '*'), lifting the inline block out of install(). - apply_cli_skill_pin(...): attach/merge the additive pin (#1771) or reset to the full bundle on --skill '*' (#1786), deriving identity/canonical from the reference so the call site stays compact. install.py drops from 2116 to 2100 (== cap, passes the > comparison). Behaviour unchanged: parity suite + full install/commands unit dirs green (2817 passed); ruff, R0801, auth-signal, and file-length guards all clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(spec): waive Mode B gate for additive --skill deploy bug fix The deployment/lockfile parity fix lands under install/ (an OpenAPM critical path) but introduces no net-new wire-format behaviour: the lockfile skill_subset field format and semantics are unchanged, and PR #1786 established the additive --skill contract without a spec requirement, so no anchor/manifest row applies. Re-triggers the spec-conformance workflow to re-read the PR-body waiver. apm-spec-waiver: bug fix to apm-CLI --skill additive deploy parity; no net-new OpenAPM wire-format surface -- lockfile skill_subset field/semantics unchanged; #1786 established the additive --skill contract without a spec requirement. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(install): fold review-panel round-2 nits for --skill parity Add hermetic unit coverage for the two helpers the additive --skill deploy fix relies on, and tighten doc + lockfile clarity per the panel: - cli_skill_subset: absent / '*' / named / mixed-'*' normalization - apply_cli_skill_pin: '*' reset branch (clears pin, records full-bundle apm.yml entry) and bare-install no-op branch - docs: package-types.md additive cross-ref; install.md additive example - lockfile.py: explicit `list(merged) if merged else []` + guard comment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: danielmeppiel <danielmeppiel@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collaborator
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.
Description
Running
apm install repo --skill qaon a package that already hasskills: [grill-me]inapm.ymlwas replacing the list with[qa]instead of merging to[grill-me, qa]. This madeit impossible to incrementally build a skill subset across multiple install invocations.
The fix reads the existing
skills:list from the manifest before applying the CLI value andproduces a deduplicated, sorted union -- matching the existing conventions in
parse_from_dict(sort on parse) and
to_apm_yml_entry(sort on emit). The--skill '*'reset-to-all behaviouris unchanged.
Fixes: #1771
Type of change
Testing
Spec conformance (OpenAPM v0.1)