Skip to content

Commit 0b7bd06

Browse files
feat(ci): promote prune-hook reconciliation [claude] to lifecycle_smoke
Adds pytest.mark.lifecycle_smoke to only the `claude` parametrization of test_prune_removes_merged_hook_entries_and_sidecar (deliberately excluding the `cursor` sibling), now that #2249's prune-hook fix has merged. The existing marker-driven `-m lifecycle_smoke tests/integration` command in ci.yml auto-picks up the newly-marked test with zero workflow edit -- confirmed via `git diff` showing no change to the lifecycle-smoke job section. Family grows from 12 to 13 tests, all passing (13 passed, ~16.5-17.9s local across 3 repeated runs -- comparable to the prior 12-test baseline of ~17.7-18.4s). Failure-injection re-proof: reverting #2249's production fix (prune.py, hook_integrator.py, uninstall/engine.py, apm_package.py) to pre-fix content causes exactly `[claude]` to fail under `-m lifecycle_smoke` selection (12 passed, 1 failed), confirming the gate is load-bearing for this regression; restored cleanly afterward (working tree verified clean pre/post). Also merges origin/main (additive merge commit, no rebase/force-push) to bring in #2249 plus intervening #2237 (Windows CI fix) and #2246 (lockfile-property tests). Resolved one real conflict in merge-gate.yml's EXPECTED_CHECKS where main's #2237 follow-on independently added a new required "Windows Compatibility Gate" check to the same ternary our branch extended with "Lifecycle Smoke (Linux)" -- both required-check names now coexist in both event branches. Docs (integration-testing.md, CHANGELOG.md) updated to enumerate the 6th target and prune's Consume/Produce/Govern coverage. No change needed to test_ci_topology.py's semantic assertions (count-agnostic by design) or ci.yml (marker-driven auto-pickup, zero edit). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 75891045-fa50-40b7-9354-b4649195f724
1 parent 2f4d2b2 commit 0b7bd06

3 files changed

Lines changed: 13 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Pull requests now run a ~65-70s hermetic `Lifecycle Smoke (Linux)` check,
1313
selected declaratively via a registered `lifecycle_smoke` pytest marker,
14-
that validates core install, lock-convergence, and policy-enforcement
15-
contracts at PR time instead of only in the merge queue -- no network,
16-
credentials, or built binary required (#2247).
14+
that validates core install, lock-convergence, policy-enforcement, and
15+
prune-time hook-reconciliation contracts at PR time instead of only in
16+
the merge queue -- no network, credentials, or built binary required
17+
(#2247).
1718
- Object-form Git dependencies now reject unsupported keys instead of silently
1819
ignoring them; use `ref` rather than `version`, and omit inert `name` fields
1920
from `git: parent`. CI audit also rejects full-SHA pins whose

docs/src/content/docs/contributing/integration-testing.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ APM uses a tiered approach to integration testing:
3434
- **Trigger**: merge queue integration workflow, plus tag, schedule, and manual promotion runs
3535

3636
### 3. **Lifecycle Smoke** (PR-time required check)
37-
- **Location**: selected declaratively via the registered `lifecycle_smoke` pytest marker, applied to all of `tests/integration/test_install_content_hash_roundtrip.py`, `test_policy_pinned_constraint_e2e.py`, `test_virtual_claude_skill_lock_convergence.py`, `test_virtual_package_lifecycle_matrix.py` (module-level), and to only `test_architecture_authorities.py::test_ado_lock_coordinates_have_single_owner` (function-level -- the file's other tests are not part of this family)
38-
- **Purpose**: Promote the smallest stable, hermetic slice of the real Consume/Produce/Govern lifecycle contracts onto the PR-time critical path, so a regression in install/lock/audit convergence or ADO lock-coordinate handling fails the PR instead of only surfacing once a change reaches the merge queue
39-
- **Scope**: install content-hash roundtrip, policy pinned-constraint enforcement, virtual-skill lock convergence, the virtual/manifestless lifecycle matrix, and the ADO lock-coordinate ownership guard -- no built binary, no network, no credentials
37+
- **Location**: selected declaratively via the registered `lifecycle_smoke` pytest marker, applied to all of `tests/integration/test_install_content_hash_roundtrip.py`, `test_policy_pinned_constraint_e2e.py`, `test_virtual_claude_skill_lock_convergence.py`, `test_virtual_package_lifecycle_matrix.py` (module-level), to only `test_architecture_authorities.py::test_ado_lock_coordinates_have_single_owner` (function-level -- the file's other tests are not part of this family), and to only the `[claude]` parametrization of `test_prune_hook_reconciliation_e2e.py::test_prune_removes_merged_hook_entries_and_sidecar` (the sibling `[cursor]` parametrization is deliberately excluded)
38+
- **Purpose**: Promote the smallest stable, hermetic slice of the real Consume/Produce/Govern lifecycle contracts onto the PR-time critical path, so a regression in install/lock/audit convergence, ADO lock-coordinate handling, or prune-time hook reconciliation fails the PR instead of only surfacing once a change reaches the merge queue
39+
- **Scope**: install content-hash roundtrip, policy pinned-constraint enforcement, virtual-skill lock convergence, the virtual/manifestless lifecycle matrix, the ADO lock-coordinate ownership guard, and prune's merged-hook/sidecar reconciliation -- no built binary, no network, no credentials
4040
- **Duration**: ~65-70s job wall time (hard 3-minute timeout)
4141
- **Trigger**: every pull request and merge queue run (`ci.yml`'s `lifecycle-smoke` job, required via `merge-gate.yml`)
4242
- **Selection mechanism**: `pytest --strict-markers -m lifecycle_smoke tests/integration` -- declarative, not an explicit file/node-id list. If every `@pytest.mark.lifecycle_smoke` mark were ever removed, the marker family collects zero tests and pytest exits code 5 ("no tests collected"), failing the job loudly rather than silently shrinking. The marker is registered in `pyproject.toml`'s `[tool.pytest.ini_options]` markers list; `--strict-markers` rejects any typo'd or unregistered mark used as a decorator.
@@ -350,6 +350,7 @@ Promotion integration tests run on:
350350
- Policy pinned-constraint enforcement (Govern contract)
351351
- The virtual/manifestless lifecycle matrix: install, lock, frozen-install, update, and audit stay consistent (the direct #2240 regression)
352352
- The ADO lock-coordinate single-owner guard (the direct #2226 regression)
353+
- Prune's merged-hook and ownership-sidecar reconciliation for the `claude` target (the direct #2249 regression -- an orphaned package's merged hook entries and sidecar markers must be cleaned up, not left pointing at deleted scripts)
353354
- No network, no credentials, no built binary required for any of the above
354355

355356
## Benefits

tests/integration/test_prune_hook_reconciliation_e2e.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,11 @@ def _pre_tool_use_commands(settings_path: Path) -> list[str]:
220220
return commands
221221

222222

223-
@pytest.mark.parametrize("target", ["claude", "cursor"], ids=["claude", "cursor"])
223+
@pytest.mark.parametrize(
224+
"target",
225+
[pytest.param("claude", marks=pytest.mark.lifecycle_smoke), "cursor"],
226+
ids=["claude", "cursor"],
227+
)
224228
def test_prune_removes_merged_hook_entries_and_sidecar(
225229
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, target: str
226230
) -> None:

0 commit comments

Comments
 (0)