Skip to content

fix: absolutize Copilot user-scope hook commands (closes #2232)#2236

Open
danielmeppiel wants to merge 3 commits into
mainfrom
fix/2232-copilot-user-scope-hook-abs-path
Open

fix: absolutize Copilot user-scope hook commands (closes #2232)#2236
danielmeppiel wants to merge 3 commits into
mainfrom
fix/2232-copilot-user-scope-hook-abs-path

Conversation

@danielmeppiel

Copy link
Copy Markdown
Collaborator

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

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>
Copilot AI review requested due to automatic review settings July 16, 2026 00:13

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.

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_scope into the Copilot hook integration path and pass a deploy_root into 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

Comment on lines 1143 to 1150
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>
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

APM Review Panel: ship_now

Clean, well-tested fix threading user_scope into Copilot hook integration; no findings remain.

cc @sergio-sisternes-epam -- a fresh advisory pass is ready for your review.

All active panelists returned clean sheets. The fix is narrow and well-scoped: it threads an existing user_scope flag into the Copilot integrate_package_hooks path, reuses the canonical _rewrite_hooks_data function for deploy-root rewriting, and adds only a guarded debug breadcrumb. Architecture review confirmed no new authority split, supply-chain review confirmed no new attack surface, and test review confirmed the regression trap with mutation-break evidence.

Aligned with: portable-by-manifest: project-scope Copilot commands remain repo-relative; multi-harness-multi-host: Copilot now has user-scope parity with the existing deploy-root rewrite path; pragmatic-as-npm: user-scope hooks resolve from any cwd without manual path fixups.

Panel summary

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 -- deleted deploy_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>
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

APM Review Panel: ship_now

Fix Copilot user-scope hook commands to write absolute installed script paths regardless of cwd, preserving project-scope repo-relative portability.

cc @danielmeppiel @sergio-sisternes-epam -- a fresh advisory pass is ready for your review.

All panelists converged on a clean signal: the fix is well-scoped, the deploy-root decision is centralized in a single helper (HookIntegrator._deploy_root_for_hook_rewrite), and the dual-scope invariant (user-scope absolute, project-scope relative) is enforced by tests. The mutation-break confirms the guard is load-bearing -- removing it causes test_copilot_user_scope_writes_absolute_hook_paths to fail, which is exactly the regression trap we need.

Strategically this unblocks the Copilot harness integration story without compromising the #1394 portability contract for project-scope hooks. The change is additive to existing behavior (project-scope paths unchanged), so community impact is zero breakage. CHANGELOG entry is present and no user migration is required.

Aligned with: Project-scope hooks remain repo-relative per #1394; user-scope hooks resolve deterministically from any working directory; Copilot harness behavior now matches the multi-harness hook promise; no extra user configuration is needed.

Panel summary

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
Loading
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]
Loading

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 -- deleted HookIntegrator._deploy_root_for_hook_rewrite guard; 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.

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.

[BUG] Copilot user-scope hook commands are repo-relative, unresolvable from any cwd ≠ $HOME

2 participants