Skip to content

Hook backlog (1c-b) both-layout install tests - #1332

Merged
mergify[bot] merged 3 commits into
mainfrom
plan/hook-backlog-1c-b-both-layout-install-tests
Oct 12, 2026
Merged

mergify[bot] merged 3 commits into
mainfrom
plan/hook-backlog-1c-b-both-layout-install-tests

Conversation

@EdbertChan

@EdbertChan EdbertChan commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

The install checks now accept both supported hook layouts: one entry per hook or one shared entry per event.

The checks expand the shared form before comparing each hook, so both layouts keep the same per-hook rules.

Review Claim

The install and wrapping checks cover both layouts, and the shared form stays off unless both full-suite modes pass.

Review Lane

behavior

Review Unit

engine-runtime

Safety Invariant

If either full-suite run fails, the dispatcher default stays off. Per-hook guarantees remain checked in the dispatcher layout.

Slice Rationale

This slice adds the install-layout proof requested by the dispatcher-defect workflow without changing production hook behavior.

Non-goals

  • Do not change hook installation behavior.
  • Do not change dispatcher routing or the dispatcher default.
  • Do not add new hooks or alter existing per-hook guarantees.

Measured

none: This slice adds proof for install layouts and has no product metric.

Test Plan

Test Plan
  • python3 engine/skills/make-pr/scripts/preflight.py --base origin/main --commit-only --dry-run
  • ruff check --select E9,F engine/hooks/_runner/tests/test_wrap_installed.py tests/test_install.py
  • python3 -m unittest tests.test_install.TestHookDispatcherFlagInstall -v
  • python3 -m unittest test_wrap_installed.DispatcherFlag -v

Revert Plan

Revert Plan
  • Safe to revert? Yes.
  • Revert command: git revert <sha>
  • Post-revert steps: Run the install and wrapping test suites.
  • Data migration? No.

Note

Low Risk
Test-only changes to install and wrap_installed suites; no production hook install or routing logic is modified.

Overview
Install and wrap tests now treat both hook config shapes as equivalent for assertions: one command per hook (dispatcher off) versus one _runner/dispatch.py entry per event (dispatcher on).

tests/test_install.py adds load_config(), which reads Claude/Cursor/Codex hook JSON and, when it sees dispatch.py, expands events back to per-hook groups via dispatch.load_event_hooks and the same runner command formatting as wrap_installed. Most install wiring checks switch from raw json.load to load_config, so per-hook matchers and script paths are validated regardless of layout. TestHookDispatcherFlagInstall.test_default_is_off_and_byte_identical_to_no_flag_at_all now strips CATSTACK_HOOK_DISPATCHER from the environment and compares a default install to one that explicitly sets the flag to whatever flags.hook_dispatcher_on resolves—so suite-wide flag leakage cannot fake a pass.

test_wrap_installed.py pins CATSTACK_HOOK_DISPATCHER=0 in the shared fixture so non-dispatcher wrap tests stay on the per-hook baseline unless DispatcherFlag turns the flag on.

No production install or dispatcher behavior changes—test-only proof that both layouts satisfy the same per-hook guarantees.

Reviewed by Cursor Bugbot for commit 0e6a50c. Bugbot is set up for automated code reviews on this repo. Configure here.

