diff --git a/corpus/skills/cat-mode/SKILL.md b/corpus/skills/cat-mode/SKILL.md index 7af3811e..2f2d5c40 100644 --- a/corpus/skills/cat-mode/SKILL.md +++ b/corpus/skills/cat-mode/SKILL.md @@ -201,6 +201,11 @@ bug: invoke `automate-me`, do not wait. - **Treat absolute negatives as categorical.** - **A blocked target is a stop, not a licence to substitute.** A number produced on a proxy carries the proxy's name beside the number. +- **A hook or classifier block is a stop, not a puzzle.** Do what the block + asks, or report the block and stop. Never reword the prompt, switch tools, + retag the claim, or propose weakening the hook to get past it. + Disagreement with a block goes to the user, after reading the hook's + source. - **An answer given through a tool binds exactly as hard as a typed one.** Each rule's full text: diff --git a/corpus/skills/cat-mode/references/named-constraints.md b/corpus/skills/cat-mode/references/named-constraints.md index 3b869def..67f4ed17 100644 --- a/corpus/skills/cat-mode/references/named-constraints.md +++ b/corpus/skills/cat-mode/references/named-constraints.md @@ -22,6 +22,14 @@ individual constraints it covers. name in the same message as the number. Before reaching for a third vendor or workaround, read `.env.example` and ask which paid source the user already has. +- **A hook or classifier block is a stop, not a puzzle.** Do not reword a + subagent prompt after `agent-routing-guard` refused it. Do not end a gated + turn with a couldn't-verify tag instead of running the check the gate asked + for. Do not reissue a denied command through a different tool, flag, or + invocation; the classifier-denial rule in `corpus/CLAUDE.learned.md` already + binds this shape. Do not open a change that makes a hook complain less. Do + what the block asks, and if the block is wrong, read the hook's source and + raise it with the user with that evidence. - **An answer given through a tool binds exactly as hard as a typed one.** A free-text reply to a multiple-choice question means every option offered was wrong. Restate it as a binding parameter in the plan before any work diff --git a/tests/test_cat_mode.py b/tests/test_cat_mode.py index 72bc17d1..8c198bf6 100644 --- a/tests/test_cat_mode.py +++ b/tests/test_cat_mode.py @@ -603,6 +603,19 @@ def test_named_constraints_reference_keeps_its_rules(self): self.assertIn("carries the proxy's name in the same message as the number", text) self.assertIn("An answer given through a tool binds exactly as hard as a typed one", text) + def test_block_is_a_stop_rule_kept_its_full_text_in_the_reference(self): + """The bullet's bold lead lives in SKILL.md; the concrete forbidden + shapes (reword, retag, reissue through another tool, weaken the hook) + live in named-constraints.md. Locks both halves the same way + test_unhedged_claim_rule_kept_its_full_text_when_it_moved does.""" + skill = normalized_skill_text() + self.assertIn("A hook or classifier block is a stop, not a puzzle.", skill) + reference = normalized_reference_text("named-constraints.md") + self.assertIn("A hook or classifier block is a stop, not a puzzle.", reference) + self.assertIn("Do not reword a subagent prompt after `agent-routing-guard` refused it", reference) + self.assertIn("Do not reissue a denied command through a different tool, flag, or invocation", reference) + self.assertIn("Do not open a change that makes a hook complain less", reference) + def test_routing_defers_to_an_installed_harness_routing_skill(self): skill = normalized_skill_text() self.assertIn("**An installed harness routing skill wins**", skill)