Commit ccdafc4
fix(hooks): stabilize root .apm hook source-ids across renames/worktrees (supersedes #1330, closes #1329) (#1392)
* fix: stabilize root hook source ids
* test: remove project-specific hook fixture names
* fix(hooks): bound dependency hook source discovery
* fix(hooks): reject symlinked dependency markers
* test(hooks): subprocess-tier coverage + debug logs for #1329
- Add tests/integration/test_hook_root_source_drift_e2e.py: subprocess
test that seeds stale .claude/settings.json + apm-hooks.json sidecar
with old source-id, runs apm install, asserts entries heal to
_local/<manifest-name> and user-owned hook entry survives.
- Add two _log.debug lines in hook_integrator.py:
- manifest-parse fallback in _get_root_local_package_name
- heal count when stale same-content merged entries are removed
- Update affected unit tests to read _apm_source from Claude sidecar
(post-#1359 schema-strict layout).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(hooks): act on review-panel recommendations for #1329 follow-up
Addresses the top recommended-tier follow-ups from the APM review panel
on #1392 (microsoft/apm#1392 (comment)).
In-PR:
* CHANGELOG: add [Unreleased] > Fixed entry with user-outcome framing,
enumerating all five affected harnesses (Claude / Codex / Cursor /
Gemini / Windsurf) and the explicit parenthetical that Copilot is
unaffected because its hooks live in per-file namespaces rather than
a shared merged config. (doc-writer + oss-growth-hacker convergence)
* Integration coverage: parametrize the e2e heal regression test across
all five merged-hook harnesses instead of Claude only. Uses an
install-then-corrupt-then-reinstall pattern so the seeded entries
match each target's on-disk shape (sidecar for Claude; in-file
_apm_source for Codex / Cursor / Gemini / Windsurf), closing the
silent-drift gap the test-coverage-expert flagged as highest-signal.
* _safe_source_name hardening: collapse runs of 2+ dots to a single
dot before stripping edges. No traversal risk today (the marker is
JSON metadata), but guards any future caller that passes the name
into a Path join. (supply-chain-security recommendation.)
* Nits: include exception message (not just class name) in the
manifest-unreadable debug log; replace O(n*m) list membership in
the heal counter with an id-set; document the project_root parameter
on _get_package_name; promote _get_root_local_package_name,
_get_hook_source_marker, and _should_remove_prior_merged_entry to
@staticmethod (they touch no instance state).
The DependencySourceScanner extraction the python-architect proposed is
explicitly out of scope for this PR per the panel's own guidance
("does not need to land in this PR but should not slip past the next
meaningful touch to hook_integrator.py").
Validation:
* uv run --extra dev ruff check src/ tests/ -- clean
* uv run --extra dev ruff format --check src/ tests/ -- clean
* uv run --extra dev pytest tests/unit/integration/test_hook_integrator.py -- 156 passed
* uv run --extra dev pytest tests/integration/test_hook_root_source_drift_e2e.py -- 5 passed (claude, codex, cursor, gemini, windsurf)
* uv run --extra dev pytest tests/unit/integration/ tests/integration/test_hook_root_source_drift_e2e.py -- 1364 passed
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(ci): resolve R0801 duplication; expand lint contract to all 7 CI gates
CI lint was failing the PR with R0801 (pylint duplicate-code). The
duplication was introduced when main was merged into this branch: the
recent MCP-client work on main left an identical
`_select_best_package` method in both CodexClientAdapter and
CopilotClientAdapter, each ~22 lines long. pylint --fail-on=R0801
catches this at the merge commit CI tests, so the PR cannot pass
until the dup is resolved.
Fix: hoist `_select_best_package` to the `MCPClientAdapter` base class
(alongside the existing `_infer_registry_name` it already calls) and
delete the duplicates from codex.py and copilot.py. Both call sites
use `self._select_best_package(packages)`, so inheritance resolves
the lookup transparently. Mirrors the in-flight refactor on
`daf99e0f refactor(adapters): hoist _select_remote_with_url and
_select_best_package to base` (not yet on main).
Also: expand the canonical lint contract at
`.apm/instructions/linting.instructions.md` to cover all seven CI
Lint steps (ruff check, ruff format, YAML I/O guard, file-length
guard, no raw `str(relative_to)`, pylint R0801, auth-signal lint)
instead of only ruff. Adds the full `uv run ... && ...` mirror chain
and calls out the merge-commit semantics (CI tests HEAD merged with
main, so duplication on main can fail a clean PR diff). Apm compile
flows the change into the generated AGENTS.md (gitignored at root)
and into `.github/copilot-instructions.md`.
Validation:
* uv run --extra dev ruff check src/ tests/ -- clean
* uv run --extra dev ruff format --check src/ tests/ -- clean
* uv run --extra dev python -m pylint --disable=all --enable=R0801 \
--min-similarity-lines=10 --fail-on=R0801 src/apm_cli/ -- 10.00/10, exit 0
* bash scripts/lint-auth-signals.sh -- clean
* uv run --extra dev pytest tests/unit/integration/test_hook_integrator.py \
tests/integration/test_hook_root_source_drift_e2e.py -- 161 passed
Pre-existing main-side test failures in
`tests/unit/test_codex_adapter_compatibility.py` (introduced by
#1262 / #1277 on main and tracked by the in-flight
`32991fb6 fix(adapters): restore _resolve_env_placeholders shim and
reject SSE remotes in tests` branch) are out of scope for this PR
and will resolve when that follow-up lands on main.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(adapters): restore _resolve_env_placeholders shim and reject SSE remotes in tests
PR #1277 removed the _resolve_env_placeholders legacy wrapper from
adapters and softened Codex remote-server rejection (https URLs are
now accepted as streamable-http), but did not update the phase-3
and compatibility test suites. The result was 6 pre-existing test
failures on Build & Test that this PR's Windows-targeted changes
inherited.
- Restore _resolve_env_placeholders on MCPClientAdapter as a thin
delegate to _resolve_variable_placeholders (empty runtime_vars).
External callers and 4 test cases rely on the legacy name.
- Update test_returns_false_for_remote_only_server in both codex
test files to use an SSE-transport remote, which is still the
rejection contract post-#1277 (streamable-http is now accepted).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Koichi Takahashi <tkou15.hi@gmail.com>
Co-authored-by: Koichi Takahashi <work@k1t.space>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Daniel Meppiel <copilot-rework@github.com>1 parent 9b36381 commit ccdafc4
11 files changed
Lines changed: 1202 additions & 77 deletions
File tree
- .apm/instructions
- .github
- src/apm_cli
- adapters/client
- integration
- tests
- integration
- unit
- integration
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | | - | |
16 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
17 | 26 | | |
18 | | - | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
19 | 31 | | |
20 | 32 | | |
21 | 33 | | |
22 | 34 | | |
23 | 35 | | |
24 | | - | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
25 | 46 | | |
26 | | - | |
| 47 | + | |
27 | 48 | | |
28 | 49 | | |
29 | 50 | | |
| |||
36 | 57 | | |
37 | 58 | | |
38 | 59 | | |
| 60 | + | |
| 61 | + | |
39 | 62 | | |
40 | 63 | | |
41 | 64 | | |
42 | 65 | | |
43 | 66 | | |
44 | 67 | | |
45 | | - | |
46 | | - | |
| 68 | + | |
| 69 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
| 14 | + | |
15 | 15 | | |
16 | | - | |
17 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
18 | 27 | | |
19 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
20 | 32 | | |
21 | 33 | | |
22 | 34 | | |
23 | 35 | | |
24 | 36 | | |
25 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
26 | 47 | | |
27 | | - | |
| 48 | + | |
28 | 49 | | |
29 | 50 | | |
30 | 51 | | |
| |||
37 | 58 | | |
38 | 59 | | |
39 | 60 | | |
| 61 | + | |
| 62 | + | |
40 | 63 | | |
41 | 64 | | |
42 | 65 | | |
43 | 66 | | |
44 | 67 | | |
45 | 68 | | |
46 | | - | |
47 | | - | |
| 69 | + | |
| 70 | + | |
48 | 71 | | |
49 | 72 | | |
50 | 73 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
14 | 18 | | |
15 | 19 | | |
16 | 20 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
248 | 248 | | |
249 | 249 | | |
250 | 250 | | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
251 | 275 | | |
252 | 276 | | |
253 | 277 | | |
| |||
542 | 566 | | |
543 | 567 | | |
544 | 568 | | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
545 | 579 | | |
546 | 580 | | |
547 | 581 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
548 | 548 | | |
549 | 549 | | |
550 | 550 | | |
551 | | - | |
552 | | - | |
553 | | - | |
554 | | - | |
555 | | - | |
556 | | - | |
557 | | - | |
558 | | - | |
559 | | - | |
560 | | - | |
561 | | - | |
562 | | - | |
563 | | - | |
564 | | - | |
565 | | - | |
566 | | - | |
567 | | - | |
568 | | - | |
569 | | - | |
570 | | - | |
571 | | - | |
572 | | - | |
573 | | - | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1007 | 1007 | | |
1008 | 1008 | | |
1009 | 1009 | | |
1010 | | - | |
1011 | | - | |
1012 | | - | |
1013 | | - | |
1014 | | - | |
1015 | | - | |
1016 | | - | |
1017 | | - | |
1018 | | - | |
1019 | | - | |
1020 | | - | |
1021 | | - | |
1022 | | - | |
1023 | | - | |
1024 | | - | |
1025 | | - | |
1026 | | - | |
1027 | | - | |
1028 | | - | |
1029 | | - | |
1030 | | - | |
1031 | | - | |
1032 | | - | |
1033 | 1010 | | |
1034 | 1011 | | |
1035 | 1012 | | |
| |||
0 commit comments