CI Bot and others added 3 commits October 11, 2026 14:27
tests/test_install.py and engine/hooks/_runner/tests/test_wrap_installed.py
asserted one settings entry per hook, so every per-hook guarantee they check
failed once CATSTACK_HOOK_DISPATCHER (#1122) collapsed an event to a single
_runner/dispatch.py entry: 70 failures and 1 error on #1122's head, all in
these two files.

load_config() in tests/test_install.py now reads an installed config and
expands a collapsed event back into one entry per hook, resolving each hook's
registration the way dispatch.py itself does (dispatch.load_event_hooks: the
cursor registry, or the hook's own manifest for claude and codex). Each
assertion therefore sees the identical shape in both layouts and keeps
checking the same guarantee -- right event, right harness, Stop mirrored to
SubagentStop or opted out, dead entries pruned, non-catstack entries
untouched. test_wrap_installed.py's fixture pins the flag off, since it
asserts the settings bytes install writes rather than a hook's registration.

#1122's own test_default_is_off_and_byte_identical_to_no_flag_at_all now
compares the default install against an install that sets the flag to
whatever flags.py resolves as the default, and clears the key from its own
environment first, so the flag-on run of the full suite cannot leak into the
"default" side of the comparison.

The CATSTACK_HOOK_DISPATCHER default is left off. Flipping it on is gated on
both full-suite runs passing, and the source branch
plan/hook-backlog-1c-install-tests-accept-the-one-entry-per-event-layout-default-on-only-if-both-suites-pass
never changed engine/hooks/_flags/flags.py, so that gate was not met there
and this commit does not claim it.

Cherry-picked from 6330abf on that branch.
The branch's two other content commits (engine/hooks/_runner/doctor.py,
scripts/test/run_skill_scenarios.py) are unrelated to this claim and are
left behind.
…ew claim: tests.test_install and test_wrap_installed accept both install layouts (one entry per hook with CATSTACK_HOOK_DISPATCHER off, one dispatcher entry per event with it on), and the flag defaults to on only if bash scripts/test/run_all_tests.sh passes with the flag on and off.

Review lane: behavior
Safety invariant: If either suite run fails, the default stays off. Per-hook guarantees stay checked in the dispatcher layout.
Files: tests/test_install.py, tests/test_wrap_installed.py
Change types: test
Acceptance criteria: This workflow publishes one pull request for the install-layout claim only.

Exit code: 0
Invoker-Finalize-Id: f459f9c9-a623-4fd7-9708-21cc3ae4cbda
…s/g0.t0.a-a464d403f-4908b6a4 — Review claim: tests.test_install and test_wrap_installed accept both install layouts (one entry per hook with CATSTACK_HOOK_DISPATCHER off, one dispatcher entry per event with it on), and the flag defaults to on only if bash scripts/test/run_all_tests.sh passes with the flag on and off.

Review lane: behavior
Safety invariant: If either suite run fails, the default stays off. Per-hook guarantees stay checked in the dispatcher layout.
Files: tests/test_install.py, tests/test_wrap_installed.py
Change types: test
Acceptance criteria: This workflow publishes one pull request for the install-layout claim only.
@cursor

cursor Bot commented Oct 11, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 629059e5-3f90-49e5-80fb-cf0a0e81cd61)

@mergify

mergify Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Queued — the merge queue status continues in this comment ↓.

@EdbertChan

Copy link
Copy Markdown
Owner Author

@Mergifyio queue

@mergify

mergify Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 1 hour 1 minute 19 seconds in the queue, including 1 hour 20 seconds running CI.

Reason

The merge conditions cannot be satisfied: the checks did not pass within the checks timeout of 1 hour

These checks were still running:

  • test

Failing checks:

Hint

You may have to fix your CI before adding the pull request to the queue again.

If you update this pull request, to fix the CI, it will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue instead, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

Waiting for
  • check-success = test
All conditions
  • check-success = test
  • check-success = lint
  • check-success = validate

Requeued — the merge queue status continues in this comment ↓.

@EdbertChan

Copy link
Copy Markdown
Owner Author

@Mergifyio queue

@mergify

mergify Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 2 hours 57 minutes 4 seconds in the queue, including 2 hours 54 seconds running CI.

Reason

The merge conditions cannot be satisfied: the checks did not pass within the checks timeout of 1 hour

These checks were still running:

  • test

Failing checks:

Hint

You may have to fix your CI before adding the pull request to the queue again.

If you update this pull request, to fix the CI, it will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue instead, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

Waiting for
  • check-success = test
All conditions
  • check-success = test
  • check-success = lint
  • check-success = validate

Requeued — the merge queue status continues in this comment ↓.

@EdbertChan

Copy link
Copy Markdown
Owner Author

@Mergifyio queue

@mergify

mergify Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 2 hours 49 minutes 48 seconds in the queue, including 1 hour 41 minutes 21 seconds running CI.

Required conditions to merge
  • check-success = lint
  • check-success = test
  • check-success = validate

@mergify mergify Bot added the queued label Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant