refactor(core): consolidate red-team lifecycle fixes behind canonical owners#2155
Conversation
Return exit code 1 when every positional package fails validation, matching manifest installs and the documented exit contract. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Ensure generated Copilot hook JSON defaults the required top-level version to 1 and cover it with a regression test. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Mark the validation summary as rendered before exiting so a clean total-validation failure does not append a misleading interruption warning. Addresses the CLI logging panel follow-up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Make the existing integration test require exit code 1 so it traps the positional total-failure regression instead of passing on error text alone. Addresses the test coverage panel follow-up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Record the corrected positional total-failure exit status under Unreleased so CI users can identify the reliability fix. Addresses the OSS growth panel follow-up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Resolve the Unreleased changelog overlap by retaining both reliability fixes before running the merge-commit CI mirror. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Protect the non-overwrite half of the schema-version fix with a regression test, addressing the review panel's test-coverage follow-up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Assert that validation ran without pinning the implementation to exactly one probe, preserving the user-visible exit and message contract. Addresses Copilot inline comment 3561124008. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
GitHub did not register pull_request workflow runs for the previous synchronize event, so retrigger the CI webhook without changing the reviewed tree. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Assert the required Copilot hook schema version at the real install-service dispatch tier, addressing the final panel coverage follow-up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Retain both concurrent Unreleased reliability entries while restoring mergeability and CI merge-commit parity. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Correct the zero-primitives progress message, type the pytest fixture, and lock the validate boundary with a mutation-proven regression test. Addresses panel and Copilot follow-ups. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Centralize managed deployment-root derivation, keep absolute path validation on the shared containment guard, add direct serialization coverage, and record the fix in the changelog. Addresses panel follow-ups from PR #2135. apm-spec-waiver: harness-install reliability fix for Claude CLAUDE_CONFIG_DIR outside HOME; no OpenAPM artifact or wire behavior change Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reuse the broadened empty-output signal for formatter suppression and document the validation/watch caller boundary. Addresses the final Python architecture panel follow-up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Qualify path containment guidance for global installs using configured target roots. Addresses the final supply-chain panel finding for PR #2135. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Suppress the contradictory zero-output warning for expected orphan cleanup, preserve hand-authored files without irrelevant duplicate-context advice, and add mutation-proven message regressions. Addresses the terminal logging and architecture panel findings. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Derive compile and install target help from the accepted target catalog, and use the same catalog for unknown-target guidance. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ellij The kiro discoverability test hard-coded the brittle 'all' target join (copilot+...+kiro), which the accepted-target catalog now supersedes as the single source of the help Values list. Assert each advertised target -- including the MCP-only intellij target this PR adds -- is discoverable in both install and compile help instead. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The stricter APMPackage.from_apm_yml identity validation (this PR) is the correct authority for audit/policy surfaces, but it leaked into the deps list/info display helpers: a manifest that merely empties 'version' now raised, collapsing the graceful '@unknown' render into an alarming '@error' that masks the package. Add a shared _tolerant_identity fallback so the display surface stays lenient (empty/missing version -> unknown) while genuinely unparsable YAML still reports error. Make deps info symmetric with deps list and cover both with regressions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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>
apm-spec-waiver: Deployment reconciliation gives update/compile the parity install already has; enforces existing lockfile ownership semantics, no new OpenAPM wire behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python architect | 1 | 2 | 0 | Contract, output-mode, and IR findings were folded. |
| CLI logging expert | 1 | 2 | 0 | Traceback redaction, output aliases, and failure wording were folded. |
| DevX UX expert | 3 | 2 | 0 | Compatibility, cancellation, registry identity, and recovery prose were folded. |
| Supply-chain security expert | 4 | 0 | 0 | Registry, auth, lockfile, and hook fail-closed gaps were folded. |
| OSS growth hacker | 0 | 2 | 0 | Lifecycle and release prose now lead with user outcomes. |
| Auth expert | 2 | 1 | 0 | Provider conflicts and inherited Git authorization channels were fixed. |
| Doc writer | 0 | 4 | 0 | Verified lifecycle, policy, registry, and contract drift was corrected. |
| Test coverage expert | 3 | 2 | 0 | CLI exit, post-hook, lockfile roundtrip, and scenario evidence were added. |
| Performance expert | 1 | 1 | 0 | Local DAG amplification and unbounded runtime buffering were fixed. |
B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength from the initial pass, not gates. The findings were folded before this update.
Top 1 follow-up
- [Test coverage expert] Add a full marketplace-to-package-registry install and lock fixture -- this would defend the complete cross-layer identity flow beyond the current registry
DependencyReferenceintegration guard.
Recommendation
Ship the current commit. Track the marketplace-to-package-registry end-to-end fixture as non-gating defense-in-depth coverage.
Full per-persona findings from the initial pass
Python architect
- [blocking] OpenAPM v0.1 rejected its documented default registry selector. Folded with v0.1
registries.defaultnegotiation and integration coverage. - [recommended] Machine-output authority missed documented JSON and SARIF aliases. Folded with command-aware aliases and tests.
- [recommended] Frozen hook IR retained mutable dictionaries. Folded with recursive immutable snapshots and edge-only rendering.
CLI logging expert
- [blocking] Exception tracebacks bypassed handler redaction. Folded by redacting formatted exception text.
- [recommended] Option-based machine formats could receive startup notices on stdout. Folded in root output-mode rules.
- [recommended] Handled install failures ended as interruptions. Folded with disposition-aware failure completion.
DevX UX expert
- [blocking] Legacy null lockfile mappings failed strict validation. Folded with null normalization.
- [blocking] Registry-routed marketplace plugins used display names as package identity. Folded with declared owner/repo identity.
- [blocking] Cancelled installs continued into MCP/LSP work. Folded with terminal-disposition return and CLI coverage.
- [recommended] Update-notification spacing could contaminate machine stdout. Folded with stderr-aware spacing.
- [recommended] Release notes lacked user recovery outcomes. Folded into
CHANGELOG.mdand docs.
Supply-chain security expert
- [blocking] Marketplace identity could diverge from declared source. Folded with validated owner/repo coordinates.
- [blocking]
GIT_CONFIG_PARAMETERSsurvived unauthenticated retry cleanup. Folded and tested. - [blocking] Lockfile deployment rows were not structurally validated. Folded while preserving legacy hashless rows.
- [blocking] Hook event payload values could bypass validate-before-mutate. Folded with event/entry validation.
OSS growth hacker
- [recommended] Producer compile guidance contradicted explicit compilation. Corrected.
- [recommended] Changelog prose led with internals instead of user trust outcomes. Corrected.
Auth expert
- [blocking]
type: gitlabcould override recognized GitHub/GHE/ADO hosts. Folded with conflict rejection tests. - [blocking]
GIT_CONFIG_PARAMETERSpreserved an authorization channel. Folded. - [recommended] Scrubbing removed unrelated indexed Git config. Folded by compacting and retaining non-credential settings.
Doc writer
- [recommended] Producer compile behavior drifted. Corrected.
- [recommended] Policy docs described partial-chain enforcement. Corrected to fail closed.
- [recommended] Manifest docs omitted marketplace registry routing. Corrected.
- [recommended] Marketplace docs omitted the registries experimental prerequisite. Corrected.
Test coverage expert
- [blocking] Parent/anchor lockfile fields lacked roundtrip coverage. Added.
- [blocking] Diagnostic disposition lacked a real CLI exit assertion. Added.
- [blocking] Failed install post-hook suppression lacked integration coverage. Added.
- [recommended] Marketplace registry routing lacks a full install-to-lock fixture. Deferred as the one follow-up above.
- [recommended] PR body lacked scenario evidence. Added in the architectural hardening section.
Performance expert
- [blocking] Declaring-parent identity amplified shared local DAGs. Folded by deduplicating on anchored physical path while retaining parent provenance.
- [recommended] Runtime output buffering was unbounded. Folded with a bounded cancellation-aware queue and reader join.
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
Mergeability summary (honest proof ledger)This PR is the consolidated outcome of a three-round reliability campaign (stress-test -> confirm -> fix) plus a follow-on architectural hardening pass and an adjacent-bug root-fix sweep on the same foundation. It closes 24 issues and locks each fix behind a dual guardrail (regression test + static CI guard) so a fix in one place can no longer silently break another. Everything below is independently verified on the merged HEAD; caveats are called out explicitly. 1. Issues this PR fixes (auto-close on merge)All 24 are registered as GitHub Reliability bugs (13) - found and confirmed by the campaign:
Architectural follow-ups folded in (6) - filed during the campaign, root-fixed here:
Adjacent community These were open community-reported bugs that turned out to be the SAME split-authority root shape as the campaign findings. Rather than patch them in isolation, each is fixed by extending the relevant canonical owner (AC1/AC3/AC6) and is regression-locked by a new guard test. Where a narrower community PR already existed, the centralized fix supersedes it.
2. Root-cause hardening (why one fix can no longer break another)The reliability bugs shared one root shape: an authority (target vocabulary, install outcome, policy chain, file write, hook shape, I/O, concurrency) was split or incompletely applied, so a fix on one path missed a sibling path. The hardening centralizes each into a single canonical owner, protected by a regression test + a static guard in
Architecture map (BEFORE -> AFTER per domain, with assessments): see the architecture diagram comment and the "Architecture analysis (onboarding guide)" section in the PR body. 3. Proof of mergeability
4. Honesty and caveats (nothing hidden)
Recommendation: ship. The reliability findings and 5 adjacent community bugs are fixed at root on one canonical-owner foundation, every fix is regression-locked by a test plus a static CI guard, the vendor-neutral contract is preserved (neutral hook IR, no |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The cure's dependency resolver anchored every transitive local package by its absolute, resolved on-disk path and stored that string as the package identity. That identity feeds three serialized lockfile fields -- dependencies[].anchored_local_path, the local: cycle/owner identity used by declaring_parent, and the deployment-ledger owner rows -- so a regenerated apm.lock.yaml embedded 105 absolute developer-home paths, making the committed artifact non-portable and non-deterministic across machines and CI. Fix the single compute site: introduce one canonical owner, APMDependencyResolver._portable_anchor_identity, that records an in-project package relative to the project root in forward-slash POSIX form (matching how directly-declared local owners already serialize) and falls back to a stable absolute POSIX identity only for out-of-project local deps. The value is identity-only and never re-opened as a filesystem path, so relativising it is behaviour-preserving. Guardrails: - Unit tests exercise the canonical helper directly (in-project, nested, out-of-project, unknown-base). - A committed-artifact guard scans the real apm.lock.yaml and fails if any anchored_local_path, local: owner identity, or home-directory prefix ever regenerates as an absolute path. - Lockfile regenerated with the fixed resolver: 0 absolute paths, audit --ci 9/9 no drift, deterministic steady state. Also folds the primitive-encoding of the single-canonical-owner discipline into the python-architect / apm-primitives-architect agents, the python and integrators instructions, the python-architecture skill, and a new architecture.instructions primitive (with deployed copies), so the same discipline that motivated this fix is captured for future contributors. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8e13654a-d2ea-4310-9261-3a38e47db5f0
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 0 | 1 | 0 | Canonical owners are coherent; normalize root-prefixed output flags. |
| CLI Logging Expert | 1 | 0 | 0 | Attached/root-prefixed output flags can corrupt JSON stdout. |
| DevX UX Expert | 1 | 1 | 0 | Ownership handoff can delete the winning deployment. |
| Supply Chain Security Expert | 2 | 0 | 0 | Two paths can reintroduce or mis-scope Git credentials. |
| OSS Growth Hacker | 0 | 1 | 1 | Ship after focused repairs; refresh stale metrics later. |
| Auth Expert | 1 | 0 | 0 | ADO bearer retry bypasses the scrubbed auth environment. |
| Doc Writer | 0 | 0 | 1 | Docs are truthful; one duplicate row is skippable. |
| Test Coverage Expert | 0 | 2 | 0 | Two critical promises lack integration-floor regression traps. |
| Performance Expert | 1 | 1 | 0 | Package-only download dedup can materialize the wrong ref. |
B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.
Top 5 follow-ups
- [Supply Chain Security Expert] (blocking-severity) Keep AuthResolver's sanitized environment authoritative and restrict GitLab credentials to trusted host classification -- raw environment merging and manifest-controlled host typing can leak credentials.
- [Auth Expert] (blocking-severity) Carry the scrubbed authentication context into the ADO PAT-to-bearer retry -- rebuilding from
os.environretains inherited authorization headers. - [DevX UX Expert] (blocking-severity) Make collision ownership handoff non-destructive -- loser cleanup can delete a path after ownership transfers to the winner.
- [Performance Expert] (blocking-severity) Deduplicate downloads by resolved ref/content identity rather than package name -- parallel conflicting refs can leave metadata and disk content inconsistent.
- [CLI Logging Expert] (blocking-severity) Normalize root-prefixed and attached output flags before routing update notices -- supported Click forms contaminate JSON stdout.
Recommendation
Apply only the focused fixes for credential scoping, ownership cleanup, ref-aware deduplication, and JSON output routing, with regression tests for each reproduction. After that targeted pass clears the already-green matrix, ship without taking on lower-priority polish or broader redesign.
Full per-persona findings
Python Architect
- [recommended] Recognize
policy statusafter root flags before reserving JSON stdout atsrc/apm_cli/core/output_mode.py:30.
Exact-headapm --verbose policy status --output jsonwrites an update notice before the JSON document.
CLI Logging Expert
- [blocking] Recognize attached and globally-prefixed machine-output options at
src/apm_cli/core/output_mode.py:21.
--output=json,-ojson,--format=json,-fjson, and root prefixes evade detection and corrupt machine-readable stdout.
DevX UX Expert
- [blocking] Cross-package ownership handoff can delete the winning package's deployed file at
src/apm_cli/install/phases/lockfile.py:256.
Exact-head reproduction ended withfile_exists=Falsewhile the ledger assigned the path to the winner. - [recommended] Unknown-target recovery lists only
allfor several commands.
Supply Chain Security Expert
- [blocking] Package-controlled
host_type: gitlabcan send the global GitLab PAT to an arbitrary host atsrc/apm_cli/core/host_providers.py:165. - [blocking] Preflight environment rebuilding restores inherited Git authorization channels at
src/apm_cli/install/pipeline.py:179.
OSS Growth Hacker
- [recommended] Refresh stale exact-head metrics in the PR body.
- [nit] Collapse the duplicate
apm compilereference row.
Auth Expert
- [blocking] ADO bearer retries retain inherited Git Authorization headers at
src/apm_cli/marketplace/ref_resolver.py:318.
Doc Writer
- [nit] Remove the duplicate
apm compilecommand row.
Test Coverage Expert
- [recommended] Portable transitive lock identities lack an install-to-lockfile assertion in
tests/integration/test_transitive_chain_e2e.py. - [recommended] Marketplace registry routing lacks a full install and lockfile fixture in
tests/integration/test_marketplace_e2e.py.
Performance Expert
- [blocking] Parallel conflicting refs can select one ref while materializing another at
src/apm_cli/deps/apm_resolver.py:1155. - [recommended] Per-owner ledger replacement makes lockfile assembly quadratic.
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f6918e42-c142-41d3-9511-7647bdb80195
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 2 | 0 | 0 | Behavior is fixed; two decision algorithms still have duplicate owners. |
| CLI Logging Expert | 0 | 0 | 0 | All attached/root-prefixed JSON forms now preserve stdout. |
| DevX UX Expert | 0 | 0 | 0 | Ownership handoff preserves the winner file. |
| Supply Chain Security Expert | 0 | 1 | 0 | Credential blockers are closed; align GitLab docs. |
| OSS Growth Hacker | 0 | 0 | 0 | No adoption-facing shipping issue. |
| Auth Expert | 0 | 1 | 0 | Auth behavior is secured; align GitLab docs. |
| Doc Writer | 0 | 0 | 0 | No material code/docs inconsistency beyond the scoped auth clarification. |
| Test Coverage Expert | 0 | 0 | 0 | All six repairs meet their tier floors. |
| Performance Expert | 0 | 0 | 0 | Ref selection/materialization is deterministic and mutation-tested. |
Counts are signal strength, not gates. The maintainer ships.
Top 3 follow-ups
- [Python Architect] (blocking-severity) Make
DeploymentReconcilerthe sole owner of prior-claim eligibility and ownership transfer;lockfile.pyshould supply facts, not recompute policy. - [Python Architect] (blocking-severity) Extract one private deterministic winner selector used by both download dispatch and flattening while retaining loser conflict reporting.
- [Auth/Supply Chain] State that
type: gitlabcontrols backend routing only; global GitLab tokens requiregitlab.com,GITLAB_HOST, orAPM_GITLAB_HOSTS.
Recommendation
Fold only the two behavior-preserving private extractions plus the GitLab documentation correction, add narrow architecture guards, rerun the mapped focused/mutation gates and the full matrix, then request one final panel pass.
Full per-persona findings
Python Architect
- [blocking]
LockfileBuilderindependently computes prior-claim eligibility before canonicalDeploymentReconcilerownership transfer atsrc/apm_cli/install/phases/lockfile.py:251. - [blocking] Download dispatch and
flatten_dependenciesindependently derive the same first-wins dependency selection atsrc/apm_cli/deps/apm_resolver.py:683.
Supply Chain Security Expert / Auth Expert
- [recommended] Align
docs/src/content/docs/getting-started/authentication.mdandpackages/apm-guide/.apm/skills/apm-usage/authentication.mdwith the new GitLab host trust boundary.
CLI Logging Expert
No findings.
DevX UX Expert
No findings.
OSS Growth Hacker
No findings.
Doc Writer
No findings.
Test Coverage Expert
No findings.
Performance Expert
No findings.
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f6918e42-c142-41d3-9511-7647bdb80195
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 0 | 0 | 0 | Both canonical-owner findings are closed; ship. |
| CLI Logging Expert | 0 | 0 | 0 | No output regression. |
| DevX UX Expert | 0 | 0 | 0 | Winner-file survival remains intact. |
| Supply Chain Security Expert | 1 | 0 | 0 | One stale test still demands forbidden PAT forwarding. |
| OSS Growth Hacker | 0 | 0 | 0 | No adoption blocker. |
| Auth Expert | 0 | 0 | 0 | Auth blockers and docs are aligned. |
| Doc Writer | 0 | 0 | 0 | Both auth docs are concise and correct. |
| Test Coverage Expert | 0 | 0 | 0 | Discovered mapped suites are green. |
| Performance Expert | 0 | 0 | 0 | Shared winner selection remains deterministic and cheap. |
Recommendation
Update the stale untrusted-host assertion, add the explicit trusted-host counterpart, and place both under CI discovery. No runtime or architectural change is requested.
Full per-persona findings
Supply Chain Security Expert
- [blocking]
tests/test_github_downloader.py:2515requires forwarding a global GitLab PAT to a type-only untrusted host.
Exact-head targeted run: 1 failed, 3 passed. The runtime and docs correctly requiregitlab.com,GITLAB_HOST, orAPM_GITLAB_HOSTSfor global token trust.
All other panelists returned no findings.
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cd93cabb-ca6e-4677-94cc-6a50a68273e5
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f6918e42-c142-41d3-9511-7647bdb80195
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 0 | 1 | 0 | Architecture is ready; tests could force fallback more directly. |
| CLI Logging Expert | 0 | 0 | 0 | No CLI output findings. |
| DevX UX Expert | 0 | 0 | 0 | No DevX regression. |
| Supply Chain Security Expert | 0 | 0 | 0 | Trusted/untrusted GitLab token contracts are correct. |
| OSS Growth Hacker | 0 | 0 | 0 | No adoption issue. |
| Auth Expert | 0 | 1 | 0 | Runtime auth is correct; tests could avoid real fetch attempts. |
| Doc Writer | 0 | 0 | 0 | Documentation remains aligned. |
| Test Coverage Expert | 0 | 0 | 0 | Focused, unit, integration, CI, and audit evidence are green. |
| Performance Expert | 0 | 0 | 0 | No production performance change. |
Counts are signal strength, not gates. The maintainer ships.
Top follow-up
- [Python Architect + Auth Expert] Patch
GitSparseFileTransport.fetch_fileto raise a deterministic transport error in the new routing tests, preventing real fetch attempts againstcode.acme.com. This is test-only and non-blocking.
Recommendation
Ship exact head 3e7a4158. Track only the small test transport mock as a bounded follow-up; no runtime changes or broader refactoring are justified.
Full per-persona findings
Python Architect
- [recommended] Isolate the GitLab REST contract tests from the primary git transport at
tests/unit/deps/test_github_downloader_gitlab_routing.py:23.
MockGitSparseFileTransport.fetch_fileto fail deterministically so the tests exercise REST routing without external-network dependence.
Auth Expert
- [recommended] Make the GitLab routing tests hermetic at
tests/unit/deps/test_github_downloader_gitlab_routing.py:26.
Prevent real git fetches before the mocked REST fallback.
All other panelists returned no findings.
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 0 | 0 | 1 | Closure verified; dependency injection is correctly used. |
| CLI Logging Expert | 0 | 0 | 0 | No findings. |
| DevX UX Expert | 0 | 0 | 0 | No findings. |
| Supply Chain Security Expert | 0 | 0 | 0 | Credential-routing tests are hermetic. |
| OSS Growth Hacker | 0 | 0 | 0 | No adoption impact. |
| Auth Expert | 0 | 0 | 0 | Trusted/untrusted token contracts are deterministic. |
| Doc Writer | 0 | 0 | 0 | Documentation remains aligned. |
| Test Coverage Expert | 0 | 0 | 0 | Focused and full evidence is green. |
| Performance Expert | 0 | 0 | 0 | No production performance change. |
Counts are signal strength, not gates. The maintainer ships.
Recommendation
Merge this exact head as-is; no follow-up work is warranted.
Full per-persona findings
Python Architect
- [nit] Design pattern record only; no action required. Tests inject
AuthResolverwith external fallback disabled and replace both transport boundaries for deterministic REST-path coverage.
All other panelists returned no findings.
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
Define the evidence-backed grouping and validation contract for restoring every issue closed by PR #2155 to the v0.25.0 changelog. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239
Plan the issue-set validation, grouped changelog rewrite, PR body synchronization, and release-gate checks for #2155. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239
Expand PR #2155 into grouped user outcomes and link every issue it closed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239
* chore: release v0.25.0 Bump apm-cli and the lockfile to 0.25.0, move sanitized user-facing changes into the dated changelog section, and confirm the CI lint mirror passes. Post-merge: tag v0.25.0 to trigger the release workflow. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239 * docs: design community-fix release notes Define the evidence-backed grouping and validation contract for restoring every issue closed by PR #2155 to the v0.25.0 changelog. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239 * docs: plan community-fix release notes Plan the issue-set validation, grouped changelog rewrite, PR body synchronization, and release-gate checks for #2155. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239 * docs: restore v0.25.0 community fixes Expand PR #2155 into grouped user outcomes and link every issue it closed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239 * chore: remove superpowers planning artifacts Remove the repository-local superpowers planning tree and ignore future local planning artifacts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239 --------- Co-authored-by: danielmeppiel <danielmeppiel@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
TL;DR
A 3-round internal reliability red-team surfaced 13 defects across MCP config, deployment tracking, install completion, and target capability. Each was fixable in isolation, but the cluster shape pointed at a deeper cause: the same lifecycle invariant was enforced in many places, so a fix in one call site silently drifted from the others. This PR lands all 13 fixes and re-homes them behind four canonical owners so the invariant lives in exactly one place per domain. Owner-invariant tests make the routing structural, not cosmetic.
Single PR by design: it supersedes and closes the 13 point PRs (#2131, #2132, #2133, #2134, #2135, #2141, #2142, #2143, #2144, #2145, #2151, #2152, #2153).
+6038 / -1878across 139 filesProblem (WHY)
The red-team fixed bugs round over round, but the recurrence pattern was the tell: deployment-file ownership, MCP source-of-truth, install exit meaning, and target capability were each computed in several modules. When one call site was patched, the others kept the old behavior — the classic symptom of diffuse ownership in a modular codebase.
This also has to respect APM's boundary discipline. Per
PRINCIPLES.mdP1:So consolidation must not introduce a harness translation layer. Owners emit each target's native schema directly; they centralize ownership, not abstraction.
Approach (WHAT)
Four canonical owners, one per recurring-bug domain, each guarded by an invariant test that fails if a foreign module reclaims the responsibility:
graph TD subgraph Owners["Canonical lifecycle owners"] C1["C1 mcp_config_view.py<br/>MCP source-of-truth"] C2["C2 deployment_state.py + deployment_ledger.py<br/>deployed-file ownership"] C3["C3 target_catalog.py<br/>target capability"] C4["C4 install/transaction.py<br/>install completion + exit meaning"] end audit["audit / install / uninstall"] --> C1 deploy["install / uninstall / update / compile"] --> C2 detect["target detection / validation / help"] --> C3 pipeline["install pipeline / commands.install"] --> C4 C1 -. owner-invariant .-> INV["structural tests<br/>(regex + AST)"] C2 -. owner-invariant .-> INV C4 -. owner-invariant .-> INVImplementation (HOW)
integration/mcp_config_view.py(327)core/deployment_state.py(306) +core/deployment_ledger.py(352)deployed_files/hashes/local mirrors, additive dual-written ledgercore/target_catalog.py(272)target_detectionconstants become derived projections;KNOWN_TARGETSstays owner of native roots (no translation layer)install/transaction.py(162)InstallDisposition+ transactional resolution;commands/install.pyis the sole placeInstallResult.exit_codemaps to process exitAdditional folded fixes that did not need a new owner: hooks top-level
version(#2128), compile orphan cleanup on--clean(#2130), parser schema-boundary rejection (#2137), ADO bearer auth preservation in the semver resolver (#2150).Supporting refactor: extracted the target-specific hook-entry converters into
integration/hook_native_formats.py(single owner of native Gemini/Antigravity hook-entry rewriting) — keepshook_integrator.pyunder the file-length guardrail and matches the P1 "emit native schema directly" rule.Owner-invariant tests (the crux)
These prove routing is real, not decorative:
tests/unit/core/test_deployment_owner_invariant.py— only the C2 owners +deps/lockfile.pymay assign the deployed-file fields.tests/unit/core/test_target_catalog_owner_invariant.py— capability metadata has one source.tests/unit/install/test_install_exit_owner_invariant.py(AST) — onlycommands/install.pymapsInstallResultto a process exit code; noinstall/module callssys.exit.Trade-offs
Validation evidence
How to test
Architecture analysis (onboarding guide)
Written as an onboarding guide for an engineer new to the codebase, reflecting the cured architecture at snapshot
cb0964e7a. Produced by a lead architect plus a 10-analyst domain sweep. All 21 architecture and execution-flow diagrams live in a single companion comment: architecture diagram map.System Overview
APM is a vendor-neutral Python CLI and package manager for AI-agent primitives. Authors declare instructions, skills, prompts, agents, hooks, MCP servers, LSP servers, scripts, dependencies, and target preferences in
apm.yml. APM resolves the dependency closure, pins it inapm.lock.yaml, deploys content into native agent-harness layouts, compiles aggregate context files, runs declared workflows, and audits policy or filesystem drift.The codebase is organized as a layered pipeline:
apm.ymlintoAPMPackage, dependency references, and primitive models.AGENTS.md,CLAUDE.md, orGEMINI.md.The architecture favors canonical owners:
core/target_catalog.pyowns target capabilities.core/auth.pyowns host classification and credential resolution.deps/apm_resolver.pyowns graph resolution.deps/lockfile.pyandcore/deployment_ledger.pyown reproducibility and deployment provenance.install/pipeline.pyowns install phase ordering.integration/base_integrator.pyandintegration/dispatch.pyown materialization behavior.core/command_logger.pyowns semantic CLI output.policy/owns governance semantics.cache/owns persistent Git and HTTP reuse.The intended lifecycle is:
author -> resolve -> lockfile pins -> install -> compile -> integrate -> run -> drift and policy auditIn the implementation, the updated lockfile is persisted after integration so it can record actual paths, hashes, owners, MCP state, and materialization outcomes.
Diagram reference: System context in the PR architecture comment.
Per-domain deep dives + cross-cutting architecture (click to expand)
CLI surface, command dispatch, and logging UX
The executable is registered as
apm_cli.cli:maininpyproject.toml.src/apm_cli/cli.pyconfigures encoding and standard-library logging, defines global options, registers top-level commands, performs update checks, and converts uncaught failures into process exit behavior.Command modules under
src/apm_cli/commands/are adapters. They parse Click values, discover the project manifest, construct service requests, invoke domain services, and select human or machine output. Command families cover dependency management, compilation, package production, execution, policy, marketplaces, runtime management, caching, and diagnostics.Important components:
src/apm_cli/cli.py: process entry, root Click group, global options, registration, and top-level error handling.src/apm_cli/commands/_helpers.py: manifest discovery, version display, update notification, and shared command helpers.src/apm_cli/core/command_logger.py: semantic output API for progress, lifecycle, auth, policy, install, and cleanup events.src/apm_cli/utils/console.py: Rich, Colorama, and plain-output routing plus ASCIISTATUS_SYMBOLS.src/apm_cli/utils/diagnostics.py: thread-safe diagnostic collection and stable category-oriented rendering.src/apm_cli/output/: typed compilation and script-execution presentation models.src/apm_cli/factory.py: registry-backed construction of MCP client and package-manager adapters.CommandLoggerand Python logging are distinct. The former is user-facing and writes through console helpers; the latter is an operational/debug channel.DiagnosticCollectorsupports collect-then-render behavior so parallel phases can report consistently without printing directly.Inputs include CLI options, environment variables, the current directory, manifests, lockfiles, and configuration. Outputs include Rich or plain text, JSON or SBOM data, filesystem changes, subprocess execution, and exit status.
Diagram reference: 1. CLI surface, dispatch, and logging UX.
Dependency resolution and lockfile
The dependency domain converts manifest references into pinned packages and a reproducible graph. It supports shorthand Git references, explicit hosts, local paths, monorepo subpaths, registries, marketplaces, VCS proxies, refs, and semver constraints.
Important components:
src/apm_cli/models/dependency/reference.py:DependencyReferenceparsing, canonical identity, transport metadata, refs, virtual paths, and install locations.src/apm_cli/deps/apm_resolver.py: deterministic, level-batched breadth-first dependency resolution.src/apm_cli/deps/dependency_graph.py: tree, flattened map, conflict, and cycle structures.src/apm_cli/deps/github_downloader.py: legacy-named facade over vendor-neutral acquisition strategies.src/apm_cli/deps/host_backends.py: host-specific URL and API behavior.src/apm_cli/deps/transport_selection.py: pure clone-transport planning.src/apm_cli/deps/clone_engine.py: authenticated clone execution and controlled fallback.src/apm_cli/deps/tiered_ref_resolver.py: per-run cache, API, bare-cache, and clone-based ref resolution.src/apm_cli/deps/registry/: package-registry version selection, download, extraction, and integrity verification.src/apm_cli/deps/path_anchoring.py: parent-relative transitive local dependency resolution.src/apm_cli/deps/lockfile.py: lockfile models, migration views, semantic comparison, and atomic persistence.src/apm_cli/deps/installed_package.py: typed handoff from installation to lockfile assembly.Resolution separates package identity from selected ref. Host-qualified identity is used for dependency deduplication, while deployment paths retain compatibility with the existing
apm_moduleslayout. The resolver loads one breadth-first level in parallel but performs graph mutation in deterministic submission order.The lockfile records exact commits or versions, source metadata, content hashes, dependency depth, parentage, deployed files, per-file hashes, MCP/LSP state, target ownership, and deployment-ledger records. It is both the reproducibility contract and the provenance input to cleanup, audit, bundle, and SBOM export.
The domain consumes
AuthResolver, cache services, marketplace or registry resolution, and policy results. It returns a graph and installed-package records to the install pipeline.Diagram reference: 2. Dependency resolution and lockfile.
Install and transaction lifecycle
src/apm_cli/install/is the application engine behindapm install. It turns manifest and CLI intent into resolved packages, target materializations, configuration updates, cleanup actions, and lockfile state.Important components:
src/apm_cli/install/request.py: immutableInstallRequest.src/apm_cli/install/service.py: application service and lifecycle-hook boundary.src/apm_cli/install/context.py: mutable phase context carrying graph, targets, diagnostics, policy, provenance, and counters.src/apm_cli/install/pipeline.py: canonical phase ordering and commit/rollback wrapper.src/apm_cli/install/phases/resolve.py: manifest, lockfile, resolver, cache, and intended-dependency setup.src/apm_cli/install/phases/policy_gate.py: resolved dependency and MCP policy enforcement.src/apm_cli/install/phases/targets.py: explicit, manifest, configured, detected, and fallback target selection.src/apm_cli/install/phases/download.py: parallel pre-download.src/apm_cli/install/sources.py: local, cached, and downloaded source strategies.src/apm_cli/install/template.py: shared scan and integration template method.src/apm_cli/install/phases/integrate.py: source dispatch and result aggregation.src/apm_cli/install/phases/cleanup.py: manifest-driven orphan and stale-output removal.src/apm_cli/install/phases/lockfile.py: lockfile and deployment-ledger assembly.src/apm_cli/install/mcp/andinstall/lsp/: post-package configuration reconciliation.src/apm_cli/install/transaction.py: manifest snapshot andapm_modulespath journal.src/apm_cli/install/summary.py: completion classification and disposition-aware reporting.The design combines an application service, a phase pipeline, source strategies, a template method, and declarative reconciliation. Reads can come from a source root while writes are directed to the deployment root, supporting drift replay and other staged operations.
The major flow is resolve -> plan -> policy -> targets -> download -> scan/integrate -> cleanup -> lockfile -> local content -> audit/finalize. MCP and LSP reconciliation are sibling configuration flows connected by command orchestration.
InstallContextis deliberately broad because it is the shared phase data bus. This makes sequencing explicit, but it also means success classification and mutation ownership must remain centralized to prevent phases and callers from interpreting the same diagnostics differently.Diagram reference: 3. Install and transaction lifecycle.
Compilation pipeline
Compilation converts portable instruction primitives into aggregate files consumed by target harnesses. It reads local
.apm/content and already-installed dependencies; it does not resolve or download packages.Important components:
src/apm_cli/commands/compile/cli.py: command validation, target selection, compiler configuration, reporting, and ownership reconciliation.src/apm_cli/core/target_catalog.py: target capabilities and compile-family metadata.src/apm_cli/core/target_detection.py: aliases, detection, target field parsing, and family projection.src/apm_cli/compilation/agents_compiler.py: primitive discovery and output-family dispatch.src/apm_cli/compilation/distributed_compiler.py: directory analysis, placement planning, rendering, and orphan detection.src/apm_cli/compilation/context_optimizer.py:applyToscoring and inherited-context minimization.src/apm_cli/compilation/link_resolver.py: context and package-asset link translation.src/apm_cli/compilation/claude_formatter.py: CLAUDE.md translation.src/apm_cli/compilation/gemini_formatter.py: GEMINI.md import output.src/apm_cli/compilation/managed_section.py: preservation of non-APM content around managed sections.src/apm_cli/compilation/output_writer.py: build-ID stabilization and atomic persistence.src/apm_cli/compilation/constitution.pyandinjector.py: optional constitution discovery and injection.The target precedence is CLI, manifest, filesystem detection, then fallback. Targets project into compiler families such as
agents,claude,gemini, orvscode. Portable primitives remain independent of these families; the family formatter is the translation boundary.Distributed compilation analyzes project directories, places instructions according to applicability, suppresses redundant shells, resolves links, injects optional constitution content, stabilizes build IDs, writes managed files, and identifies safe orphan cleanup candidates.
Compilation and integration are related but different. Compilation emits aggregate root or distributed context. Integration materializes individual primitive files and native configuration. Installation currently stages compile-family content and may instruct the user to run explicit compilation rather than universally invoking the compile command.
Diagram reference: 4. Compilation pipeline.
Integration and file materialization
Integration is the filesystem and native-configuration boundary. It receives resolved target profiles and portable primitives, selects the appropriate integrator, renders native formats, handles adoption or collision, and returns provenance-rich materialization results.
Important components:
src/apm_cli/integration/targets.py:TargetProfile,PrimitiveMapping, paths, formats, scopes, capabilities, and detection.src/apm_cli/integration/base_integrator.py: common collision, ownership, path validation, link resolution, synchronization, and result behavior.src/apm_cli/integration/dispatch.py: shared primitive-to-integrator registry.src/apm_cli/integration/coverage.py: profile and dispatch completeness checks.src/apm_cli/integration/*_integrator.py: specialized instruction, skill, prompt, agent, command, canvas, hook, MCP, and LSP materializers.src/apm_cli/integration/hook_integrator.py: hook parsing, event mapping, script rewriting, merging, and provenance.src/apm_cli/integration/hook_native_formats.py: native hook-schema conversion.src/apm_cli/integration/cleanup.py: hash-aware stale and orphan cleanup.src/apm_cli/integration/_shared.py: shared MCP/LSP dependency and lockfile lookup.src/apm_cli/integration/skill_transformer.py: target-specific skill metadata transformation.The central patterns are data-driven routing and a base-class template method. Target profiles declare capabilities, dispatch selects specialized behavior, and
BaseIntegratorowns common safety and provenance rules.IntegrationResultand materialization records carry counts, locators, paths, content hashes, owners, validation status, and adoption state. Install writes these into lockfile and ledger views. Cleanup and uninstall consume the same ownership information and preserve files whose current hash indicates user modification.Native target translation belongs here. Portable package fields should not encode one harness's schema, event names, locators, or configuration keys.
Diagram reference: 5. Integration and file materialization.
Authentication and credential resolution
Remote authentication is centralized in
src/apm_cli/core/auth.py, whilesrc/apm_cli/security/primarily owns content scanning, executable approval, audit formats, and external scanner ingestion.Authentication components:
HostInfo: immutable host kind, API base, port, and public-repository capability.AuthContext: resolved token source, scheme, host information, and Git environment.AuthResolver: process-scoped, thread-safe classification, credential resolution, fallback, diagnostics, and caching.src/apm_cli/core/token_manager.py: environment, supported CLI, and Git credential-helper acquisition.src/apm_cli/deps/host_backends.py: host-specific clone and API URL strategies.src/apm_cli/deps/git_auth_env.py: non-interactive Git environment construction.Credential precedence is host-specific. GitHub-family hosts use organization-specific or global environment variables, supported CLI credentials, and credential helpers. ADO supports PAT followed by Azure CLI bearer fallback. GitLab supports environment credentials and credential helpers. Generic hosts use credential helpers.
The resolver accepts a
DependencyReferenceand returns anAuthContextconsumed by validation, downloads, clone operations, raw-file access, marketplaces, and ref resolution. Repository path and port are retained for credential-helper disambiguation.Security components include:
SecurityGateandContentScannerfor hidden-character scanning.This separation is conceptually sound: credential resolution, content trust, and executable approval are distinct responsibilities, even though they meet in the install pipeline.
Diagram reference: 6. Authentication and credential resolution.
MCP trust, registry, and marketplace
The marketplace domain provides curated plugin discovery. A registered catalog resolves
plugin@marketplaceinto a normal dependency reference plus provenance. The MCP registry domain provides MCP server search and metadata. Installation remains responsible for trust, policy, target configuration, and lockfile adoption.Important marketplace components:
src/apm_cli/marketplace/models.py: immutable source, plugin, and manifest models.src/apm_cli/marketplace/registry.py: persisted marketplace registrations.src/apm_cli/marketplace/client.py: local, hosted, GitHub-family, GitLab, ADO, and generic Git fetching and caching.src/apm_cli/marketplace/resolver.py: marketplace reference parsing and dependency handoff.src/apm_cli/marketplace/builder.py: authoring and marketplace artifact generation.src/apm_cli/marketplace/output_profiles.py: target artifact capabilities.src/apm_cli/marketplace/output_mappers.py: explicit native marketplace translation.src/apm_cli/marketplace/audit.py: marketplace pinning and bypass analysis.src/apm_cli/marketplace/version_resolver.py: tag and version selection.Important registry components:
src/apm_cli/registry/client.py: bounded, cached MCP Registry v0.1 client.src/apm_cli/registry/integration.py: compatibility translation to package-shaped records.src/apm_cli/registry/operations.py: existence checks and runtime/environment collection.src/apm_cli/install/mcp/integration.py: current-state merge, transitive trust, policy, target writes, stale removal, and lockfile updates.Direct MCP declarations are trusted as explicit user intent. Self-declared transitive MCP servers require root re-declaration or an explicit trust option. The current desired set is rebuilt from the root manifest and lockfile-bounded package manifests rather than accepting lockfile-only entries as authority.
Marketplace provenance records the discovery source, plugin, source URL, digest, ref, and concrete dependency. MCP lockfile state records target ownership, resolved configuration, and package provenance.
Harness-specific marketplace artifacts and MCP configuration belong in output mappers and client adapters, not in portable manifest semantics.
Diagram reference: 7. MCP trust, registry, and marketplace.
Primitives, core domain, and packaging
The core model converts author-facing YAML and files into validated in-memory contracts shared by resolution, installation, compilation, integration, and packaging.
Important components:
src/apm_cli/models/apm_package.py:APMPackage, manifest loading, dependencies, registries, scripts, targets, includes, and executable approvals.src/apm_cli/core/apm_yml.py: canonicaltargetandtargetsparsing.src/apm_cli/models/dependency/: APM, MCP, LSP, remote, and resolved dependency models.src/apm_cli/models/validation.py: package classification andValidationResult.src/apm_cli/models/format_detection.py: independent format evidence and normalization planning.src/apm_cli/primitives/models.py: instructions, skills, prompts, agents, context, collections, and conflicts.src/apm_cli/primitives/parser.py: frontmatter-to-model conversion.src/apm_cli/primitives/discovery.py: local and dependency discovery with deterministic precedence.src/apm_cli/core/build_orchestrator.py: bundle and marketplace producer selection.src/apm_cli/core/plugin_manifest.py: native plugin manifest translation.src/apm_cli/bundle/packer.py: lockfile-attested APM bundle construction.src/apm_cli/bundle/plugin_exporter.py: native plugin layout generation.src/apm_cli/bundle/lockfile_enrichment.py: embedded provenance and target filtering.src/apm_cli/bundle/local_bundle.py: archive detection and integrity verification.src/apm_cli/bundle/unpacker.py: safe additive extraction of lockfile-listed files.Dataclasses are the primary contract style. Parsing, format detection, validation, and filesystem materialization are separate stages. Primitive discovery uses local-first precedence, followed by dependency order, while retaining conflict information.
The lockfile is the boundary between install and packaging. Bundles copy only recorded files, verify hashes, enrich embedded provenance, and optionally translate portable primitives into a native plugin layout.
The public v0.1 manifest schema and current v0.3 working-draft implementation are separate contracts. The code currently lacks explicit manifest-version negotiation, making careful schema ownership important.
Diagram reference: 8. Primitives, core domain, and packaging.
Policy, governance, drift, and audit
Policy controls what may be installed. It is not a runtime permission system; execution permissions remain with the consuming harness.
Important components:
src/apm_cli/policy/schema.py: immutable policy dataclasses and tri-state list semantics.src/apm_cli/policy/parser.py: YAML validation and model construction.src/apm_cli/policy/discovery.py: local, URL, repository, cache, pin, and inheritance discovery.src/apm_cli/policy/inheritance.py: root-to-leaf tighten-only merging.src/apm_cli/policy/matcher.py: canonical reference matching and deny-over-allow decisions.src/apm_cli/policy/policy_checks.py: dependency, MCP, registry, target, pinning, and manifest checks.src/apm_cli/policy/ci_checks.py: lockfile, ownership, configuration, and integrity checks.src/apm_cli/policy/install_preflight.py: enforcement for non-pipeline and dry-run paths.src/apm_cli/policy/outcome_routing.py: canonical fetch-outcome handling.src/apm_cli/policy/project_config.py: fetch-failure defaults and policy hash pins.src/apm_cli/drift.py: manifest, lock, source, orphan, stale-file, and MCP drift.src/apm_cli/install/drift.py: cache-only replay into scratch and workspace comparison.src/apm_cli/core/deployment_state.py: deployment ledger records.src/apm_cli/core/deployment_ledger.py: lockfile compatibility projection.src/apm_cli/update_policy.py: separate self-update distribution policy.Policy values distinguish no opinion, explicit empty, and populated constraints. Inheritance generally intersects allowlists, unions restrictions, escalates enforcement, and applies deny-wins behavior.
Install performs resolved dependency checks before deployment and target checks after target selection. Audit performs baseline lockfile and ownership checks, optional policy evaluation, cache-only replay, and comparison against the working tree.
The deployment ledger maps locators to owners, active owner, target, runtime, scope, and hash. It is the canonical provenance model projected into compatibility lockfile fields.
Diagram reference: 9. Policy, governance, drift, and audit.
Runtime execution, adapters, cache, and export
APM separates deployment from execution.
apm runexecutes named scripts fromapm.yml, compiling referenced prompt files before invocation. Runtime adapters provide a second programmatic prompt-execution path.Important components:
src/apm_cli/commands/run.py: Click entry for named scripts and parameters.src/apm_cli/core/script_runner.py: script discovery, prompt compilation, runtime command recognition, and subprocess execution.src/apm_cli/runtime/base.py: runtime adapter interface and streaming helper.src/apm_cli/runtime/factory.py: runtime construction and preference.src/apm_cli/runtime/manager.py: managed runtime installation and removal.src/apm_cli/runtime/utils.py: managed-binary andPATHresolution.src/apm_cli/workflow/parser.py: prompt frontmatter toWorkflowDefinition.src/apm_cli/workflow/discovery.py: workflow discovery.src/apm_cli/workflow/runner.py: adapter-based workflow execution.src/apm_cli/adapters/client/base.py: normalized MCP client contract and native configuration boundary.src/apm_cli/factory.py: client-adapter registration.src/apm_cli/cache/git_cache.py: content-addressed bare repositories and immutable checkouts.src/apm_cli/cache/http_cache.py: TTL, ETag, hash, and LRU HTTP caching.src/apm_cli/cache/integrity.py: cache validation.src/apm_cli/cache/locking.py: per-shard locks and atomic landing.src/apm_cli/export/sbom.py: deterministic CycloneDX and SPDX generation.src/apm_cli/export/purl.py: credential-free package identities.src/apm_cli/bootstrap_mirror.py: enterprise mirror routing.src/apm_cli/config.py: user-private configuration and process caching.Recognized runtime commands are executed with argument arrays and compiled prompt content. Arbitrary authored scripts use the platform shell. Client adapters translate normalized MCP declarations into native JSON or TOML formats.
Git caching is content-addressed by normalized repository and resolved SHA. HTTP caching combines freshness, conditional requests, body hashes, and bounded eviction. SBOM export is intentionally network-free and derives only from lockfile state.
A second workflow execution path exists through
workflow/runner.py, butapm runprimarily usesScriptRunner. This parallel surface contributes to runtime capability drift.Diagram reference: 10. Runtime, adapters, cache, and export.
Cross-cutting architecture
Logging and diagnostics
CommandLoggeris the semantic output owner.DiagnosticCollectorsupports deferred, categorized summaries. Python logging remains a separate debug channel. Commands producing machine-readable output must establish stdout/stderr policy before root-level notifications or progress output.Authentication
AuthResolveris the shared credential authority. It classifies hosts, resolves credentials once, cachesAuthContext, and applies controlled fallback. Downloaders and host backends should consume this contract rather than inspect environment variables independently.Error handling
The code uses both exceptions and accumulated diagnostics. Exceptions express immediate inability to continue; diagnostics support phase aggregation and user summaries. Success classification must occur before lifecycle hooks, commit, and programmatic return. Otherwise the CLI and service callers can disagree about the same operation.
Caching
Git and HTTP caches are optimization layers, not authorities. Cache hits are validated through resolved SHA or body hash. Lockfile pins remain the reproducibility authority. Drift replay intentionally uses cache-only operation to avoid network-dependent audit outcomes.
Provenance and ownership
Materializers return locators, hashes, owners, and validation state. The deployment ledger is the canonical ownership model; lockfile compatibility fields project that state for existing consumers. Cleanup is hash-aware and preserves user-modified content rather than deleting solely by path.
Vendor-neutrality posture
The portable core is based on primitives, dependency references, target capabilities, and normalized MCP/LSP models. Harness-specific paths and schemas appropriately belong in target profiles, integrators, formatters, client adapters, and plugin exporters.
Neutrality weakens where generic install, auth, runtime, or hook layers contain closed vendor lists, native locator rules, or one harness's intermediate representation. New harness support should extend capability or adapter registries rather than add portable manifest fields or branches throughout orchestration code.
Surfaced architectural findings
New findings
deps/apm_resolver.py:608-626,792-827models/dependency/reference.py:301-319;install/phases/resolve.py:859-870deps/lockfile.py:641-647,692-762;docs/.../lockfile-spec.md:308-321install/phases/lockfile.py:172-173,461-465;install/phases/finalize.py:155-161;install/service.py:107-110;install/summary.py:30-49compilation/agents_compiler.py:679-688,964-1000,1418-1433;compilation/output_writer.py:1-18;docs/.../cli/compile.md:57-59CompiledOutputWriter.require_explicit_includesis droppedpolicy/schema.py:99-105;policy/inheritance.py:245-261commands/audit.py:538-554;policy/discovery.py:246-256policy/discovery.py:447-449,501-560commands/mcp.py:18-46;registry/integration.py:11-19RegistryIntegration, and reuse the install registry wiring.marketplace/models.py:305-313,413-455;marketplace/resolver.py:788-820targetsis ignored by APM bundle packingmodels/apm_package.py:476-512;bundle/packer.py:88-155;core/apm_yml.py:41-102integration/hook_integrator.py:1188-1233cli.py:146-152;commands/_helpers.py:464-477; callback-local output routing incommands/pack.py,deps/why.py, andlock.pycli.py:99-106; descendant loggers such ascore/auth.pyandintegration/mcp_integrator.pycore/auth.py:633-637,675-679,997-1028models/dependency/reference.py:919-938;core/auth.py:287-299;deps/host_backends.py:494-522install/deployed_paths.py:21-38;install/manifest_reconcile.py:38-62;install/services.py:284-314integration/hook_native_formats.py:1-65,111-121runtime/factory.py:14-19,91-105;runtime/manager.py:29-50;commands/runtime.py:25-27;core/script_runner.py;workflow/runner.pyruntime/base.py:21-44;runtime/codex_runtime.py:41-76marketplace/registry.py:45-78,104-124docs/public/specs/schemas/manifest-v0.1.schema.json:35-51;models/apm_package.py:101-137docs/.../concepts/lifecycle.md:77-79;install/services.py:898-904;install/phases/finalize.py:146-153compilation/output_writer.py:1-18;agents_compiler.py:1430-1433;user_root_context.py:267-292CompiledOutputWriterand remove duplicate build-ID finalization.Known / in remediation
core/target_catalog.py:127-132,183-200,214-219commands/install.py:1426-1445,1526-1532;install/transaction.py:35-78,136-171apm.ymlis removed only on genuine failure, and logging follows the owning layer.Consolidated issues (auto-close on merge)
This cure folds and re-homes all 13 point fixes under their canonical owners; the superseded point PRs are closed. Merging this PR resolves:
Closes #2126
Closes #2127
Closes #2128
Closes #2129
Closes #2130
Closes #2136
Closes #2137
Closes #2138
Closes #2139
Closes #2140
Closes #2148
Closes #2149
Closes #2150
Closes #2156
Closes #2157
Closes #2158
Closes #2159
Closes #2160
Closes #2161
Architectural hardening (root-cause clusters AC1-AC7)
The 24 follow-up findings shared one root cause: a fact or mutation had more than one authority. This hardening pass completes the canonical-owner pattern and locks each cluster with both behavioral and structural guardrails.
tests/integration/test_architecture_authorities.pyscripts/lint-architecture-boundaries.sh(AC1)CompiledOutputWriter; validate hooks and lockfiles before mutationtests/integration/test_architecture_mutation_guards.pyscripts/lint-architecture-boundaries.sh(AC2)install/outcome.pyowns disposition and exit semantics; policy discovery is chain-aware and incomplete chains fail closedtests/integration/test_architecture_outcome_guards.pyscripts/lint-architecture-boundaries.sh(AC3)tests/integration/test_architecture_intent_guards.pyscripts/lint-architecture-boundaries.sh(AC4)tests/integration/test_architecture_io_guards.pyscripts/lint-architecture-boundaries.sh(AC5)$schemanegotiation, and one install/compile lifecycle contracttests/integration/test_architecture_contract_guards.pyscripts/lint-architecture-boundaries.sh(AC6)tests/integration/test_architecture_concurrency_guards.pyscripts/lint-architecture-boundaries.sh(AC7)The static guard is wired into the
Lintjob in.github/workflows/ci.yml. Legitimate exceptions require an inline# architecture-authority-exempt: <reason>annotation.Scenario Evidence
tests/integration/test_architecture_authorities.pytests/integration/test_architecture_mutation_guards.pytests/integration/test_architecture_outcome_guards.pytests/integration/test_architecture_intent_guards.pytests/integration/test_architecture_io_guards.pytests/integration/test_architecture_contract_guards.pytests/integration/test_architecture_concurrency_guards.pyHardening validation
10187 passed, 255 skipped, 2 xfailed(includes the 5 adjacent-bug regression guards; re-run green on the merged HEAD)18631 passed, 2 skipped, 21 xfailed, 88 subtests passedAdjacent community bugs root-fixed on the same foundation
These open community-reported
[BUG]s shared the same split-authority root as thecampaign findings, so each is fixed by extending the relevant canonical owner
(AC1/AC3/AC6) and locked by a new guard test. Where a narrower community PR already
existed, the centralized fix supersedes it (#2116 -> #2117, #2062 -> #2097, #2071 -> #2095).
apm init --targetwrites atargets:value thatapm installthen rejects #2147 -apm initandapm installnow share one accepted target catalog (AC1)apm install --skill <name>is a silent no-op when the skill is not in the plugin.json skills array #2116 -apm install --skillwith no match fails closed instead of a silent no-op (AC3)Closes #2147
Closes #2103
Closes #2116
Closes #2062
Closes #2071