accc1692e1
Spec §4.4 — shouldBlock rewritten on mode='off'|'warn-only'|'enforce'. Old
boolean warnOnly API kept as legacy fallback. Continuation deliberately NOT
in the §17 exempt set (D1) — an inherited 'feature' classification still
triggers the gate.
- tools/router-tool-gate.mjs:
+ NON_BLOCKING_TASK_TYPES = ['conversation','micro','manual_override']
+ shouldBlock returns false OR { block: true, reason } with reason ∈
{'no_skill_found_block','direct_in_non_conversation'}.
+ Reads state.classification.task_type (v4 snake_case) with fallback to
legacy taskType — backward-compatible until Task 14 updates prehook.
+ resolveMode(): options.mode wins; legacy warnOnly=false maps to enforce.
+ decideDecision returns decision/reason/reason_code on block, warning on
warn-only with non-exempt classification, empty on proceed/exempt.
+ gateMode() now recognises 'off' alongside warn-only/enforce.
- tools/router-tool-gate.test.mjs: rewritten 25 tests (mode-based) — covers
§17 exempt set, no_skill_found path, skill invoked, routing-tag escape,
read-only Bash, tool whitelist, legacy back-compat (warnOnly + taskType),
decideDecision reason_code + warn-only warning suppression on exempt tasks.
Tests: 25/25 PASS.