Skip to content

fix(pack): route empty dependencies bundle (supersedes #2447, closes #2431) - #2458

Merged
Daniel Meppiel (danielmeppiel) merged 3 commits into
mainfrom
supersede/pr-2447
Aug 4, 2026
Merged

fix(pack): route empty dependencies bundle (supersedes #2447, closes #2431)#2458
Daniel Meppiel (danielmeppiel) merged 3 commits into
mainfrom
supersede/pr-2447

Conversation

@danielmeppiel

Copy link
Copy Markdown
Collaborator

fix(pack): route empty dependencies bundle

TL;DR

apm pack now treats dependencies: {} as a declared dependency mapping and emits the local bundle. Omitted and null dependencies: values still do not select bundle output. The packaged CLI lifecycle proves that a Copilot package receives its root skill, bundle, and .github/plugin/plugin.json together.

Note

Supersedes #2447 and closes #2431.

Problem (WHY)

  • [BUG] apm pack does not produce bundle when dependencies: {} #2431 reported that dependencies: {} exited successfully but did not create a bundle directory.
  • A truthiness predicate in detect_outputs treated an explicit empty mapping like no declaration.
  • [!] Producer docs used inconsistent language for empty, omitted, and null dependency declarations.

Why this matters: "Grounding outputs in deterministic tool execution transforms probabilistic generation into verifiable action."

Approach (WHAT)

# Fix
1 Select BundleProducer when dependencies is non-null, including {}.
2 Preserve no-bundle behavior for omitted and null declarations.
3 Exercise the packaged Copilot lifecycle and align every affected producer reference.

Implementation (HOW)

  • src/apm_cli/core/build_orchestrator.py -- replaces the truthiness check with a non-null declaration check at the canonical output-routing boundary.
  • tests/unit/core/test_build_orchestrator.py -- guards empty-mapping routing and null omission semantics.
  • tests/integration/test_pack_root_skills_e2e.py -- invokes the installed CLI with target: copilot, an empty mapping, and a root skill; it asserts both build and manifest outputs.
  • Producer and APM usage docs -- use one canonical rule: an explicit mapping, including {}, bundles; omitted or null does not. The panel fold also removes duplicate apm pack command rows.

Diagrams

Legend: the dashed decision is the changed routing rule; a declared empty mapping now reaches the bundle producer without altering the independent Copilot manifest path.

flowchart LR
    subgraph Parse[Parse]
        M["apm.yml"]
        D["detect_outputs"]
    end
    subgraph Produce[Produce]
        B["BundleProducer"]
        P["PluginManifestProducer"]
    end
    M --> D
    D -->|"dependencies is not null"| B
    D -->|"target is copilot"| P
    B --> S["build skills root-skill SKILL.md"]
    P --> G[".github plugin plugin.json"]
    classDef new stroke-dasharray: 5 5;
    class D new;
Loading

Trade-offs

  • Non-null declaration check. Chose is not None instead of truthiness so {} is intentional while omitted and null remain distinct.
  • Lifecycle plus unit proof. The packaged CLI test costs more than a unit test but proves emitted artifacts on the user-facing command path.
  • No marketplace predicate change. Marketplace has no valid empty-mapping output contract, so its existing truthiness check remains outside this fix.

Benefits

  1. dependencies: {} produces exactly one local bundle directory.
  2. Copilot-targeted local packages emit both skills/root-skill/SKILL.md in the bundle and .github/plugin/plugin.json.
  3. Omitted and null dependency declarations continue to omit bundle output.
  4. Producer and agent-facing command references describe the same three-state contract.

Validation

uv run --extra dev pytest tests/unit/core/test_build_orchestrator.py -q:

38 passed in 0.76s

APM_E2E_TESTS=1 uv run --extra dev pytest tests/integration/test_pack_root_skills_e2e.py::test_pack_empty_dependencies_creates_bundle_and_copilot_manifest -q:

1 passed in 0.92s
Lint and architecture gates
All checks passed!
1595 files already formatted
Your code has been rated at 10.00/10
[+] auth-signal lint clean
[+] architecture boundary lint clean

The new empty-mapping regression test failed when the production guard was reverted to the prior truthiness predicate, then passed after restoration.

Scenario Evidence

# Scenario (user promise) Principle(s) Test(s) proving it Type
1 A local-only Copilot package with dependencies: {} can pack its root skill, bundle, and plugin manifest. Multi-harness support, DevX (pragmatic as npm) tests/unit/core/test_build_orchestrator.py::TestDetectOutputs::test_empty_dependencies_mapping_returns_bundle (regression-trap for #2431)
tests/integration/test_pack_root_skills_e2e.py::test_pack_empty_dependencies_creates_bundle_and_copilot_manifest
unit, e2e
2 A project with omitted or null dependencies: does not receive a bundle unexpectedly. DevX (pragmatic as npm) tests/unit/core/test_build_orchestrator.py::TestDetectOutputs::test_null_dependencies_does_not_return_bundle
tests/unit/core/test_build_orchestrator.py::TestDetectOutputs::test_neither_block_returns_empty
unit

How to test

  • Create apm.yml with target: copilot and dependencies: {}; add skills/root-skill/SKILL.md and an empty apm.lock.yaml.
  • Run apm pack --format plugin --verbose; expect exit code 0.
  • Confirm build/<name>-<version>/skills/root-skill/SKILL.md and .github/plugin/plugin.json exist.
  • Replace the mapping with an omitted or null dependencies: value; expect no bundle selection.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clarify that only dependency mappings select bundle output and prevent null values from regressing to a bundle producer. Addresses the review-panel DevX follow-ups for PR #2447.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fold panel documentation follow-ups so every producer-facing reference distinguishes an explicit empty dependencies mapping from omitted and null declarations.

Addresses apm-review-panel follow-ups for #2447.

Co-authored-by: danielmeppiel <danielmeppiel@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes apm pack output routing so that an explicitly declared empty dependency mapping (dependencies: {}) is treated as intentional and triggers bundle production, while omitted or null dependencies: continues to produce no bundle. It also adds regression coverage and aligns user-facing docs so the three-state contract (omitted vs null vs mapping/empty mapping) is described consistently.

Changes:

  • Update detect_outputs() to select BundleProducer when dependencies is present and non-null (including {}).
  • Add unit + packaged CLI integration coverage for the empty-mapping and null/omitted behaviors.
  • Update reference + producer + agent-facing docs to document the same empty/omitted/null dependency selection rules.
Show a summary per file
File Description
src/apm_cli/core/build_orchestrator.py Switch bundle selection from truthiness to an explicit non-null dependencies check; update module docstring to mention {}.
tests/unit/core/test_build_orchestrator.py Add regression tests proving {} selects bundle while null does not.
tests/integration/test_pack_root_skills_e2e.py Add a lifecycle_smoke packaged-CLI test asserting bundle + Copilot plugin manifest are emitted with dependencies: {}.
packages/apm-guide/.apm/skills/apm-usage/package-authoring.md Document the empty-mapping vs omitted/null dependency behavior for bundle production.
packages/apm-guide/.apm/skills/apm-usage/commands.md Update apm pack command reference to explicitly describe {} vs omitted/null behavior.
docs/src/content/docs/reference/cli/pack.md Update CLI reference to state that an empty mapping produces a bundle while omitted/null does not.
docs/src/content/docs/producer/repo-shapes.md Clarify marketplace-only repo shape produces no bundle when dependencies: is omitted.
docs/src/content/docs/producer/publish-to-a-marketplace.md Align marketplace publishing guidance with the explicit-mapping (incl. {}) bundle selection rule.
docs/src/content/docs/producer/pack-a-bundle.md Add a short, explicit note that dependencies: {} selects bundle output and omitted/null does not.

Review details

  • Files reviewed: 9/9 changed files
  • Comments generated: 0
  • Review effort level: Lite

@danielmeppiel
Daniel Meppiel (danielmeppiel) merged commit 48c6a95 into main Aug 4, 2026
20 checks passed
@danielmeppiel
Daniel Meppiel (danielmeppiel) deleted the supersede/pr-2447 branch August 4, 2026 06:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] apm pack does not produce bundle when dependencies: {}

2 participants