Skip to content

[Hook architecture](17) Put the diu-stop hook onto the shared hook code - #732

Merged
mergify[bot] merged 23 commits into
mainfrom
plan/hook-architecture-17-put-the-diu-stop-hook-onto-the-shared-hook-code
Sep 17, 2026
Merged

mergify[bot] merged 23 commits into
mainfrom
plan/hook-architecture-17-put-the-diu-stop-hook-onto-the-shared-hook-code

Conversation

@EdbertChan

@EdbertChan EdbertChan commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Summary

The hook that checks reply length and proof now runs through the shared hook code. It still stops the same replies: too long, or claims with no proof.

Before this change, each of its scripts read its input, picked its own response, and printed it. The stop-or-warn choice was fixed inside the hook.

Now each check returns a list of findings. The shared runner picks stop, warn, or off from the hook registry and writes one event row per finding.

A setting can now turn its stop into a warning. No hook code has to change for that.

Review Claim

The reply-length hook sends its findings to the shared hook code, which applies the registry mode and writes event rows, while the hook still stops replies by default.

Review Lane

behavior

Review Unit

engine-runtime

Safety Invariant

Every case in engine/hooks/diu-stop/tests gives the same stop, warn, or silent result as before. The only new result is the mode override, and the test folder still exits 0.

Slice Rationale

This is part 17 of the hook architecture stack. It moves one hook, so each move can be reviewed alone. The shared runner already landed lower in the stack.

Non-goals

  • No change to what diu-stop looks for: word limit, unproven claims, marker tags, plain words.
  • No change to its default mode, which stays stop.
  • No other hook is changed.
  • Codex has no way to block a reply, so its notify script still only prints a note. It now skips the note when the mode is off and writes event rows.

Architecture

Before

graph TD
    A["Claude Stop event"] --> B["claude_stop_check.main()"]
    B --> C["checks inside main()"]
    C --> D["stderr text + exit 2"]
Loading

After

graph TD
    A["Claude Stop event"] --> B["run_hook('diu-stop', 'claude', detect, 'Stop')"]
    B --> C["detect(event) returns Finding list"]
    C --> D["registry mode: stop, warn, or off"]
    D --> E["stop: stderr + exit 2"]
    D --> F["warn: additionalContext + exit 0"]
    D --> G["events-*.jsonl row per rule_id"]
Loading

Test Plan

Test Plan
  • python3 -m unittest discover -s engine/hooks/diu-stop/testsRan 111 tests in 0.367s / OK
  • python3 scripts/ci/check_hook_test_coverage.py engine/hooks/diu-stopcheck_hook_test_coverage: OK (1 hook(s) checked)
  • bash scripts/pr/scrub-handoff-artifacts.shscrub-handoff-artifacts-ok
  • New tests in tests/test_hooks_sdk_mode.py:
    • test_mode_override_warn_changes_block_to_warning: with CATSTACK_HOOK_MODE_DIU_STOP=warn, a 200-word reply exits 0 and warns.
    • test_mode_stop_still_blocks_by_default: with no override, the same reply still exits 2.
    • test_each_finding_writes_one_event_row_with_rule_id: one row with rule id diu-stop.word-limit, mode warn, action warned.
  • Test-only change in tests/test_hooks.py: the old main() calls now allow SystemExit, because run_hook exits on its own.

Revert Plan

Revert Plan
  • Safe to revert? Yes
  • Revert command: git revert <merge-sha>
  • Post-revert steps: None. diu-stop goes back to its own stop logic and ignores the registry mode.
  • Data migration? No. Event rows already written stay on disk and nothing reads them back.

🤖 Generated with Claude Code


Note

Medium Risk
Changes how assistant replies are blocked or warned at turn end (core agent behavior), though detection rules are unchanged and existing tests assert parity except the new mode override.

Overview
diu-stop now routes Claude hooks through the shared run_hook SDK instead of hand-rolled JSON stdin/stdout and sys.exit(2).

claude_stop_check.py and claude_prompt_reminder.py expose a detect(event) that returns Finding objects with stable **rule_id**s (word limit, unverified claims, markers, plain words, prompt reminder). The shared runner applies registry stop / warn / off via CATSTACK_HOOK_MODE_DIU_STOP, renders Claude hook output, and writes one events-*.jsonl row per finding. Default behavior stays block on violation; warn surfaces the same text as additionalContext with exit 0.

