Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
71f6d56
fix(install): deploy skills through home directory aliases
danielmeppiel Sep 7, 2026
f864bdd
docs(changelog): link home alias fix pull request
danielmeppiel Sep 7, 2026
70e52a0
test(install): exercise alias lifecycle and declared plugin skills
danielmeppiel Sep 7, 2026
22618ce
fix(lifecycle): complete alias-path revision and recovery transitions
danielmeppiel Sep 7, 2026
d126ee2
Merge main for lifecycle validation
danielmeppiel Sep 7, 2026
9eeaf37
test(lifecycle): record compatible readers and project-only command l…
danielmeppiel Sep 7, 2026
060880e
test(lifecycle): cover hidden readers and exact recovery branches
danielmeppiel Sep 7, 2026
1f917a1
test(architecture): guard alias lifecycle authority routing
danielmeppiel Sep 7, 2026
7ae1035
Merge remote-tracking branch 'origin/main' into danielmeppiel-complet…
danielmeppiel Sep 7, 2026
171a3ec
docs(conformance): record frozen manifest pin requirement coverage
danielmeppiel Sep 7, 2026
9c32593
merge: integrate PR 2876 with current main
danielmeppiel Sep 30, 2026
7b32b6b
fix: qualify standalone HOME-alias lifecycle repair
danielmeppiel Sep 30, 2026
71a2e17
merge: compose standalone repair with current main
danielmeppiel Sep 30, 2026
ace6ee3
test: close native proof mutation gaps and preserve launcher identity
danielmeppiel Sep 30, 2026
25299d0
test: strengthen real execution and alias ownership witnesses
danielmeppiel Sep 30, 2026
260d5dc
test: cover marketplace remote owner in mutation matrix
danielmeppiel Sep 30, 2026
ed32e02
fix: fold standalone lifecycle evidence and seed review
danielmeppiel Sep 30, 2026
b6f544d
Merge current main into standalone lifecycle repair
danielmeppiel Sep 30, 2026
541e583
test: tolerate wrapped legacy plugin diagnostics
danielmeppiel Sep 30, 2026
2e819da
test: close provider recovery and lifecycle smoke budget gaps
danielmeppiel Sep 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion .apm/architecture/owners/contracts-tooling.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,31 @@
"src/apm_cli/models/dependency/object_fields.py",
"src/apm_cli/models/dependency/reference.py",
"src/apm_cli/primitives/discovery.py",
"src/apm_cli/deps/apm_resolver.py"
"src/apm_cli/deps/apm_resolver.py",
"src/apm_cli/commands/deps/cli.py",
"src/apm_cli/install/phases/download.py",
"src/apm_cli/install/phases/integrate.py",
"src/apm_cli/install/plan.py"
],
"guards": ["contracts-tooling-dependency-identity", "contracts-tooling-policy-identity"]
},
{
"id": "native-lifecycle-evidence",
"decision": "Bounded #2867 fresh source-Python lifecycle evidence, immutable witness bindings and candidate-bound native completion; not repository shipping policy",
"owner": "scripts/lifecycle_contracts.py (authored obligations and execution validation) + scripts/check_lifecycle_evidence.py (candidate identity and completion) + tests/utils/lifecycle_evidence.py (fresh runner/Hypothesis observation)",
"selectors": [
"scripts/check_lifecycle_evidence.py",
"scripts/lifecycle_contracts.py",
"tests/utils/lifecycle_evidence.py",
"tests/utils/apm_lifecycle_runner.py",
"tests/utils/isolated_apm_environment.py",
"tests/fixtures/lifecycle_bug_ledger.json",
"tests/fixtures/lifecycle_completion.schema.json",
"tests/unit/scripts/test_lifecycle_evidence.py",
"tests/integration/test_architecture_native_lifecycle_evidence.py"
],
"guards": ["contracts-tooling-native-lifecycle-evidence"]
},
{
"id": "generated-python-artifact-membership",
"decision": "Generated Python bytecode membership across copy, inventory, and cleanup",
Expand Down
8 changes: 6 additions & 2 deletions .apm/architecture/owners/install-deployment.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@
{
"id": "deployment-provenance-state",
"decision": "Deployment provenance / state",
"owner": "deployment_ledger.py",
"selectors": ["src/apm_cli/core/deployment_ledger.py"],
"owner": "deployment_ledger.py; read-only index: skill_support.build_skill_ownership_maps, exposed by SkillIntegrator._build_ownership_maps with integrate-phase snapshot lifetime",
"selectors": [
"src/apm_cli/core/deployment_ledger.py",
"src/apm_cli/integration/skill_support.py",
"src/apm_cli/install/pipeline.py"
],
"guards": ["install-deployment-provenance-state"]
},
{
Expand Down
11 changes: 6 additions & 5 deletions .apm/architecture/owners/transport-auth-platform.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@
},
{
"id": "host-credential-resolution",
"decision": "Host + credential resolution",
"owner": "core/auth.py (AuthResolver), core/host_providers.py",
"decision": "Host + credential resolution and effective provider identity consumed by dependency drift and dependency-scoped lock seeds",
"owner": "core/auth.py (AuthResolver), core/host_providers.py (effective_host_provider_identity); consumers: drift.py and tiered_ref_resolver.py",
"selectors": [
"src/apm_cli/core/auth.py",
"src/apm_cli/core/host_providers.py"
"src/apm_cli/core/host_providers.py",
"src/apm_cli/drift.py"
],
"guards": [
"transport-platform-ado-validation-bearer-fallback",
Expand Down Expand Up @@ -137,8 +138,8 @@
},
{
"id": "git-ref-freshness",
"decision": "Git ref freshness and cache eligibility",
"owner": "deps/tiered_ref_resolver.py (RefFreshnessPolicy)",
"decision": "Git ref freshness, cache eligibility, and dependency-scoped lock-seed identity",
"owner": "deps/tiered_ref_resolver.py (RefFreshnessPolicy, _lock_seed_key consuming effective_host_provider_identity)",
"selectors": ["src/apm_cli/deps/tiered_ref_resolver.py"],
"guards": ["transport-platform-ref-freshness"]
},
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,8 @@ jobs:
#
# Why timeout-minutes: 6
# ------------------------
# Two xdist workers share the required selection without widening the cap.
# Four xdist workers use the public Ubuntu runner's four CPUs without
# widening the cap or changing the required selection.
# loadgroup preserves xdist_group serialization for HOME-mutating tests,
# matching the merge-group integration scheduler. The 6-minute cap includes
# checkout/setup/sync/cleanup; hosted job duration is the release authority.
Expand Down Expand Up @@ -628,6 +629,8 @@ jobs:
env:
APM_E2E_TESTS: "1"
run: |
printf 'Runner logical CPUs: '
nproc
uv run --extra dev pytest -p no:cacheprovider -q --strict-markers \
-n 2 --dist loadgroup \
-n 4 --dist loadgroup \
-m 'lifecycle_smoke and not lifecycle_merge_group' tests/integration
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Global skill installs work through `HOME`/`APM_HOME` directory aliases without relaxing package or destination safety; frozen installs reject ref, pin, provider and transport drift, and unseeded mutable refs resolve upstream. After an intentional declaration change, review it and run `apm install --update`. (by @DaveMeadAdjust, #2876)
### Added

- GitHub MCP authentication now preserves explicit `Authorization` headers and writes the selected environment-variable reference on runtime-capable targets instead of resolving the credential into generated config. (#3103)
- OpenCode MCP installs and reinstalls preserve an explicitly supplied `enabled` value and JSON type; omitted values still default to `true` - by @dajiaohuang (#3102).
- `apm compile --target claude` imports dependency-root `CLAUDE.md` files at any metadata-backed materialization depth, including ADO and nested GitLab paths, and resolves transitive imports with redirected `--root` output. Frozen replay also reads the selected installation's lockfile. (by @vyrnsynx, #2952)
Expand Down
3 changes: 2 additions & 1 deletion CONFORMANCE.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@
"keyword": "MUST",
"section": "5.2",
"status": "active",
"test_count": 4,
"test_count": 5,
"tests": [
"tests/spec_conformance/test_lockfile_reqs.py::test_frozen_manifest_pin_requires_the_exact_locked_commit",
"tests/spec_conformance/test_lockfile_reqs.py::test_full_sha_pin_audit_rejects_resolved_commit_mismatch",
"tests/spec_conformance/test_lockfile_reqs.py::test_lockfile_carries_dependencies_block",
"tests/spec_conformance/test_resolution_reqs.py::test_frozen_short_pin_checks_recorded_commit_without_discovery[False]",
Expand Down
2 changes: 1 addition & 1 deletion CONFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Repository-coordinate segments are case-insensitive for `github.com`, GitHub Ent
| [req-ext-002](docs/src/content/docs/specs/openapm-v0.1.md#req-ext-002) | MUST | 4.1 | producer | active | 1 | - |
| [req-lk-001](docs/src/content/docs/specs/openapm-v0.1.md#req-lk-001) | MUST | 5.1 | consumer | active | 1 | - |
| [req-lk-002](docs/src/content/docs/specs/openapm-v0.1.md#req-lk-002) | MUST | 5.4 | consumer | active | 1 | - |
| [req-lk-003](docs/src/content/docs/specs/openapm-v0.1.md#req-lk-003) | MUST | 5.2 | consumer | active | 4 | - |
| [req-lk-003](docs/src/content/docs/specs/openapm-v0.1.md#req-lk-003) | MUST | 5.2 | consumer | active | 5 | - |
| [req-lk-004](docs/src/content/docs/specs/openapm-v0.1.md#req-lk-004) | MUST | 5.4 | consumer | active | 1 | - |
| [req-lk-005](docs/src/content/docs/specs/openapm-v0.1.md#req-lk-005) | MUST | 5.5 | consumer | active | 2 | - |
| [req-lk-006](docs/src/content/docs/specs/openapm-v0.1.md#req-lk-006) | MUST | 5.5 | consumer | active | 5 | - |
Expand Down
38 changes: 37 additions & 1 deletion docs/src/content/docs/contributing/integration-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,42 @@ APM uses a tiered approach to integration testing:

## Running Tests Locally

### Exact-head HOME-alias lifecycle qualification

The #2867 contract uses real CLI subprocesses in isolated project, canonical-home
and aliased-home fixtures. Its eight required/generated/replay witnesses retain
the mandatory lifecycle inside Hypothesis execution; an additional project
scenario checks semver transport refusal and recovery. Ownership snapshot tests
also enforce one lockfile read per used root and integration phase, zero unused
reads, and at most 15x record visits when fixture size grows from N to 10N.
These counts do not claim a wall-clock speedup.

Use a clean committed checkout. Set `BASE_SHA` to the full 40-hex commit SHA
of a locally available, distinct ancestor of the checked-out `HEAD`.
Set `REPORT_PATH` and `COMPLETION_PATH` to distinct, new paths outside the checkout:

```bash
uv run --frozen --extra dev python scripts/check_lifecycle_evidence.py \
--base "$BASE_SHA" --head "$(git rev-parse HEAD)" --lane full \
--report "$REPORT_PATH" --completion-output "$COMPLETION_PATH"
```

The command emits the schema-validated native completion sidecar only after fresh success.
It verifies source/interpreter identity and freshly executes the authored
contract; a skipped witness or disconnected sequence is not acceptance.
It is source-Python coverage, not packaged-binary parity. Ordinary hosted
platform checks remain separate.

For independent acceptance, use another clean checkout with the same base/head,
its own interpreter and disposable environment. Replace `--completion-output`
with `--completion "$DRIVER_COMPLETION_PATH"`, pointing to the driver's native
sidecar, and use a new external `--report` path. Keep the driver's report available
at the path recorded in that sidecar. Completion mode verifies its digest and
reruns the contract; it does not reuse the report as execution. Keep this native
sidecar separate from the unchanged merge-worker completion JSON.

### Selecting integration tests

Integration tests live under `tests/integration/` and run via `pytest`
directly. Each test module declares the preconditions it needs as
standard pytest markers; the registry in
Expand Down Expand Up @@ -420,7 +456,7 @@ skill. The local fixture covers both an independent skill and a separately
installed skill from the plugin; the network-backed case uses the same assertions.
Cleanup wording is not the lifecycle contract.

Linux Lifecycle Smoke runs the required marker subset with `-n 2 --dist loadgroup`. Grouped tests stay on one worker, and the six-minute job limit remains unchanged.
Linux Lifecycle Smoke runs the required marker subset with four bounded workers (`-n 4 --dist loadgroup`) on the public Ubuntu runner. Grouped tests stay on one worker, and the six-minute job limit remains unchanged.
Its `lifecycle_smoke and not lifecycle_merge_group` selection is not all
lifecycle coverage: also run affected generated state machines, deployment
ledger, and failure/retry contracts when changing those behaviors.
Expand Down
4 changes: 4 additions & 0 deletions docs/src/content/docs/reference/cli/deps.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ installed package's source tree are parent-owned content, not separate
dependencies. Real lockfile-resolved dependencies install at their own package
roots and remain visible regardless of graph depth.

Declared or locked aliases are found at `apm_modules/<alias>` and displayed
under their logical dependency identity. The selected project or user store
remains authoritative; listing does not search another store to fill a gap.

Local dependencies are shown as portable `_local/<name>` keys rather than
machine-specific absolute paths. For a direct local declaration with matching
`apm.lock.yaml` metadata, copy that key into `apm uninstall` (with `-g` for user
Expand Down
Loading
Loading