Skip to content

fix(install): verify local content in frozen mode - #3236

Open
Wu Shuwen (dajiaohuang) wants to merge 13 commits into
microsoft:mainfrom
dajiaohuang:fix/3194-frozen-local-path
Open

Wu Shuwen (dajiaohuang) wants to merge 13 commits into
microsoft:mainfrom
dajiaohuang:fix/3194-frozen-local-path

Conversation

@dajiaohuang

@dajiaohuang Wu Shuwen (dajiaohuang) commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Description

Normal installs record the existing content hash from the validated, dereferenced local-copy image before integration transforms. Frozen installs compare each selected direct or transitive local dependency against its existing lock evidence before lifecycle/pipeline work. Changed, added, or removed content and missing or legacy baseline evidence are refused without replacing managed content or rewriting the lockfile. Unchanged replay and ordinary non-frozen local development remain supported.

The bounded CI recovery adds proposed req-lk-023, four real-CLI conformance cases, and five direct-local content_hash fields. The latest-main continuation required no re-seeding: all five hashes still match their canonical validated-copy images. The candidate root audit passes all 10 checks, preserving 3,099 tracked files and all 288 recorded managed paths, including file/directory modes and exact lock bytes. The actual latest-main combined-tree audit also passes without mutations. Every other lock semantic value equals integrated main; no broad root regeneration was run.

Important

The specification change is proposed 0.1.48, not adopted; main's separate 0.1.47 amendment is preserved. Product-scope acceptance and automated review do not establish Section 9.3 qualified non-author approvals or the ensuing comment period. This assignment requires genuine human adoption evidence; applicable Section 9.2/9.5 obligations also remain. Cross-implementation local-hash canonicalization remains reserved for v0.2.

Issue and approved scope

Issue: #3194

Human scope-approval comment: #3194 (comment)

This PR implements the accepted scope, including explicit missing-baseline handling and real APMLifecycle regression evidence. It does not request merge approval or change the hash algorithm, lockfile format, or the project's own .apm/ deployment behavior.

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally
  • All existing tests pass
  • Added tests for new functionality (if applicable)

Exact locally tested head: fc5241d155bb8b9d80b02649ffe8732fce8f4075; integrated base: bd672981210f7751381d88eba4d9d9354d2a44ea. All six exact-head technical workflows passed: CI, Merge Gate, CodeQL, Docs, Spec, and NOTICE. This does not claim a complete local test-suite run.

Latest main 6333b56a3c2e11e20d87f6f55070c4a06669d06d was strictly merged into a non-committed preview and actually root-audited; all five canonical hashes and tracked/managed bytes and modes remained unchanged. Regenerated conformance stayed stable at 130 requirements. The preview was aborted to preserve the tested candidate; it is not claimed as the locally tested base. CodeQL uploads cover merge faa14ea217cce30ea5d2f2f370502d698fef5e27 (parents: tested bd672981 and this published head), with no errors, warnings, or results. They do not prove that newer main 6333b56a was scanned. No empty commit or scan-chasing push was made.

Executed local commands and results
APM_E2E_TESTS=1 uv run --frozen --extra dev pytest tests/integration/test_frozen_local_path_lifecycle.py tests/spec_conformance/test_frozen_local_content_reqs.py tests/unit/install/test_sources_materialisation.py::TestLocalDependencySourceAcquire::test_success_with_apm_yml tests/unit/install/test_plan.py::TestLockfileSatisfiesManifest::test_local_deps_require_locked_evidence tests/integration/test_unmatched_skill_selection_lifecycle.py tests/spec_conformance/test_claude_cleanup_roots.py tests/integration/test_local_shared_root_skill_cleanup.py tests/unit/install/test_local_rows_need_reconciling.py -q -n 2 -p no:cacheprovider --basetemp=../pr-3236-evidence/oct16-runtime/bd-head-tests
50 passed in 300.68s (all selected cases executed, including upstream shared-root cleanup, conservative historical preservation, and selection cases)

uv run --frozen --extra dev apm audit --ci
All 10 checks passed (audit scratch outside the project tree)

uv run --frozen --extra dev python -m tests.spec_conformance.orphan_check
130 requirements aligned across anchors / manifest / Appendix C / pytest markers

