fix: absolutize Copilot user-scope hook commands (closes #2232)#2236
fix: absolutize Copilot user-scope hook commands (closes #2232)#2236danielmeppiel wants to merge 3 commits into
Conversation
Thread user_scope through the Copilot hook dispatch so the existing deploy_root rewrite owner emits absolute script paths for user-scope installs while preserving relative project-scope commands. Architecture: ordinary fix within the existing neutral hook shape to native hook integrator owner. No new authority is introduced; existing deploy_root rewriting remains the canonical mechanism, and the behavioral regression tests cover both user-scope and project-scope paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes a Copilot-only inconsistency in hook integration: when installing to user scope (apm install -g), Copilot hook JSON commands are now rewritten to absolute installed script paths so they work regardless of the current working directory, while project-scope installs keep commands repo-relative to preserve portability (#1394). This aligns Copilot with the existing scope-aware command rewrite behavior used by the merge-based hook targets.
Changes:
- Thread
user_scopeinto the Copilot hook integration path and pass adeploy_rootinto the existing_rewrite_hooks_data()/_rewrite_command_for_target()rewrite logic. - Add/extend unit tests to assert Copilot project-scope commands remain relative and user-scope commands become absolute.
Show a summary per file
| File | Description |
|---|---|
src/apm_cli/integration/hook_integrator.py |
Adds a user_scope signal to Copilot hook integration and uses it to enable absolute command rewriting only for user-scope deploys. |
tests/unit/integration/test_hook_integrator.py |
Updates/extends coverage to assert repo-relative project-scope Copilot commands and absolute user-scope Copilot commands. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Low
| Args: | ||
| package_info: PackageInfo with package metadata and install path | ||
| project_root: Root directory of the project | ||
| force: If True, overwrite user-authored files on collision | ||
| managed_files: Set of relative paths known to be APM-managed | ||
| target: Optional TargetProfile for scope-resolved root_dir | ||
| user_scope: If True, rewrite hook script commands to absolute paths | ||
|
|
Clarify the Copilot-specific rewrite comment and add a debug breadcrumb when user-scope installs activate deploy-root rewriting, addressing panel follow-ups for PR #2236. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| python-architect | 0 | 0 | 0 | Clean minimal fix; canonical owner of deploy-root rewriting remains _rewrite_hooks_data. |
| cli-logging-expert | 0 | 0 | 0 | Debug breadcrumb uses _log.debug with lazy formatting and no default-mode noise. |
| devx-ux-expert | 0 | 0 | 0 | No CLI surface change; behavior fixes user-scope hook resolution. |
| supply-chain-security-expert | 0 | 0 | 0 | Existing rewrite and containment path remains in use; no new attack surface. |
| oss-growth-hacker | 0 | 0 | 0 | Silent reliability win for Copilot user-scope hooks. |
| doc-writer | 0 | 0 | 0 | No documentation drift. |
| test-coverage-expert | 0 | 0 | 0 | Regression traps cover both project-scope relative and user-scope absolute promises. |
B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.
Recommendation
Ship now. The bug fix is narrow, CI is green, and no follow-ups remain after folding the stale comment cleanup and debug breadcrumb.
Folded in this run
- (panel) Fix stale Copilot rewrite comment and add deploy-root debug breadcrumb -- resolved in a3254e4.
Regression-trap evidence (mutation-break gate)
tests/unit/integration/test_hook_integrator.py::TestScopeResolvedHookDeployment::test_copilot_user_scope_writes_absolute_hook_paths-- deleteddeploy_root=deploy_root_for_rewrite; test FAILED as expected; guard restored.
Lint contract
uv run --extra dev ruff check src/ tests/ and
uv run --extra dev ruff format --check src/ tests/ both silent.
CI
gh pr checks 2236 --repo microsoft/apm reports all checks passing, including Lint, Build & Test shards, CodeQL, gate, smoke, coverage, architecture ratchets, and CLA (after 0 CI fix iteration(s)).
Mergeability status
Captured from gh pr view 2236 --repo microsoft/apm --json number,headRefOid,mergeable,mergeStateStatus,statusCheckRollup immediately after the last push of this run.
| PR | head SHA | CEO stance | iters | folds | defers | Copilot rounds | CI | mergeable | mergeStateStatus | notes |
|---|---|---|---|---|---|---|---|---|---|---|
| #2236 | a3254e4 |
ship_now | 1 | 1 | 0 | 2 | green | MERGEABLE | BLOCKED | pending required review |
Convergence
1 outer iteration(s); 2 Copilot round(s). Final panel verdict: ship_now.
Ready for maintainer review.
Full per-persona findings
No findings.
Inactive panelists: auth-expert (no auth surface touched), performance-expert (no performance surface touched).
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
Centralize the hook deploy-root decision so Copilot and merged-hook targets share the same user-scope absolutization rule, and add the missing changelog entry for PR #2236 follow-ups. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 0 | 0 | 0 | Hook rewrite authority remains centralized; a small helper keeps the user-scope deploy-root decision shared across paths. |
| CLI Logging Expert | 0 | 0 | 0 | No user-facing CLI output changed; the debug log uses lazy formatting and the Copilot comment is accurate. |
| DevX UX Expert | 0 | 0 | 0 | Internal plumbing preserves project-scope portability while making user-scope Copilot hooks work from any cwd. |
| Supply Chain Security Expert | 0 | 0 | 0 | Path safety remains on the existing rewrite path; no new execution or credential surface is introduced. |
| OSS Growth Hacker | 0 | 0 | 0 | Contributor-reported Copilot hook fix is now changeloged with clear user-facing framing. |
| Doc Writer | 0 | 0 | 0 | No docs drift; the folded changelog entry covers the user-visible bug fix. |
| Test Coverage Expert | 0 | 0 | 0 | Regression traps cover user-scope absolute Copilot paths and project-scope relative portability, with mutation-break evidence. |
B = highest-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.
Architecture
classDiagram
class HookIntegrator {
+integrate_hooks_for_target()
+integrate_package_hooks()
-_deploy_root_for_hook_rewrite()
-_rewrite_hooks_data()
}
class HookIntegrationResult
HookIntegrator ..> HookIntegrationResult : returns
flowchart TD
A[integrate_hooks_for_target] --> B{Copilot target}
B -->|yes| C[integrate_package_hooks]
B -->|no| D[merged hook path]
C --> E[_deploy_root_for_hook_rewrite]
D --> E
E --> F[_rewrite_hooks_data]
F --> G[write native hook config]
Recommendation
All signals green, zero open findings, test coverage is mutation-verified. Merge at will.
Folded in this run
- (panel) Centralized the user-scope hook deploy-root decision so Copilot and merged-hook paths cannot drift -- resolved in
3b2bf10a2ea700853209e9928b21a05d747236b9. - (panel) Added the missing CHANGELOG entry for the Copilot user-scope hook fix -- resolved in
3b2bf10a2ea700853209e9928b21a05d747236b9.
Regression-trap evidence (mutation-break gate)
tests/unit/integration/test_hook_integrator.py::TestScopeResolvedHookDeployment::test_copilot_user_scope_writes_absolute_hook_paths-- deletedHookIntegrator._deploy_root_for_hook_rewriteguard; test FAILED as expected; guard restored.
Lint contract
uv run --extra dev ruff check src/ tests/ and
uv run --extra dev ruff format --check src/ tests/ both silent. Full local push gate also passed: pylint R0801, scripts/lint-auth-signals.sh, and scripts/lint-architecture-boundaries.sh.
CI
gh pr checks 2236 --repo microsoft/apm reports all 14 checks passing on 3b2bf10a2ea700853209e9928b21a05d747236b9 (after 0 CI fix iteration(s)).
Mergeability status
Captured from gh pr view 2236 --repo microsoft/apm --json mergeable,mergeStateStatus,statusCheckRollup immediately after the last push of this run.
| PR | head SHA | CEO stance | iters | folds | defers | Copilot rounds | CI | mergeable | mergeStateStatus | notes |
|---|---|---|---|---|---|---|---|---|---|---|
| #2236 | 3b2bf10 |
ship_now | 1 | 2 | 0 | 2 | green | MERGEABLE | BLOCKED | pending required review |
Convergence
1 outer iteration(s); 2 Copilot round(s). Final panel stance: ship_now.
Ready for maintainer review.
Full per-persona findings
No active panelist findings remained after the folded helper and changelog follow-ups.
Auth Expert -- inactive: changed files are hook integration, changelog, and hook-integrator tests; no token, credential, host, or AuthResolver behavior is touched.
Performance Expert -- inactive: changed files add a constant-time bool/path helper and tests; no dependency download, cache, install hot path, growing loop, or I/O complexity surface is touched.
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
Copilot user-scope hook installs now thread the explicit user_scope signal into the existing deploy_root rewrite path, so commands in .copilot hook JSON point at absolute installed script paths and resolve from any cwd. Project-scope Copilot hooks still keep repo-relative commands, preserving the #1394 portability constraint. How to test: uv run --extra dev pytest tests/unit/integration/test_hook_integrator.py -q; uv run --extra dev ruff check src/ tests/; uv run --extra dev ruff format --check src/ tests/. Mutation gate: removing the Copilot deploy_root threading makes test_copilot_user_scope_writes_absolute_hook_paths fail. closes #2232