Closes v3.8 FATAL F2: nested agent() calls inside Workflow scripts were
invisible to PreToolUse gates. New tools/enforce-workflow-gate.mjs hook
(PreToolUse, block-mode) enforces:
1. scriptPath requires approve_workflow_script record in
~/.claude/runtime/askuser-decisions-<sess>.jsonl with sha256 of content
and 5-min window (mirrors approve_git_operation pattern).
2. scriptContent static-scanned for dangerous patterns: env-key reads
(ROUTER_LLM_KEY/ANTHROPIC_API_KEY/GITHUB_TOKEN/SENTRY_AUTH_TOKEN),
eval(), child_process spawn/exec/fork, absolute fs writes outside /tmp,
path traversal (../../../).
3. sha256 mismatch between approval and current content → block (catches
modification after approval).
4. resumeFromRunId blocked unconditionally (state replay risk per spec).
5. Per-agent inheritance via CLAUDE_GATE_INHERIT env is handled by
subagent-prompt-prefix.mjs (Stream E) — this hook focuses on the outer
Workflow tool call. Nested agent() inside Workflow inherits parent gate.
Regression: vitest tools 1731/1731 GREEN (was 1726; +5 workflow-gate tests
under "enforce-workflow-gate scriptPath approval (F2)" describe block).
DEFERRED: .claude/settings.json registration (matcher "Workflow" → command
"node tools/enforce-workflow-gate.mjs", block-mode, timeout 5000ms) — the
settings.json file is in DEFAULT_PROTECTED_PATTERNS and enforce-read-path-
deny.mjs (Smoke 5 emergency fix 25e184e5) has no LEGIT_SKILLS exemption
like enforce-normative-content-rules.mjs does. Harness Edit/Write tracker
cannot be satisfied without a successful Read first. Will be batched into
a single manual settings.json registration step at end of Phase H-α
alongside H5/H6/H7 hook registrations. Hook code is fully implemented and
unit-tested; activation pending settings.json update.
Stream H Task 3 of 11. Plan: docs/superpowers/plans/2026-05-30-router-gate-v4-stream-H.md