Reflect and automate-me hooks are off until one setting turns them on - #500
Open
EdbertChan wants to merge 1 commit into
Conversation
Owner
Author
|
This pull request is part of a Mergify stack:
|
2 tasks
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_866bee4b-375b-4220-ab9b-2c1b022b6a7e) |
Four hooks push the user toward /reflect and automate-me: scope-lock (which stops every tool after a second scope correction), reflect-on-thrash, wrong-check-reflect and verdict-flip-watch. None of them could be switched off. They now do nothing unless CATSTACK_REFLECT_ENFORCEMENT is on, read from the environment, $CATSTACK_ENV_FILE, the repo's .env or ~/.catstack.env. The reader moves into engine/hooks/_flags so the four hooks share one lookup instead of four copies drifting apart. It also stops returning "not set" for an .env file that exists but cannot be read: that case raises inside the reader, is collected in FlagLookup.unreadable, and enforcement_gate names the file on stderr before failing closed. Each gate sits ahead of the hook's recorder, not just its output. A disabled scope-lock that kept counting corrections would hard stop the first tool call after the flag went on; a disabled reflect-on-thrash that kept writing its deferred marker would hand the prompt to a later session. install.sh links _flags into the Claude, Cursor and Codex hook folders, since scope-lock and wrong-check-reflect load it on all three. A missing link is an import error at hook start, which fails open and looks like "not opted in"; _flags/tests/test_installed_layout.py pins the link per harness. The scenario runner switches the flag on for each scenario. Without that, two expect_fire/expect_enqueue scenarios failed, and three expect_silent checks on these hooks passed only because the hook was off. A new test inverts two real scenarios with the flag set to 0 and requires both to be reported. frustration-watchdog is deliberately left alone: it enforces the live-demo "end the wait" rule and its output never mentions reflect or automate-me. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vy9sMw49j6PqS2NLRBYhs Change-Id: I82a634782fcb75591db4807d0d67e028c02ae252
EdbertChan
force-pushed
the
stack/EdbertChan/docs/reflect-enforcement-flag-readme/reflect-automate-me-enforcement-opt-behind-one--82a63478
branch
from
September 12, 2026 19:28
0c00aa6 to
710df82
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_8164718a-765c-4b2b-94f4-157892fac721) |
Owner
Author
Revision history
|
Contributor
|
Tick the box to add this pull request to the merge queue (same as
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Some checkers in this kit push you to stop and review your own work. One can freeze every tool until you type two set phrases.
The problem: there was no way to turn these checkers off. They ran on every machine, whether or not you wanted them.
The cause: each checker was written to always run. None of them looked for a setting.
The fix: these four checkers now stay quiet unless you switch them on with one setting. If a settings file cannot be read, they say so out loud.
Review Claim
Four review-pushing checkers do nothing until you turn on one shared setting, and a settings file that cannot be read is reported, not treated as "off".
Review Lane
behavior
Review Unit
engine-runtime
Safety Invariant
With
CATSTACK_REFLECT_ENFORCEMENT=1, all four hooks behave exactly as before: every existing test passes with only an opt-in added to its setup, no assertion changed. Unset, they stay silent and write no state. A missing_flagslink fails open (silent), never blocks a tool.Slice Rationale
One claim: the reflect/automate-me class gets an off switch. The shared reader in
engine/hooks/_flagsships in the same PR because the four gates are its only new callers; splitting it out would land a module nothing uses.frustration-watchdogis left out on purpose: it enforces the live-demo "end the wait" rule and its output never mentions reflect or automate-me. The scenario runner change is in this PR because without it the gate makes two scenarios fail and three silence checks pass for the wrong reason. The root README section naming the flag is a stacked docs PR on top of this one, since the lane rules keep docs out of a behavior PR.Non-goals
cat-mode-defaultonto the shared reader; it keeps its own copy for now.automate-meandreflectskills,cat-mode, and the "same complaint twice" line in the core rules). Skills cannot read an environment variable; gating them would be an install-time change and a separate PR._markersinto the Cursor and Codex hook folders, although it has the same gap_flagswould have had.Architecture
Before
graph TD A["hook payload"] --> B["scope-lock / reflect-on-thrash / wrong-check-reflect / verdict-flip-watch"] B --> C["record state, then block or nudge"]After
graph TD A["hook payload"] --> G["_flags.enforcement_gate(hook, cwd)"] G -->|"env, CATSTACK_ENV_FILE, repo .env, ~/.catstack.env"| D{"CATSTACK_REFLECT_ENFORCEMENT on?"} G -->|"a candidate file exists but cannot be read"| N["name the file on stderr"] N --> D D -->|"no"| S["return silent, write no state"] D -->|"yes"| B["same detector as before"] B --> C["record state, then block or nudge"]Test Plan
Test Plan
python3 -m unittest discover -s engine/hooks/_flags/tests(29 tests: lookup order, set-on / set-off / unset, unreadable file reported not swallowed, installed symlink layout,_flagslinked into all three harness hook folders)python3 -m unittest discover -s engine/hooks/scope-lock/tests(newTestEnforcementFlagfailed 5 subtests before the gate, passes after)python3 -m unittest discover -s engine/hooks/reflect-on-thrash/testspython3 -m unittest discover -s engine/hooks/verdict-flip-watch/testspython3 -m unittest discover -s engine/hooks/wrong-check-reflect/testspython3 -m unittest tests.test_skill_scenarios(new inverted-scenario test failed with[]before the runner fix, passes after)python3 engine/skills/make-pr/scripts/preflight.py --base origin/main(exit 0, unitengine-runtime)bash scripts/run_all_tests.shon this PR's tree (710df82):EXIT=0, 1932 ok, 0 failed, 1 skipped (CONSUMER_REPO_ROOTnot set; unrelated).github/workflows/ci.yml, run locally on 710df82, each exit 0:check_no_tracked_local_artifacts,check_hook_test_coverage(36 hooks),check_rules_are_wired,check_skills_three_harnesses,check_ecosystem_boundaries,check_skill_file_refs,check_skill_test_coverage --base origin/main --head HEAD,check_skill_test_debt_no_growth,check_skill_trigger_mechanism,check_dora_baseline,check_no_dated_provenance --base origin/main,check_no_new_comments --base origin/main,ruff check . --select E9,F,shellcheck install.shcheck_no_new_comments(fail 20 new comment line(s); comments are banned in code); the comments were removed or folded into docstrings, and the same check now printsok no new commentstests.test_no_new_comments,tests.test_no_dated_provenance,tests.test_skill_scenarios, the five hook suites above, andscripts/check_no_tracked_local_artifacts.py, all OKRevert Plan
Revert Plan
git revert <merge-sha>./install.shso the_flagslinks are pruned; the four hooks go back to always on.🤖 Generated with Claude Code
https://claude.ai/code/session_011vy9sMw49j6PqS2NLRBYhs