uv run --frozen --extra dev python -m tests.spec_conformance.gen_statement
git diff --exit-code -- CONFORMANCE.md CONFORMANCE.json
Passed; committed generated inventory is unchanged

uv run --frozen --extra dev ruff check src/ tests/ scripts/lint_architecture_boundaries.py scripts/architecture_linter/ scripts/windows_native_symlink_probe_entry.py
Passed
uv run --frozen --extra dev ruff format --check src/ tests/ scripts/lint_architecture_boundaries.py scripts/architecture_linter/ scripts/windows_native_symlink_probe_entry.py
Passed; 1953 files already formatted
uv run --frozen --extra dev python -m pylint --disable=all --enable=R0801 --min-similarity-lines=10 --fail-on=R0801 src/apm_cli/ scripts/lint_architecture_boundaries.py scripts/architecture_linter/ scripts/windows_native_symlink_probe_entry.py
Passed; 10.00/10
bash scripts/lint-auth-signals.sh
Passed
bash scripts/lint-architecture-boundaries.sh
Passed

The YAML-I/O, 2,100-line, and portable-relative-path guards also passed. Fresh deterministic owner detection covers two canonical owners, with version-2 functional evidence bound to the exact head.

Scenario evidence and how to test

  • Run the command above. test_frozen_local_path_refuses_changed_snapshot_without_mutation covers direct/transitive content changes, cold/existing consumers, unchanged replay, and recovery (secure-by-default).
  • test_frozen_local_requires_selected_lock_evidence covers missing entries and legacy baselines; the orphan and symlink-retarget cases protect selected-graph and materialization semantics (secure-by-default).
  • test_frozen_local_content_preserves_prior_evidence covers direct/transitive changed content and legacy baselines through the real CLI, including exact filesystem snapshots and restoration (secure-by-default).

Historical mutation proof (not rerun in this continuation; all eight scoped source/test blobs are unchanged from cd4cc0d): all four new conformance cases failed with the verifier/baseline guards removed, then passed after restoration. Earlier targeted mutations produced 7, 2, and 3 expected failures for the original production guards.

The latest main integration preserves concrete local target provenance, shared sibling claims, conservative preservation of ambiguous historical/bundle paths, and the dry-run stale-cleanup caveat. No blanket historical deletion is authorized.

Trade-offs: missing-baseline legacy frozen installs now fail explicitly; review sources and use a normal install to establish trusted evidence. Verification uses the existing validated-copy/hash owners rather than changing the global hash policy or substituting transformed deployed-file hashes.

Spec conformance (OpenAPM v0.1)

If this PR changes behaviour that an OpenAPM v0.1 req-XXX covers,
confirm the three-step ritual in the
development guide:

  • Spec edit: docs/src/content/docs/specs/openapm-v0.1.md updated
    (new/changed <a id="req-XXX"></a> anchor + prose + Appendix C
    row).
  • Manifest edit: docs/src/content/docs/specs/manifests/openapm-v0.1.requirements.yml
    updated.
    The repository's current canonical manifest location is docs/public/specs/manifests/openapm-v0.1.requirements.yml; that is the file updated here.
  • Test edit: a @pytest.mark.req("req-XXX") test under
    tests/spec_conformance/ added or extended.
  • CONFORMANCE.{md,json} regenerated via
    uv run --extra dev python -m tests.spec_conformance.gen_statement
    and committed.
  • N/A -- this PR does not change OpenAPM-observable behaviour.

Requirement: proposed req-lk-023. The genuine prior review by four spec-guardian reviewers plus the synthesizer returned an average 8.0/10 with no blocking findings. In-scope folds are implemented, including the runtime test index; the proposed-status annotation preserves the canonical Appendix C parser grammar. No internal-refactor or N/A waiver is used.

The prior CEO stance remains ship_with_followups, not a new panel approval of this integration. Section 9.3 still lacks a spec-labeled issue, qualifying amendment approvals, and the ensuing 14-day period. A proposed draft merge is not itself a claim of adoption, but the stated sequence supplies no explicit early-merge exception. A maintainer must decide the non-adopting integration interpretation or complete that sequence; technical success is not ratification, platform admission, or merge permission.

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.

🟡 Changes recommended

Verification misses unlocked local dependencies and symlink changes while incorrectly rejecting tolerated orphan entries.

4 open findings
What changed in this PR

Addresses #3194 by recording local-package source hashes and checking them before frozen-install deployment.