Codex codex_notify.py adopts the same finding shape and effective_mode / write_events (still advisory-only on stderr); it skips output when mode is off.

Tests tolerate SystemExit from run_hook, and test_hooks_sdk_mode.py covers warn override, default block, and metrics rows with rule_id.

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

Invoker Bot and others added 22 commits September 16, 2026 07:07
… build-the-lever hook onto the shared hook code.

Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode warn.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/build-the-lever/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The build-the-lever entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Suggests a script when many files are hand-edited. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode warn.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/build-the-lever/claude_posttooluse.py, engine/hooks/build-the-lever/claude_prompt_submit.py, engine/hooks/build-the-lever/codex_posttooluse.py, engine/hooks/build-the-lever/codex_prompt_submit.py, engine/hooks/build-the-lever/cursor_before_submit.py, engine/hooks/build-the-lever/cursor_post_tool_use.py, engine/hooks/build-the-lever/detect.py, engine/hooks/build-the-lever/install_claude_hook.py, engine/hooks/build-the-lever/install_codex_hook.py, engine/hooks/build-the-lever/install_cursor_hook.py, engine/hooks/build-the-lever/state.py, engine/hooks/build-the-lever/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/build-the-lever/claude_posttooluse.py: modify
- engine/hooks/build-the-lever/claude_prompt_submit.py: modify
- engine/hooks/build-the-lever/codex_posttooluse.py: modify
- engine/hooks/build-the-lever/codex_prompt_submit.py: modify
- engine/hooks/build-the-lever/cursor_before_submit.py: modify
- engine/hooks/build-the-lever/cursor_post_tool_use.py: modify
- engine/hooks/build-the-lever/detect.py: modify
- engine/hooks/build-the-lever/install_claude_hook.py: modify
- engine/hooks/build-the-lever/install_codex_hook.py: modify
- engine/hooks/build-the-lever/install_cursor_hook.py: modify
- engine/hooks/build-the-lever/state.py: modify
- engine/hooks/build-the-lever/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/build-the-lever/tests` exits 0.
- With CATSTACK_HOOK_MODE_BUILD_THE_LEVER set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Solution:
  Put the build-the-lever hook onto the shared hook code.
Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode warn.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/build-the-lever/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The build-the-lever entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Suggests a script when many files are hand-edited. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode warn.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/build-the-lever/claude_posttooluse.py, engine/hooks/build-the-lever/claude_prompt_submit.py, engine/hooks/build-the-lever/codex_posttooluse.py, engine/hooks/build-the-lever/codex_prompt_submit.py, engine/hooks/build-the-lever/cursor_before_submit.py, engine/hooks/build-the-lever/cursor_post_tool_use.py, engine/hooks/build-the-lever/detect.py, engine/hooks/build-the-lever/install_claude_hook.py, engine/hooks/build-the-lever/install_codex_hook.py, engine/hooks/build-the-lever/install_cursor_hook.py, engine/hooks/build-the-lever/state.py, engine/hooks/build-the-lever/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/build-the-lever/claude_posttooluse.py: modify
- engine/hooks/build-the-lever/claude_prompt_submit.py: modify
- engine/hooks/build-the-lever/codex_posttooluse.py: modify
- engine/hooks/build-the-lever/codex_prompt_submit.py: modify
- engine/hooks/build-the-lever/cursor_before_submit.py: modify
- engine/hooks/build-the-lever/cursor_post_tool_use.py: modify
- engine/hooks/build-the-lever/detect.py: modify
- engine/hooks/build-the-lever/install_claude_hook.py: modify
- engine/hooks/build-the-lever/install_codex_hook.py: modify
- engine/hooks/build-the-lever/install_cursor_hook.py: modify
- engine/hooks/build-the-lever/state.py: modify
- engine/hooks/build-the-lever/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/build-the-lever/tests` exits 0.
- With CATSTACK_HOOK_MODE_BUILD_THE_LEVER set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Invoker-Finalize-Id: 35d0555b-3f55-47f9-9e41-97f12e84dc55
…terministic proof for put the build-the-lever hook onto the shared hook code.

