[Hook architecture](15) Put the categorical-scope-guard hook onto the shared hook code - #768
Conversation
An answer already written down costs one read. Add the learned rule and a test that pins it. Change-Id: I8831f9085cdb5fe672f820dbe96186ca5dc74b29 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… shared hook code (#730) * invoker: wf-1789406883560-32/implement-hook-build-the-lever — 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. 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 * invoker: wf-1789406883560-32/verify-hook-build-the-lever — Run the deterministic 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 * invoker: wf-1789406883560-32/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 70147de4-ee65-46de-90da-48ab84cce9d0 * invoker: wf-1789406886887-33/implement-hook-cat-mode-default — 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. 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 * invoker: wf-1789406886887-33/verify-hook-cat-mode-default — Run the deterministic 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 * invoker: wf-1789406886887-33/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 74c962cc-f188-4db3-be0c-c3da68c20e9a * invoker: wf-1789406891093-34/implement-hook-categorical-scope-guard — 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 * invoker: wf-1789406891093-34/verify-hook-categorical-scope-guard — Run 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 * invoker: wf-1789406891093-34/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 85155944-670a-40b9-a845-1252af44dacd * categorical-scope-guard: log the detector failure before returning UNCHECKED check_no_silent_hook_except flagged the broad handler in detect() because it returned a finding without writing the error to stderr. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Change-Id: I10e84179b9915593bd69889b7ebe3ebdaed05060 --------- Co-authored-by: Invoker Bot <invoker@local> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… code (#731) * invoker: wf-1789406883560-32/implement-hook-build-the-lever — 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. 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 * invoker: wf-1789406883560-32/verify-hook-build-the-lever — Run the deterministic 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 * invoker: wf-1789406883560-32/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 70147de4-ee65-46de-90da-48ab84cce9d0 * invoker: wf-1789406886887-33/implement-hook-cat-mode-default — 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. 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 * invoker: wf-1789406886887-33/verify-hook-cat-mode-default — Run the deterministic 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 * invoker: wf-1789406886887-33/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 74c962cc-f188-4db3-be0c-c3da68c20e9a * invoker: wf-1789406891093-34/implement-hook-categorical-scope-guard — 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 * invoker: wf-1789406891093-34/verify-hook-categorical-scope-guard — Run 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 * invoker: wf-1789406891093-34/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 85155944-670a-40b9-a845-1252af44dacd * invoker: wf-1789406894793-35/implement-hook-demo-freeze — 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. Exit code: 1 Invoker-Finalize-Id: 4a3989de-6a6e-4011-9900-c8aa481e9c27 * invoker: wf-1789406894793-35/implement-hook-demo-freeze — 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. 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 * invoker: wf-1789406894793-35/verify-hook-demo-freeze — Run the deterministic 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 * invoker: wf-1789406894793-35/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 58d2877b-64ef-434d-8479-4faf4996f91f --------- Co-authored-by: Invoker Bot <invoker@local>
…de (#732) * invoker: wf-1789406883560-32/implement-hook-build-the-lever — 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. 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 * invoker: wf-1789406883560-32/verify-hook-build-the-lever — Run the deterministic 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 * invoker: wf-1789406883560-32/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 70147de4-ee65-46de-90da-48ab84cce9d0 * invoker: wf-1789406886887-33/implement-hook-cat-mode-default — 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. 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 * invoker: wf-1789406886887-33/verify-hook-cat-mode-default — Run the deterministic 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 * invoker: wf-1789406886887-33/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 74c962cc-f188-4db3-be0c-c3da68c20e9a * invoker: wf-1789406891093-34/implement-hook-categorical-scope-guard — 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 * invoker: wf-1789406891093-34/verify-hook-categorical-scope-guard — Run 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 * invoker: wf-1789406891093-34/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 85155944-670a-40b9-a845-1252af44dacd * invoker: wf-1789406894793-35/implement-hook-demo-freeze — 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. Exit code: 1 Invoker-Finalize-Id: 4a3989de-6a6e-4011-9900-c8aa481e9c27 * invoker: wf-1789406894793-35/implement-hook-demo-freeze — 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. 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 * invoker: wf-1789406894793-35/verify-hook-demo-freeze — Run the deterministic 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 * invoker: wf-1789406894793-35/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 58d2877b-64ef-434d-8479-4faf4996f91f * invoker: wf-1789406897817-36/implement-hook-diu-stop — 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. Exit code: 1 Invoker-Finalize-Id: cc582581-b6f8-4f71-8dd9-cf16d79f1628 * invoker: wf-1789406897817-36/implement-hook-diu-stop — 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. 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 * invoker: wf-1789406897817-36/verify-hook-diu-stop — Run the deterministic 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 * invoker: wf-1789406897817-36/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: d41f4da8-d2ba-4eec-847c-65460155a619 --------- Co-authored-by: Invoker Bot <invoker@local>
|
Mergify repair stopped: unresolved human review thread PRRT_kwDOT3uYWs6jPLm9 |
… hook code (#766) * invoker: wf-1789406883560-32/implement-hook-build-the-lever — 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. 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 * invoker: wf-1789406883560-32/verify-hook-build-the-lever — Run the deterministic 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 * invoker: wf-1789406883560-32/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 70147de4-ee65-46de-90da-48ab84cce9d0 * invoker: wf-1789406886887-33/implement-hook-cat-mode-default — 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. 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 * invoker: wf-1789406886887-33/verify-hook-cat-mode-default — Run the deterministic 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 * invoker: wf-1789406886887-33/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 74c962cc-f188-4db3-be0c-c3da68c20e9a * invoker: wf-1789406886887-33/implement-hook-cat-mode-default — 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. Exit code: 1 Invoker-Finalize-Id: d1bf500d-c8f0-47fc-8c0d-c636c7506b4c * invoker: wf-1789406886887-33/implement-hook-cat-mode-default — 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. 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: publish-approved-fix * invoker: wf-1789406886887-33/verify-hook-cat-mode-default — Run the deterministic 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: 5699f69c-cb1c-4890-b373-d374ac8be49f * invoker: wf-1789406886887-33/scrub-handoff-artifacts — 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 Exit code: 0 Invoker-Finalize-Id: 946f5c14-9399-42ca-a370-bbe5a0fedc02 --------- Co-authored-by: Invoker Bot <invoker@local> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… 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. Exit code: 1 Invoker-Finalize-Id: c99c0492-b180-456b-bfa1-0dc12286babf
… 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. Exit code: 0 Invoker-Finalize-Id: publish-approved-fix
…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: 1520f16c-25dd-46cb-9c23-704b47674955
…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: 5e36be9b-5d81-43c2-b960-7e5dde433045
…-aabe4097d-912cfb8d — 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
b23ffd0 to
f1c98a1
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f1c98a1. Configure here.
| "additionalContext": REMINDER, | ||
| } | ||
| })) | ||
| run_hook("diu-stop", "claude", detect, "UserPromptSubmit") |
There was a problem hiding this comment.
Reminder findings always record as stopped
Medium Severity
The prompt reminder detect always returns a finding, and diu-stop stays in registry stop mode. UserPromptSubmit still only injects context, but every turn is stored as a stopped event. That drowns out the hook's real stop counts used for mode review.
Reviewed by Cursor Bugbot for commit f1c98a1. Configure here.


