From c992b04ac4532479546e01629933123f7daf323a Mon Sep 17 00:00:00 2001 From: Edbert Chan Date: Sat, 12 Sep 2026 05:28:11 +0000 Subject: [PATCH 1/6] Add cat-mode block stop rule --- corpus/skills/cat-mode/SKILL.md | 5 +++++ corpus/skills/cat-mode/references/named-constraints.md | 8 ++++++++ 2 files changed, 13 insertions(+) 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 From bba451d63ae82c6ab57e43a367e75c15e92a86ef Mon Sep 17 00:00:00 2001 From: Invoker Bot Date: Sat, 12 Sep 2026 05:28:43 +0000 Subject: [PATCH 2/6] =?UTF-8?q?invoker:=20wf-1789190816603-2/add-block-is-?= =?UTF-8?q?a-stop-rule=20=E2=80=94=20Review=20claim:=20cat-mode=20names=20?= =?UTF-8?q?a=20hook=20or=20classifier=20block=20as=20a=20stop,=20with=20th?= =?UTF-8?q?e=20concrete=20ways=20of=20getting=20past=20a=20block=20spelled?= =?UTF-8?q?=20out=20as=20forbidden.=20Review=20lane:=20docs=20Safety=20inv?= =?UTF-8?q?ariant:=20Prose=20only.=20No=20hook,=20script,=20installer,=20o?= =?UTF-8?q?r=20settings=20change,=20and=20no=20edit=20outside=20corpus/ski?= =?UTF-8?q?lls/cat-mode.=20Pending=20user=20confirmation=20in=20this=20ses?= =?UTF-8?q?sion.=20Effectiveness=20measurement:=20The=20coverage=20and=20p?= =?UTF-8?q?rovenance=20gates=20pass=20on=20the=20diff=20and=20the=20bullet?= =?UTF-8?q?'s=20bold=20lead=20appears=20once=20in=20SKILL.md.=20Slice=20ra?= =?UTF-8?q?tionale:=20One=20rule=20in=20one=20skill,=20so=20the=20diff=20c?= =?UTF-8?q?arries=20one=20claim.=20Architectural=20effect:=20None;=20the?= =?UTF-8?q?=20mode=20skill=20gains=20one=20standing=20rule.=20Goal:=20Add?= =?UTF-8?q?=20the=20bullet=20to=20SKILL.md=20under=20Named=20constraints?= =?UTF-8?q?=20and=20its=20full=20text=20to=20references/named-constraints.?= =?UTF-8?q?md,=20mirroring=20the=20neighbours'=20structure.=20Motivation:?= =?UTF-8?q?=20The=20same=20complaint=20class=20recurred=20in=20three=20ses?= =?UTF-8?q?sions=20and=20the=20existing=20lines=20cover=20only=20reading?= =?UTF-8?q?=20a=20gate=20and=20classifier=20denials.=20Alternative=20consi?= =?UTF-8?q?derations:=20Relying=20on=20the=20tag-needs-a-tool-call=20hook?= =?UTF-8?q?=20alone=20was=20rejected=20because=20rewording=20a=20subagent?= =?UTF-8?q?=20prompt=20and=20reissuing=20a=20denied=20command=20are=20not?= =?UTF-8?q?=20tag=20shapes.=20Restating=20the=20classifier-denial=20rule?= =?UTF-8?q?=20from=20CLAUDE.learned.md=20was=20rejected;=20the=20new=20tex?= =?UTF-8?q?t=20references=20it=20in=20one=20clause.=20Implementation=20det?= =?UTF-8?q?ails:=20See=20prompt.=20Non-goals:=20No=20hook=20or=20code=20ch?= =?UTF-8?q?ange.=20No=20change=20to=20CLAUDE.core.md=20or=20CLAUDE.learned?= =?UTF-8?q?.md.=20No=20dates,=20session=20ids,=20or=20incident=20narrative?= =?UTF-8?q?=20in=20the=20rule=20text.=20Layer:=20docs=20Feature=20state:?= =?UTF-8?q?=20active=20Files:=20-=20corpus/skills/cat-mode/SKILL.md=20-=20?= =?UTF-8?q?corpus/skills/cat-mode/references/named-constraints.md=20Change?= =?UTF-8?q?=20types:=20-=20corpus/skills/cat-mode/SKILL.md:=20modify=20-?= =?UTF-8?q?=20corpus/skills/cat-mode/references/named-constraints.md:=20mo?= =?UTF-8?q?dify=20Acceptance=20criteria:=20-=20`git=20grep=20-c=20"A=20hoo?= =?UTF-8?q?k=20or=20classifier=20block=20is=20a=20stop,=20not=20a=20puzzle?= =?UTF-8?q?"=20--=20corpus/skills/cat-mode/SKILL.md`=20prints=201.=20-=20`?= =?UTF-8?q?python3=20scripts/check=5Fskill=5Ftest=5Fcoverage.py=20--base?= =?UTF-8?q?=20origin/main=20--head=20HEAD`=20exits=200.=20-=20`python3=20s?= =?UTF-8?q?cripts/check=5Fno=5Fdated=5Fprovenance.py`=20exits=200.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exit code: 0 Invoker-Finalize-Id: 6f060ec2-4eb0-4b6e-af44-cf78932754c7 From 3dd7ea5ef9465bac1adff8df33d50f4cb0da9321 Mon Sep 17 00:00:00 2001 From: Invoker Bot Date: Sat, 12 Sep 2026 05:30:19 +0000 Subject: [PATCH 3/6] =?UTF-8?q?invoker:=20wf-1789190816603-2/verify-rule-p?= =?UTF-8?q?resent-and-gates=20=E2=80=94=20Review=20claim:=20the=20rule=20i?= =?UTF-8?q?s=20present=20exactly=20once=20and=20the=20prose=20gates=20pass?= =?UTF-8?q?=20on=20the=20finished=20branch.=20Review=20lane:=20proof=20Saf?= =?UTF-8?q?ety=20invariant:=20Verification=20is=20read-only=20and=20does?= =?UTF-8?q?=20not=20alter=20any=20file.=20Effectiveness=20measurement:=20T?= =?UTF-8?q?he=20grep=20count=20and=20the=20two=20gate=20runs=20are=20the?= =?UTF-8?q?=20direct=20measurement.=20Slice=20rationale:=20One=20focused?= =?UTF-8?q?=20proof=20per=20claim=20before=20review.=20Architectural=20eff?= =?UTF-8?q?ect:=20None;=20verification=20only.=20Goal:=20Prove=20the=20bul?= =?UTF-8?q?let=20landed=20once=20and=20the=20coverage=20and=20provenance?= =?UTF-8?q?=20gates=20are=20green.=20Layer=20exception:=20allowed.=20Proof?= =?UTF-8?q?=20runs=20after=20the=20docs=20task=20so=20it=20checks=20the=20?= =?UTF-8?q?finished=20branch;=20it=20reads=20files=20only=20and=20changes?= =?UTF-8?q?=20nothing.=20Motivation:=20A=20rule=20that=20fails=20a=20gate?= =?UTF-8?q?=20never=20reaches=20the=20installed=20skill.=20Alternative=20c?= =?UTF-8?q?onsiderations:=20Reading=20the=20diff=20by=20eye=20was=20reject?= =?UTF-8?q?ed=20as=20non-deterministic.=20Implementation=20details:=20Run?= =?UTF-8?q?=20the=20grep=20and=20the=20two=20gate=20scripts.=20Non-goals:?= =?UTF-8?q?=20No=20mutations.=20Layer:=20app=5Fregression=20Feature=20stat?= =?UTF-8?q?e:=20active=20Acceptance=20criteria:=20-=20Exits=200=20only=20w?= =?UTF-8?q?hen=20the=20grep=20count=20is=201=20and=20both=20gates=20pass.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exit code: 1 Invoker-Finalize-Id: d7581d63-c315-4b14-8995-518d9748c0f7 From 2ac5b07b08b4d98e95b2015c3ac8aa2304a50769 Mon Sep 17 00:00:00 2001 From: Edbert Chan Date: Sat, 12 Sep 2026 05:31:57 +0000 Subject: [PATCH 4/6] Add test coverage for cat-mode block-is-a-stop rule The prior docs commit added the "hook or classifier block is a stop" bullet to SKILL.md and named-constraints.md without a corresponding test change, failing check_skill_test_coverage.py. Co-Authored-By: Claude Sonnet 5 --- tests/test_cat_mode.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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) From 23491edc35a039fa3c16b7ec8c3abbb0ec3dbbd5 Mon Sep 17 00:00:00 2001 From: Invoker Bot Date: Sat, 12 Sep 2026 05:32:36 +0000 Subject: [PATCH 5/6] =?UTF-8?q?invoker:=20wf-1789190816603-2/verify-rule-p?= =?UTF-8?q?resent-and-gates=20=E2=80=94=20Review=20claim:=20the=20rule=20i?= =?UTF-8?q?s=20present=20exactly=20once=20and=20the=20prose=20gates=20pass?= =?UTF-8?q?=20on=20the=20finished=20branch.=20Review=20lane:=20proof=20Saf?= =?UTF-8?q?ety=20invariant:=20Verification=20is=20read-only=20and=20does?= =?UTF-8?q?=20not=20alter=20any=20file.=20Effectiveness=20measurement:=20T?= =?UTF-8?q?he=20grep=20count=20and=20the=20two=20gate=20runs=20are=20the?= =?UTF-8?q?=20direct=20measurement.=20Slice=20rationale:=20One=20focused?= =?UTF-8?q?=20proof=20per=20claim=20before=20review.=20Architectural=20eff?= =?UTF-8?q?ect:=20None;=20verification=20only.=20Goal:=20Prove=20the=20bul?= =?UTF-8?q?let=20landed=20once=20and=20the=20coverage=20and=20provenance?= =?UTF-8?q?=20gates=20are=20green.=20Layer=20exception:=20allowed.=20Proof?= =?UTF-8?q?=20runs=20after=20the=20docs=20task=20so=20it=20checks=20the=20?= =?UTF-8?q?finished=20branch;=20it=20reads=20files=20only=20and=20changes?= =?UTF-8?q?=20nothing.=20Motivation:=20A=20rule=20that=20fails=20a=20gate?= =?UTF-8?q?=20never=20reaches=20the=20installed=20skill.=20Alternative=20c?= =?UTF-8?q?onsiderations:=20Reading=20the=20diff=20by=20eye=20was=20reject?= =?UTF-8?q?ed=20as=20non-deterministic.=20Implementation=20details:=20Run?= =?UTF-8?q?=20the=20grep=20and=20the=20two=20gate=20scripts.=20Non-goals:?= =?UTF-8?q?=20No=20mutations.=20Layer:=20app=5Fregression=20Feature=20stat?= =?UTF-8?q?e:=20active=20Acceptance=20criteria:=20-=20Exits=200=20only=20w?= =?UTF-8?q?hen=20the=20grep=20count=20is=201=20and=20both=20gates=20pass.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exit code: 0 Invoker-Finalize-Id: publish-approved-fix From 3c7c3f59670b692a8ae7067a77ccd61902858ef7 Mon Sep 17 00:00:00 2001 From: Invoker Bot Date: Sat, 12 Sep 2026 05:33:27 +0000 Subject: [PATCH 6/6] =?UTF-8?q?invoker:=20wf-1789190816603-2/scrub-handoff?= =?UTF-8?q?-artifacts=20=E2=80=94=20Review=20claim:=20No=20ephemeral=20int?= =?UTF-8?q?er-task=20handoff=20files=20remain=20in=20the=20worktree=20befo?= =?UTF-8?q?re=20the=20merge=20gate.=20Review=20lane:=20cleanup=20Safety=20?= =?UTF-8?q?invariant:=20The=20scrub=20script=20only=20checks=20for=20known?= =?UTF-8?q?=20handoff=20artifact=20names=20and=20never=20touches=20source,?= =?UTF-8?q?=20tests,=20or=20other=20repository=20files.=20Effectiveness=20?= =?UTF-8?q?measurement:=20The=20script=20exits=20non-zero=20if=20any=20han?= =?UTF-8?q?doff=20artifact=20remains.=20Slice=20rationale:=20Required=20te?= =?UTF-8?q?rminal=20scrub=20for=20every=20implementation=20workflow.=20Arc?= =?UTF-8?q?hitectural=20effect:=20None;=20hygiene=20only.=20Goal:=20Leave?= =?UTF-8?q?=20the=20branch=20free=20of=20handoff=20artifacts.=20Motivation?= =?UTF-8?q?:=20Handoff=20files=20must=20not=20reach=20the=20PR.=20Alternat?= =?UTF-8?q?ive=20considerations:=20Manual=20cleanup=20was=20rejected=20as?= =?UTF-8?q?=20non-deterministic.=20Implementation=20details:=20Run=20scrip?= =?UTF-8?q?ts/scrub-handoff-artifacts.sh.=20Non-goals:=20No=20product=20ed?= =?UTF-8?q?its.=20Layer:=20app=5Fregression=20Feature=20state:=20active=20?= =?UTF-8?q?Acceptance=20criteria:=20-=20`bash=20scripts/scrub-handoff-arti?= =?UTF-8?q?facts.sh`=20exits=200.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exit code: 0 Invoker-Finalize-Id: 608b0668-5db8-4b5b-898b-415a17f9d6c7