Review claim: The proof exits 0 only when put the build-the-lever hook onto the shared hook code holds.
Review lane: proof
Safety invariant: Proof only; it changes no product behavior.
Effectiveness measurement: The exit status of `python3 -m unittest discover -s engine/hooks/build-the-lever/tests` is the signal for this slice.
Slice rationale: One proof unit for this workflow.
Architectural effect: None; verification only.
Goal: Prove put the build-the-lever hook onto the shared hook code with one deterministic run.
Motivation: Each workflow carries its own proof so a reviewer can trust the slice alone.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Execute the proof as a terminal gate.
Non-goals: No product edits here.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 3fe2349d-7d5a-4cf2-a6ab-f4c370ef2d0f
…only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 70147de4-ee65-46de-90da-48ab84cce9d0
…ae3e57046-efa4e452 — Terminal read-only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active
…e cat-mode-default hook onto the shared hook code.

Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode warn.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/cat-mode-default/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The cat-mode-default entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Applies the user's working style each turn. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode warn.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/cat-mode-default/claude_pretooluse_agent.py, engine/hooks/cat-mode-default/claude_prompt_submit.py, engine/hooks/cat-mode-default/detect.py, engine/hooks/cat-mode-default/install_claude_hook.py, engine/hooks/cat-mode-default/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/cat-mode-default/claude_pretooluse_agent.py: modify
- engine/hooks/cat-mode-default/claude_prompt_submit.py: modify
- engine/hooks/cat-mode-default/detect.py: modify
- engine/hooks/cat-mode-default/install_claude_hook.py: modify
- engine/hooks/cat-mode-default/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/cat-mode-default/tests` exits 0.
- With CATSTACK_HOOK_MODE_CAT_MODE_DEFAULT set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Solution:
  Put the cat-mode-default hook onto the shared hook code.
Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode warn.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/cat-mode-default/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The cat-mode-default entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Applies the user's working style each turn. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode warn.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/cat-mode-default/claude_pretooluse_agent.py, engine/hooks/cat-mode-default/claude_prompt_submit.py, engine/hooks/cat-mode-default/detect.py, engine/hooks/cat-mode-default/install_claude_hook.py, engine/hooks/cat-mode-default/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/cat-mode-default/claude_pretooluse_agent.py: modify
- engine/hooks/cat-mode-default/claude_prompt_submit.py: modify
- engine/hooks/cat-mode-default/detect.py: modify
- engine/hooks/cat-mode-default/install_claude_hook.py: modify
- engine/hooks/cat-mode-default/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/cat-mode-default/tests` exits 0.
- With CATSTACK_HOOK_MODE_CAT_MODE_DEFAULT set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Invoker-Finalize-Id: a0c6917e-a7c5-46f3-a6a1-b370f2d14108
…eterministic proof for put the cat-mode-default hook onto the shared hook code.

Review claim: The proof exits 0 only when put the cat-mode-default hook onto the shared hook code holds.
Review lane: proof
Safety invariant: Proof only; it changes no product behavior.
Effectiveness measurement: The exit status of `python3 -m unittest discover -s engine/hooks/cat-mode-default/tests` is the signal for this slice.
Slice rationale: One proof unit for this workflow.
Architectural effect: None; verification only.
Goal: Prove put the cat-mode-default hook onto the shared hook code with one deterministic run.
Motivation: Each workflow carries its own proof so a reviewer can trust the slice alone.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Execute the proof as a terminal gate.
Non-goals: No product edits here.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 8132f734-9bf7-4d89-8c3c-56bc4b969d79
…only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 74c962cc-f188-4db3-be0c-c3da68c20e9a
…a23c8b9a3-964c6d87 — Terminal read-only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active
… Put the categorical-scope-guard hook onto the shared hook code.

Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/categorical-scope-guard/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The categorical-scope-guard entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Stops a change that covers only part of an all request. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode stop.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/categorical-scope-guard/claude_pretooluse.py, engine/hooks/categorical-scope-guard/detect.py, engine/hooks/categorical-scope-guard/install_claude_hook.py, engine/hooks/categorical-scope-guard/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/categorical-scope-guard/claude_pretooluse.py: modify
- engine/hooks/categorical-scope-guard/detect.py: modify
- engine/hooks/categorical-scope-guard/install_claude_hook.py: modify
- engine/hooks/categorical-scope-guard/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/categorical-scope-guard/tests` exits 0.
- With CATSTACK_HOOK_MODE_CATEGORICAL_SCOPE_GUARD set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Solution:
  Put the categorical-scope-guard hook onto the shared hook code.
Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/categorical-scope-guard/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The categorical-scope-guard entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Stops a change that covers only part of an all request. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode stop.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/categorical-scope-guard/claude_pretooluse.py, engine/hooks/categorical-scope-guard/detect.py, engine/hooks/categorical-scope-guard/install_claude_hook.py, engine/hooks/categorical-scope-guard/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/categorical-scope-guard/claude_pretooluse.py: modify
- engine/hooks/categorical-scope-guard/detect.py: modify
- engine/hooks/categorical-scope-guard/install_claude_hook.py: modify
- engine/hooks/categorical-scope-guard/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/categorical-scope-guard/tests` exits 0.
- With CATSTACK_HOOK_MODE_CATEGORICAL_SCOPE_GUARD set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Invoker-Finalize-Id: 1540cec2-0149-477b-b36f-03c02bb58574
…n the deterministic proof for put the categorical-scope-guard hook onto the shared hook code.

