fix(install): preserve generated aggregate ownership and rebuilds - #2923
fix(install): preserve generated aggregate ownership and rebuilds#2923Daniel Meppiel (danielmeppiel) wants to merge 13 commits into
Conversation
Extract the complete aggregate runtime and lifecycle proof from #2820 at 824b170 onto current main. Preserve shared final digests, source-backed survivor/root reconstruction, safe refusal receipts and proven-removal projection cleanup without activating corrective v0.2. Acquisition-source cached caller and its routing witness belong to the combined local/audit successor. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve only aggregate user guidance from #2820, retaining current main documentation ordering and the active v0.1 assessment. Explain whole-file source authoring, truthful refusal receipts and global-scope recovery without a force bypass. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Extract the exact cached restoration call from #2820 (824b170). Both independent successors inherit this same prerequisite. Move the two cached/fresh identity cases from 0119fc6 into their shared module; retain parsed URL assertions. No acquisition trust or local admission changes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Restore the original #2820 cached-source route and mutation witness to aggregate ownership. The canonical caller and its cached/fresh behavioral cases now belong to shared prerequisite 63b3619 rather than depending on another successor landing first. 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>
APM expert advisory panelRecommendation: ship_with_followups. Implementation accepted; human ship/approval gates remain. Final continuation of the existing outer4 advisory, not a new panel or roster. This updates the prior Prior findings are closed
Exact-head local evidence: 110 focused tests, 43 restored controls, 13 installed-CLI native positives with zero errors/failures/skips; eight component mutations killed plus the separate installed legacy negative; canonical seven lint gates and architecture boundaries pass. These groups are not a claim of unique whole-suite coverage. Hosted success observed on the same SHA: CI, required The actual CEO continuation accepts the implementation and reports no remaining in-scope code finding. Retained Architecture, Performance and Supply Chain source follow-ups support the bounded codec change; no security finding is overridden. The actual test-coverage continuation confirms the lint helper/closure repairs preserve all 13 obligations and original assertions. No new abstraction, trust authority or registry schema was introduced. Evidence and scope limitsNative qualification is this checkout's own installed editable CLI in isolated homes, not a packaged binary. Warm measurements count codec record/owner construction, not elapsed time or all install work. Original aggregate runtime lineage is preserved through The docs classifier and growth invocation failures remain explicitly disclosed. The continuation's tool-less classifier also failed; bounded orchestrator source/diff/index fallback is not portrayed as a successful specialist review. Retained CDO acceptance remains authoritative for the adopted prose. Source identity restoration is not acquisition trust; #2919 owns that separate scope. The original outer4/Copilot2/CI2 history is preserved. Later user authorization removed administrative stopping conditions; it did not grant approval, merge or specification-ratification authority. Required human actionsThe driver has marked this PR ready for review and requested Sergio Sisternes (@sergio-sisternes-epam) under explicit maintainer authorization. Readback confirms the same qualified head and green checks; no human approval has been supplied.
This is an advisory recommendation, not a merge approval. The owner-gate verifier's full-path success certifies its evidence contract, not the outstanding human permissions. |
Docs sync advisoryVerdict: in_place, CDO agree; adopted * Pages affected: 1 * LLM calls/phases: 11/15 (conservative inherited accounting including failed invocations and bounded fallbacks) The canonical uninstall reference now states that root-owned receipts can retain the lockfile after the last package is removed. It also distinguishes aggregate cleanup/rebuild failure after package and declaration removal, and links to scope-correct recovery in the existing Copilot targets reference. Existing target-cleanup, hook and LSP paragraphs remain unchanged. No TOC or normative specification change was made. The original writer, deterministic Python verifier, editorial review and CDO accepted this two-location correction. It was committed at Continuation scope: the later codec accumulation preserves the public contract; the conformance regeneration adds two existing-requirement witnesses without changing requirement text/status. The last three commits regenerate inventory and perform assertion-preserving test lint repairs. These deltas need no additional page or TOC change. This is a narrow continuation conclusion, not a claim that the whole PR had no documentation impact. Execution limits: the original classifier reported unavailable tools and the original growth invocation could not resolve its artifact path. The continuation classifier also lacked file/command tools. Those invocations are failures, not successful specialist reviews; the orchestrator recorded bounded source/diff/index fallbacks, without another roster. The retained successful panel returns were schema-validated. Current evidence: all 13 installed-editable-CLI lifecycle cases pass at |
Exercise req-lk-020 fresh active-path preservation across prior identities and req-lk-016 serialized digest envelopes through canonical aggregate cleanup and attachment. Preserve the original twelve native cases and add direct uninstall from legacy last-writer-only receipts. Fold the canonical uninstall reference correction from the actual final outer4 advisory. No normative text, waiver, or runtime semantics change. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep accumulation within DeploymentLedgerCodec and preserve owner order and hash fallback. Add warm root/no-root scaling traps and legacy/native semantic controls. Runtime qualification remains pending the assigned execution slot. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Regenerate the existing conformance statement after adding the req-lk-016 and req-lk-020 aggregate regression tests. Preserve all requirement statuses and normative text while making the committed test inventory match hosted generation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Extract persisted legacy receipt, installed-source, and root-only assertions without dropping checks; bind warm codec counters outside the size loop. Preserve all thirteen native scenarios and scaling-control semantics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve the original #2820 history while moving executable ownership to the published #2919 and #2923 successors. Restore current main runtime and the active v0.1 assessment verbatim; retain the exact corrective draft overlay and its release-note obligation. Final normative repin still follows qualified-human #2901 landing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved critical cleanup and moderate aggregate ownership and error-reporting issues remain.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Lite
Findings: 1
New issues introduced by this change (2)
| Severity | Finding |
|---|---|
src/apm_cli/integration/instruction_integrator.py — This aggregate cleanup passes an empty hash map when the legacy receipt has no… |
|
CHANGELOG.md — The Unreleased entry ends with (#2820), which identifies the earlier foundation PR rather than… |
What changed in this PR
This PR repairs shared Copilot instruction ownership and uninstall reconstruction.
Changes:
- Tracks aggregate contributors and final content hashes.
- Rebuilds validated survivor/root content with safer cleanup and recovery.
- Adds identity fixes, ledger updates, tests, architecture checks, documentation, and conformance updates.
Open findings:
- Critical — Hashless legacy receipts can bypass edited-file cleanup protection.
- Moderate —
--onlyinstalls may drop claims for unselected dependencies. - Moderate — Removing root instructions can preserve stale aggregate ownership.
- Moderate — Verbose aggregate errors can expose chained exception details.
- Nit — Changelog attribution should reference
#2923, not#2820.
| File | Summary |
|---|---|
tests/unit/test_uninstall_engine_helpers.py |
Tests recovery and truthful failure outcomes. |
tests/unit/test_aggregate_installed_source.py |
Tests installed-source identity safeguards. |
tests/unit/scripts/test_architecture_runner.py |
Verifies architecture rule registration. |
tests/unit/install/test_install_copilot_user_instructions.py |
Tests aggregate output locations. |
tests/unit/install/test_cached_source_identity.py |
Tests cached and fresh Git identity. |
tests/unit/install/phases/test_lockfile_cross_package_reconcile.py |
Tests aggregate hashes, claims, and reconstruction work bounds. |
tests/unit/core/test_deployment_state.py |
Tests codec ordering, hashing, and row semantics. |
tests/spec_conformance/test_aggregate_lockfile_reqs.py |
Adds aggregate lockfile conformance witnesses. |
tests/integration/test_copilot_aggregate_uninstall.py |
Covers installed-CLI aggregate lifecycle scenarios. |
tests/integration/test_architecture_owner_rule_mutations.py |
Registers aggregate mutation coverage. |
tests/integration/test_architecture_copilot_aggregate.py |
Tests aggregate architecture boundaries. |
src/apm_cli/models/apm_package.py |
Restores shared Git source identity. |
src/apm_cli/integration/instruction_integrator.py |
Handles aggregate discovery and cleanup. |
src/apm_cli/install/sources.py |
Applies cached source identity restoration. |
src/apm_cli/install/services.py |
Controls reconstruction scan hints. |
src/apm_cli/install/phases/lockfile.py |
Persists aggregate hashes, claims, and invalidation state. |
src/apm_cli/install/manifest_reconcile.py |
Protects genuine root-authored files. |
src/apm_cli/install/helpers/security_scan.py |
Suppresses ineffective force hints during reconstruction. |
src/apm_cli/core/deployment_state.py |
Tracks ordered shared aggregate ownership. |
src/apm_cli/core/deployment_ledger.py |
Reconstructs receipts and projects compatibility state. |
src/apm_cli/commands/uninstall/lockfile_state.py |
Propagates confirmed removal state. |
src/apm_cli/commands/uninstall/engine.py |
Rebuilds aggregates and reports typed failures. |
src/apm_cli/commands/uninstall/cli.py |
Handles partial-removal recovery. |
scripts/architecture_linter/checks/install_deployment_analyzers.py |
Checks removal forwarding. |
scripts/architecture_linter/checks/install_base_integrator_and_contraction.py |
Checks aggregate routing. |
packages/apm-guide/.apm/skills/apm-usage/commands.md |
Adds recovery guidance. |
docs/src/content/docs/reference/targets-matrix.md |
Documents aggregate ownership behavior. |
docs/src/content/docs/reference/cli/uninstall.md |
Documents aggregate recovery. |
CONFORMANCE.md |
Regenerates conformance documentation. |
CONFORMANCE.json |
Regenerates the conformance inventory. |
CHANGELOG.md |
Records the user-visible fix. |
.apm/architecture/owners/install-deployment.json |
Registers ownership boundaries. |
Suppressed comments (3)
src/apm_cli/commands/uninstall/cli.py:144
AggregateIntegrationErrordeliberately exposes only sanitized phase/path facts, but this unconditional traceback also emits its chained cause in verbose mode. Source validation or cleanup exceptions can put raw paths and source/error text in that traceback, defeating the sanitization promised by the new exception; keep the traceback detail for generic errors only.
logger.verbose_detail(f"Integration cleanup failed: {type(sync_err).__name__}: {sync_err}")
logger.verbose_detail(traceback.format_exc().rstrip())
src/apm_cli/install/phases/lockfile.py:535
- When an existing user-scope aggregate was also recorded under
., removing the root instructions leavescurrent_aggregatesempty, but this union copies the old aggregate back into the new local compatibility view.post_deps_localis skipped for USER scope, so the stale root owner and hash survive and later uninstall treats package-only output as root-owned. Filter prior local state so aggregate paths are carried forward only when they are present incurrent_aggregates.
local_files = sorted(
set(self.ctx.existing_lockfile.local_deployed_files) | current_aggregates
)
src/apm_cli/install/phases/lockfile.py:250
- This path also runs for
--onlyinstalls, wherepackage_keyscontains the merged existing dependencies butcurrent_claimscontains only the selected packages. For a shared aggregate,reconcile_package_claimstherefore drops the prior claims for unselected packages; because a selected package still produces a canonical batch,apply_to_lockfilethen projects emptydeployed_filesfor those survivors and loses their ownership. Carry forward shared claims for unselected dependencies (or preserve their canonical rows) before projecting the merged ledger.
package_claims = DeploymentReconciler.reconcile_package_claims(
package_keys=package_keys,
current_claims=current_claims,
prior_files=prior_files_by_package,
prior_hashes=prior_hashes_by_package,
shared_paths=shared_paths,
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| cleanup = remove_stale_deployed_files( | ||
| project_root=project_root, | ||
| stale_paths=self.aggregate_paths([target]).intersection(managed_files or ()), | ||
| recorded_hashes=managed_file_hashes or {}, |
|
|
||
| ### Fixed | ||
|
|
||
| - Generated Copilot user instructions retain every contributor's ownership; global uninstall rebuilds surviving sources and root authoring, while cleanup refusals retain receipts and report partial removal with recovery steps. (#2820) |


fix(install): preserve and rebuild shared Copilot aggregate ownership
TL;DR
Record every contributor to generated Copilot user instructions with the final combined-content digest, then reconstruct the file from surviving package sources and genuine root authoring on uninstall. Preserve ordinary last-writer collision behavior and refuse unsafe cleanup. The directly coupled warm-codec repair accumulates ordered owners before freezing records, avoiding repeated growing-owner copies without changing receipt semantics.
Important
Aggregate-only successor to #2820, not a claim to resolve all of #2815, #2816, or #2818. Local-source admission and acquisition trust belong to #2919. This PR does not activate OpenAPM v0.2, change the v0.1 assessment, ratify specification text, or authorize merge.
Problem (WHY)
Unrecorded removed-owner body survivedin the installed CLI.These are executable failure cases, not speculative expansion of the original fix. The evidence-first scope follows Agent Skills' "Real-world failure cases and their resolutions".
Approach (WHAT)
Implementation (HOW)
Runtime paths below are under
src/apm_cli/; test and documentation paths are repository-relative.models/apm_package.pyf1a605862.install/sources.py63b361990, whose parent isf1a605862; no trust fields added.core/deployment_state.pycore/deployment_ledger.pyinstall/phases/lockfile.pyinstall/manifest_reconcile.pyintegration/instruction_integrator.pycommands/uninstall/engine.pycommands/uninstall/cli.py,commands/uninstall/lockfile_state.pyinstall/services.py,install/helpers/security_scan.py.apm/architecture/owners/install-deployment.jsonscripts/architecture_linter/checks/install_base_integrator_and_contraction.py,install_deployment_analyzers.pytests/integration/test_architecture_copilot_aggregate.py,test_architecture_owner_rule_mutations.pytests/integration/test_copilot_aggregate_uninstall.pytests/unit/core/test_deployment_state.pytests/unit/install/phases/test_lockfile_cross_package_reconcile.pytests/unit/install/test_cached_source_identity.py,tests/unit/test_aggregate_installed_source.pytests/unit/test_uninstall_engine_helpers.pytests/unit/install/test_install_copilot_user_instructions.py,tests/unit/scripts/test_architecture_runner.pytests/spec_conformance/test_aggregate_lockfile_reqs.pyreq-lk-020fresh-path andreq-lk-016hash-envelope witnesses.CONFORMANCE.json,CONFORMANCE.mddocs/src/content/docs/reference/cli/uninstall.md,reference/targets-matrix.mdpackages/apm-guide/.apm/skills/apm-usage/commands.md,CHANGELOG.mdThe cached caller restores identity, not acquisition trust. The warm controls count actual codec construction through existing-local-state preservation.
Diagrams
Authored inputs pass through existing safety owners; successful reconstruction records shared ownership, while refusal retains prior receipts.
flowchart LR subgraph Sources["Authored inputs"] P["Surviving package instructions"] R["Root .apm instructions"] end subgraph Validation["Canonical safety owners"] C["remove_stale_deployed_files: hash and containment"] S["integrate_package_primitives: authorization and scan"] end subgraph Materialization["Generated output"] A["InstructionIntegrator: write generated aggregate"] L["DeploymentLedgerCodec: shared owners and final digest"] F["AggregateIntegrationError: retain prior receipts"] end P --> S R --> S C -->|"safe removal"| S C -->|"refused"| F S -->|"accepted sources"| A S -->|"source failure"| F A --> L classDef new stroke-dasharray: 5 5; class C,L,F new;Trade-offs
.apm/instructions/; back up/move refused generated output before regeneration.Benefits
Validation
Local qualification head:
6ccd935af3bd8bd02cbd889db742f41f3c030896; included main:e38261c5db4d893d6ddebc3925742e4e3bd2ba74.Runtime source is byte-identical to preserved
475550d0; subsequent commits regenerate conformance inventory and make assertion-preserving test lint repairs.Frozen
uv.lockversions and hashes were restored through the existing trusted enterprise feed;UV_NO_SYNC=1prevents redundant dependency restoration, not test execution.Exact-head local execution excerpts and mutation limits
Focused aggregate, model, cached-source, contraction, codec, recovery and architecture selectors via
uv run --frozen --extra dev pytest -p no:cacheprovider -q -s:Restored regression selectors, including all 14 codec semantic controls, using the same runner:
APM_BINARY_PATH="$PWD/.venv/bin/apm" uv run --frozen --extra dev pytest -p no:cacheprovider -q -s tests/integration/test_copilot_aggregate_uninstall.py:All 13 native cases have zero failures/errors/skips. Eight isolated component mutations were killed, plus one separate installed-CLI legacy negative. The latter preserves original function globals/classes/references and fails the removed-owner-body assertion, not setup/import.
The two-method old-codec mutation through the existing warm route:
Both failures are the owner-work bound. Restored no-root counts are
100 -> 1000; root counts are102 -> 1002; both keep two record constructions.BASE_REF=e38261c5db4d893d6ddebc3925742e4e3bd2ba74 bash tests/spec_conformance/mode_b_detector.sh:The concurrent edit consists of two genuine existing-v0.1 test witnesses, not a waiver or new normative clause. Orphan binding passes. Generated inventory was refreshed after the full conformance run (
204 passed, 2 skippedat475550; those existing skips are not native aggregate skips).Canonical seven-part lint mirror plus architecture boundaries on the exact final head:
The deterministic owner detector found four touched owners. Schema-valid v2 evidence maps each to executed exact-head functional tests; the semantic verifier re-detected the same base/head and reported
terminal_evidence_required: true, not the blocked-status bypass.Hosted Spec conformance passed at this SHA, including Mode B, the complete conformance suite and clean regenerated artifacts. The former spec-citation failure is resolved without a waiver. Human approval and any normative ratification are separate from this result.
Hosted CI, required
gate, CodeQL, NOTICE and Docs workflows also succeeded. The existing CEO continuation accepts the implementation with no remaining in-scope finding; the draft/code-owner/last-push and human ship decision remain outstanding.Scenario Evidence
Lifecyclebelow meanstests/integration/test_copilot_aggregate_uninstall.py::test_generated_copilot_aggregate_lifecycle; every listed native row passed at the exact head above.[initial-owners](original #2820 regression trap)[removed-section],[survivor-state][survivor-identity]; cached/fresh identity tests[collision][root][edited][unsafe-survivor][survivor-empty],[survivor-missing],[survivor-ineligible][root-missing][legacy-last-writer]plus guard-deletion negativetests/unit/install/phases/test_lockfile_cross_package_reconcile.py::test_aggregate_attachment_work_is_linear,::test_warm_aggregate_root_carry_work_is_linearHow to test
APM_BINARY_PATHand a unique pytest--basetemp; expect no skips and unchanged unowned sentinels.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com