Changes:

  • Records and verifies local source-content hashes.
  • Adds lifecycle coverage for replay, content changes, and restoration.
  • Documents frozen-mode checks and legacy-lock behavior.
File Description
tests/​integration/​test_frozen_local_path_lifecycle.py Adds frozen local-package lifecycle coverage.
src/​apm_cli/​install/​sources.py Records local source-tree hashes.
src/​apm_cli/​install/​service.py Adds preflight local-content verification.
packages/​apm-guide/​.apm/​skills/​apm-usage/​commands.md Updates bundled install guidance.
docs/​src/​content/​docs/​reference/​cli/​install.md Documents local-content and legacy-lock checks.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/apm_cli/install/service.py Outdated
Comment thread src/apm_cli/install/sources.py Outdated
Comment thread src/apm_cli/install/service.py Outdated
Comment thread tests/integration/test_frozen_local_path_lifecycle.py
Preserve current upstream behavior and README link corrections before scoped validation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Address Copilot and panel findings on microsoft#3236 for accepted scope microsoft#3194. Require lock evidence through structural satisfaction, validate only reachable local declarations using existing anchored identity, and hash the contained dereferenced local-copy image before transforms. Add independent direct/transitive lifecycle regressions, legacy and orphan cases, and mutation-tested recording evidence without changing the global hashing policy.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
@danielmeppiel

Daniel Meppiel (danielmeppiel) commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

APM Review Panel: ship_with_followups

The genuine prior CEO stance remains unchanged. This is an evidence/integration update, not a new panel approval. All eight scoped source/test blobs remain identical to reviewed cd4cc0d; the genuine guardian result remains 8.0/10, with eleven findings folded, F3 adapted, and only F13's v0.2 hash policy deferred.

Published fc5241d integrates tested main bd67298. The real documentation conflict with #3190 is resolved while preserving provenance, shared claims, conservative historical preservation, and the dry-run caveat. Fifty focused tests, full lint, exact-head two-owner v2 verification, and all six technical workflows passed. Exact commands and run links are in the PR description.

No baseline rewrite was needed: all five canonical local hashes match. Candidate and actual combined 6333b56 root audits pass 10/10 without lock, managed-byte, or mode changes; combined conformance remains stable at 130 requirements. The newer-base preview is not relabeled as locally tested or scanned. Actual CodeQL uploads cover faa14ea (bd67298 plus fc5241d), with zero results and no errors/warnings.

Req-lk-023 remains proposed 0.1.48, preserving main's separate 0.1.47. Section 9.3 still lacks the spec-labeled issue, qualified non-author amendment approvals, and ensuing 14-day period. A draft merge would not itself claim adoption, but the sequence supplies no explicit early-merge exception. A maintainer must decide that process interpretation or complete the sequence; no ratification or waiver is invented.

Technical success is not platform admission or merge permission. The parent reports an admission blocker; no current admin capability is claimed. No worker merge, reviewer request, PR review approval, issue closure, policy change, or empty scan-chasing push occurred.


Generated by autopilot-pr-merge-worker. This comment is AI-generated and may contain errors.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Record the accepted behavior as a pending normative amendment, with real CLI refusal and recovery evidence.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a

# Conflicts:
#	docs/src/content/docs/specs/openapm-v0.1.md
Only five existing local content_hash fields are added. Independent snapshots preserve 3083 tracked and managed files and all other lock semantics; root audit passes all ten checks. Fold the four-panel proposed amendment clarifications without claiming specification adoption.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Preserve upstream Copilot marketplace, unmatched-selection preservation, and SSH/cache changes. Resolve documentation overlap without changing the reviewed frozen-local implementation; retain proposed req-mf-022 revision 0.1.47 and label req-lk-023 as proposed 0.1.48. Canonical combined-tree audit confirms all five local hashes still match, so no lock refresh or managed-file regeneration is needed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Preserve microsoft#3148 user-scope containment and conformance while retaining the proposed frozen-local amendment. No feature reimplementation or hash policy change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a
Preserve microsoft#3190 concrete local target provenance, shared claims and conservative historical preservation. Resolve only the adjacent frozen/dry-run documentation rows; retain proposed req-lk-023 and current conformance contributions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f79e464c-180e-4be3-9056-0773aa679a1a

This branch has not been deployed

No deployments
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.

3 participants