Review claim: The proof exits 0 only when put the categorical-scope-guard hook onto the shared hook code holds.
Review lane: proof
Safety invariant: Proof only; it changes no product behavior.
Effectiveness measurement: The exit status of `python3 -m unittest discover -s engine/hooks/categorical-scope-guard/tests` is the signal for this slice.
Slice rationale: One proof unit for this workflow.
Architectural effect: None; verification only.
Goal: Prove put the categorical-scope-guard hook onto the shared hook code with one deterministic run.
Motivation: Each workflow carries its own proof so a reviewer can trust the slice alone.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Execute the proof as a terminal gate.
Non-goals: No product edits here.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 30fc01e9-dbf4-4302-9c20-a786ccb160ef
…only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 85155944-670a-40b9-a845-1252af44dacd
…ad1e0ee86-5f6e3e25 — Terminal read-only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active
…o-freeze hook onto the shared hook code.

Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/demo-freeze/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The demo-freeze entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Stops edits to what the user is demoing. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode stop.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/demo-freeze/claude_pretooluse_check.py, engine/hooks/demo-freeze/install_claude_hook.py, engine/hooks/demo-freeze/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/demo-freeze/claude_pretooluse_check.py: modify
- engine/hooks/demo-freeze/install_claude_hook.py: modify
- engine/hooks/demo-freeze/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/demo-freeze/tests` exits 0.
- With CATSTACK_HOOK_MODE_DEMO_FREEZE set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Exit code: 1
Invoker-Finalize-Id: 4a3989de-6a6e-4011-9900-c8aa481e9c27
…o-freeze hook onto the shared hook code.

Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/demo-freeze/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The demo-freeze entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Stops edits to what the user is demoing. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode stop.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/demo-freeze/claude_pretooluse_check.py, engine/hooks/demo-freeze/install_claude_hook.py, engine/hooks/demo-freeze/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/demo-freeze/claude_pretooluse_check.py: modify
- engine/hooks/demo-freeze/install_claude_hook.py: modify
- engine/hooks/demo-freeze/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/demo-freeze/tests` exits 0.
- With CATSTACK_HOOK_MODE_DEMO_FREEZE set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Solution:
  Put the demo-freeze hook onto the shared hook code.
Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/demo-freeze/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The demo-freeze entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Stops edits to what the user is demoing. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode stop.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/demo-freeze/claude_pretooluse_check.py, engine/hooks/demo-freeze/install_claude_hook.py, engine/hooks/demo-freeze/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/demo-freeze/claude_pretooluse_check.py: modify
- engine/hooks/demo-freeze/install_claude_hook.py: modify
- engine/hooks/demo-freeze/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/demo-freeze/tests` exits 0.
- With CATSTACK_HOOK_MODE_DEMO_FREEZE set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Invoker-Finalize-Id: publish-approved-fix
…inistic proof for put the demo-freeze hook onto the shared hook code.

Review claim: The proof exits 0 only when put the demo-freeze hook onto the shared hook code holds.
Review lane: proof
Safety invariant: Proof only; it changes no product behavior.
Effectiveness measurement: The exit status of `python3 -m unittest discover -s engine/hooks/demo-freeze/tests` is the signal for this slice.
Slice rationale: One proof unit for this workflow.
Architectural effect: None; verification only.
Goal: Prove put the demo-freeze hook onto the shared hook code with one deterministic run.
Motivation: Each workflow carries its own proof so a reviewer can trust the slice alone.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Execute the proof as a terminal gate.
Non-goals: No product edits here.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: d36e6bb9-501d-4015-bb29-c6ec478f7a78
…only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 58d2877b-64ef-434d-8479-4faf4996f91f
…a2a286034-921bb939 — Terminal read-only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active
…op hook onto the shared hook code.

Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/diu-stop/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The diu-stop entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Stops a reply that is too long or unproven. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode stop.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/diu-stop/claude_prompt_reminder.py, engine/hooks/diu-stop/claude_stop_check.py, engine/hooks/diu-stop/codex_notify.py, engine/hooks/diu-stop/diu_limit.py, engine/hooks/diu-stop/install_claude_hook.py, engine/hooks/diu-stop/install_codex_notify.py, engine/hooks/diu-stop/plain_words.py, engine/hooks/diu-stop/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/diu-stop/claude_prompt_reminder.py: modify
- engine/hooks/diu-stop/claude_stop_check.py: modify
- engine/hooks/diu-stop/codex_notify.py: modify
- engine/hooks/diu-stop/diu_limit.py: modify
- engine/hooks/diu-stop/install_claude_hook.py: modify
- engine/hooks/diu-stop/install_codex_notify.py: modify
- engine/hooks/diu-stop/plain_words.py: modify
- engine/hooks/diu-stop/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/diu-stop/tests` exits 0.
- With CATSTACK_HOOK_MODE_DIU_STOP set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Exit code: 1
Invoker-Finalize-Id: cc582581-b6f8-4f71-8dd9-cf16d79f1628
…op hook onto the shared hook code.

Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/diu-stop/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The diu-stop entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Stops a reply that is too long or unproven. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode stop.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/diu-stop/claude_prompt_reminder.py, engine/hooks/diu-stop/claude_stop_check.py, engine/hooks/diu-stop/codex_notify.py, engine/hooks/diu-stop/diu_limit.py, engine/hooks/diu-stop/install_claude_hook.py, engine/hooks/diu-stop/install_codex_notify.py, engine/hooks/diu-stop/plain_words.py, engine/hooks/diu-stop/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/diu-stop/claude_prompt_reminder.py: modify
- engine/hooks/diu-stop/claude_stop_check.py: modify
- engine/hooks/diu-stop/codex_notify.py: modify
- engine/hooks/diu-stop/diu_limit.py: modify
- engine/hooks/diu-stop/install_claude_hook.py: modify
- engine/hooks/diu-stop/install_codex_notify.py: modify
- engine/hooks/diu-stop/plain_words.py: modify
- engine/hooks/diu-stop/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/diu-stop/tests` exits 0.
- With CATSTACK_HOOK_MODE_DIU_STOP set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Solution:
  Put the diu-stop hook onto the shared hook code.
Review claim: This hook reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review lane: behavior
Safety invariant: The hook gives the same stop, warn, or silent result on every case in its current test folder, except the mode change named in this claim, and its test folder keeps exiting 0.
Effectiveness measurement: `python3 -m unittest discover -s engine/hooks/diu-stop/tests` exits 0, and the new mode-override case fails before this change.
Slice rationale: One hook per workflow, as the user asked, so each migration is reviewed on its own.
Architectural effect: The diu-stop entry scripts become thin calls into the shared runtime; its detection returns findings.
Goal: Stops a reply that is too long or unproven. Keep that behavior while its mode moves into the registry.
Motivation: Mode and output shape live inside each hook today; the shared code makes a mode change a one-line registry edit.
Alternative considerations: Migrating several hooks per workflow was set aside because the user asked for one hook per workflow.
Implementation details: Turn this hook's detection into detect(event) returning Finding objects with stable rule ids, and make each harness entry script call run_hook from engine/hooks/_sdk/runtime.py. It keeps mode stop.
Non-goals: No change to what the hook detects. No other hook changes.
Layer: domain
Feature state: active
Files: engine/hooks/diu-stop/claude_prompt_reminder.py, engine/hooks/diu-stop/claude_stop_check.py, engine/hooks/diu-stop/codex_notify.py, engine/hooks/diu-stop/diu_limit.py, engine/hooks/diu-stop/install_claude_hook.py, engine/hooks/diu-stop/install_codex_notify.py, engine/hooks/diu-stop/plain_words.py, engine/hooks/diu-stop/tests/test_hooks_sdk_mode.py
Change types:
- engine/hooks/diu-stop/claude_prompt_reminder.py: modify
- engine/hooks/diu-stop/claude_stop_check.py: modify
- engine/hooks/diu-stop/codex_notify.py: modify
- engine/hooks/diu-stop/diu_limit.py: modify
- engine/hooks/diu-stop/install_claude_hook.py: modify
- engine/hooks/diu-stop/install_codex_notify.py: modify
- engine/hooks/diu-stop/plain_words.py: modify
- engine/hooks/diu-stop/tests/test_hooks_sdk_mode.py: create
Acceptance criteria:
- `python3 -m unittest discover -s engine/hooks/diu-stop/tests` exits 0.
- With CATSTACK_HOOK_MODE_DIU_STOP set to warn, a case that stops today produces a warning instead, proving the registry mode drives the response.
- Each finding writes one event row with the hook's rule_id.

Invoker-Finalize-Id: publish-approved-fix
…stic proof for put the diu-stop hook onto the shared hook code.

Review claim: The proof exits 0 only when put the diu-stop hook onto the shared hook code holds.
Review lane: proof
Safety invariant: Proof only; it changes no product behavior.
Effectiveness measurement: The exit status of `python3 -m unittest discover -s engine/hooks/diu-stop/tests` is the signal for this slice.
Slice rationale: One proof unit for this workflow.
Architectural effect: None; verification only.
Goal: Prove put the diu-stop hook onto the shared hook code with one deterministic run.
Motivation: Each workflow carries its own proof so a reviewer can trust the slice alone.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Execute the proof as a terminal gate.
Non-goals: No product edits here.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 26d6f94a-7646-4bba-a249-4e63e35f3a4c
…only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: d41f4da8-d2ba-4eec-847c-65460155a619
…a3cf5f094-a7e2b026 — Terminal read-only gate confirming no ephemeral handoff files were left behind.

Review claim: The workflow leaves no ephemeral handoff files in the tree.
Review lane: proof
Safety invariant: Read-only; it never deletes files, alters the index, or commits caller work.
Effectiveness measurement: A non-zero exit when ephemeral handoff files remain is the signal.
Slice rationale: One unit: the hygiene gate.
Architectural effect: None.
Goal: Confirm no ephemeral handoff files remain after every other task finishes.
Motivation: Ephemeral inter-task files leak into the diff and read as part of the change.
Alternative considerations: Manual inspection was set aside as non-deterministic.
Implementation details: Run scripts/scrub-handoff-artifacts.sh in check mode.
Non-goals: No deletion, no index changes, no commits.
Layer: e2e_regression
Feature state: active

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread engine/hooks/diu-stop/claude_prompt_reminder.py
Comment thread engine/hooks/diu-stop/codex_notify.py
Comment thread engine/hooks/diu-stop/tests/test_hooks.py
…e-17-put-the-diu-stop-hook-onto-the-shared-hook-code

Change-Id: I1bb37ed056a591d4d6c16aea704dd388e9322b81

# Conflicts:
#	engine/hooks/_sdk/runtime.py
#	engine/hooks/categorical-scope-guard/detect.py
@EdbertChan
EdbertChan changed the base branch from plan/hook-architecture-16-put-the-demo-freeze-hook-onto-the-shared-hook-code to main September 17, 2026 06:36
@mergify

mergify Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

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

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 281e4f2. Configure here.


import markers # noqa: E402
from finding import Finding # noqa: E402
from runtime import run_hook # noqa: E402

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Installed hooks cannot import shared SDK

High Severity

The new scripts import finding and runtime from a sibling _sdk directory, but install.sh never links _sdk into ~/.claude/hooks or ~/.codex/hooks. After install, each entrypoint looks next to those hook roots, misses the package, and fails on import. The Stop check, prompt reminder, and Codex notify then never run, so long or unproven replies are no longer blocked.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 281e4f2. Configure here.

@EdbertChan

Copy link
Copy Markdown
Owner Author

@Mergifyio queue admin-bypass

@mergify

mergify Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 6 minutes 42 seconds in the queue, including 6 minutes 18 seconds running CI.

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

@mergify mergify Bot added the queued label Sep 17, 2026
@EdbertChan

Copy link
Copy Markdown
Owner Author

Mergify repair stopped: unresolved human review thread PRRT_kwDOT3uYWs6jPQ8G

@mergify
mergify Bot merged commit 2a9208f into main Sep 17, 2026
10 checks passed
@mergify mergify Bot removed the queued label Sep 17, 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