Summary
The guard that checks "all" requests now runs on the shared hook code. It still stops a command that changes only some items after the user asked for all.
Before this, the hook chose its own response and printed its own output. A mode change meant editing the hook itself.
Now the hook only reports what it found. The shared code picks stop, warn, or silent from the registry and writes one event row per finding.
One behavior did change. If the checker itself crashes, the hook now lets the command through and logs the error. Before, it blocked the command.
Review Claim
The guard that checks "all" requests reports findings to the shared hook code, which applies its registry mode and writes event rows. It keeps mode stop.
Review Lane
behavior
Review Unit
engine-runtime
Safety Invariant
Every case in the hook's current test folder gets the same stop, warn, or silent result as before, and the folder still exits 0. The new mode-override test is the only intended change.
Known gap: when the checker crashes, the hook used to block the command. The removed code in
claude_pretooluse.pycaught the error and calledsys.exit(2). Now the shared runtime's crash handler inengine/hooks/_sdk/runtime.pylogscatstack-hook-error categorical-scope-guard: <error>and callssys.exit(0), so the command goes through. A deliberate crash probe (see Test Plan) exited 0. The current test folder has no case for this path. A reviewer should decide whether this needs a follow-up.Slice Rationale
One hook per workflow, so each move to the shared code is reviewed on its own. This is part 15 of the stack in
docs/hook-architecture.md.Non-goals
install_claude_hook.pywas listed in the plan but is not changed here.Test Plan
Test Plan
python3 -m unittest discover -s engine/hooks/categorical-scope-guard/tests→Ran 45 tests in 0.290s/OKtest_mode_override_warn_changes_block_to_warning: withCATSTACK_HOOK_MODE_CATEGORICAL_SCOPE_GUARD=warn, a case that stops today exits 0 and returns a warning instead.test_each_finding_writes_one_event_row_with_rule_id: one stopped event row with rule idcategorical-scope-guard.narrowed-mutation.python3 engine/skills/make-pr/scripts/preflight.py --dry-run --base origin/plan/hook-architecture-14-put-the-cat-mode-default-hook-onto-the-shared-hook-code→unit engine-runtime: 4 file(s)/ok preflight passedpython3 scripts/ci/check_hook_test_coverage.py engine/hooks/categorical-scope-guard→check_hook_test_coverage: OK (1 hook(s) checked)bash scripts/scrub-handoff-artifacts.sh→scrub-handoff-artifacts-okRuntimeError("probe")). The expected error log printed:catstack-hook-error categorical-scope-guard: RuntimeError: probe. The probe then printedcrash-path exit 0.ruff check --select E9,Fon the four changed files: not run, becauseruffis not installed on this machine (command not found: ruff).Revert Plan
Revert Plan
git revert <merge-sha>🤖 Generated with Claude Code
Note
High Risk
categorical-scope-guard is security-sensitive; shared-runtime detector crashes now fail open (exit 0) instead of blocking, which can let status-narrowed mutations through if classification breaks.
Overview
categorical-scope-guard now reports
Findingobjects throughengine/hooks/_sdk/runtime.pyinstead of choosing exit codes in the Claude entrypoint. Thin PreToolUse wrappers exist for Claude, Cursor, and Codex;detect(event)maps HIT/UNCHECKED to rule idspartial-status-filterandunchecked. Registry defaultstopstill blocks, butCATSTACK_HOOK_MODE_CATEGORICAL_SCOPE_GUARD=warnturns blocks intoadditionalContextwarnings and writes per-finding metrics rows (new SDK mode tests).Documented behavior change: if
detect()throws past its own handler, the shared runtime logscatstack-hook-error, records a crash event, and exits 0 (allows the tool). The old entrypoint exited 2 on detector failure.The same diff also moves demo-freeze and diu-stop (Claude Stop/UserPromptSubmit, Codex notify) onto
run_hook, addsCATSTACK_HOOK_METRICS_DIRsetup in cat-mode fail-open tests, clarifies invalid JSON stderr inruntime.py, and adds a working-style rule plustest_check_memory_first_rule.pyto pin “search saved memory (both ways) before a deep dive.”Reviewed by Cursor Bugbot for commit f1c98a1. Bugbot is set up for automated code reviews on this repo. Configure here.