Merge branch 'feat/compose-solution' into refactor/drop-restricted agents

This commit is contained in:
Parfii-bot 2026-04-21 19:10:42 +08:00
commit 4e8542a0d5
9 changed files with 636 additions and 0 deletions

View file

@ -140,6 +140,16 @@ KeiSeiKit ships 11 verified tool-bridge templates under `_bridges/`. Render them
All paths are idempotent: existing bridge files in the project are skipped, never overwritten. See `_bridges/README.md` for the full template→output-path table.
## Meta-composer
`/compose-solution` is the meta-creator: tell it what you want to solve in one free-text paragraph, it decomposes the task, greps existing blocks / skills / manifests / bridges for prior art, proposes a minimal math-first architecture, and assembles the right artefact — agent, skill, hook, rule, or block. Every decision except the intake is a click (option-picker), never free-text.
Example: "I want a hook that blocks `rm -rf ~/` in any Bash call" → Phase 2 decomposes into (pattern-match, severity, event, wiki entry) → Phase 3 greps `hooks/` and `_blocks/` for prior art → Phase 5 proposes `hook = PreToolUse:Bash + pattern + exit 2` → Phase 7 hands off to `/escalate-recurrence` with severity and event pre-filled.
Phase 6 is the feedback loop: when a component has no prior art, the skill drafts a new `_blocks/<slug>.md` and — on your click — persists it. Next time `/compose-solution` (or `/new-agent`) runs, that block is discoverable. Every session leaves the kit a little smarter; the report prints `_blocks/` count before → after so the growth is visible.
See `skills/compose-solution/SKILL.md` and its phase files (`phase-1-intake.md` through `phase-7-assemble.md`) for the full 7-phase pipeline.
## License
MIT. See `LICENSE` in this directory.

View file

@ -0,0 +1,121 @@
---
name: compose-solution
description: Meta-orchestrator — converts a free-text task description into the right artefact(s) (agent, skill, hook, rule, or block) by composing existing KeiSeiKit primitives. Pure-click decision chain except the single intake field. Enriches `_blocks/` over time via Phase 6 block-augmentation — the kit gets smarter with every invocation.
argument-hint: <free-text task description>
---
# Compose-Solution — Meta-Orchestrator (index)
You are converting an arbitrary user task ("I want to solve X") into the
right durable KeiSeiKit artefact — an agent manifest, a skill, a hook, a
rule, or a new behavioural block. You decompose, grep prior art,
gap-analyse, compose, and assemble. Every decision is a click; only the
intake description (and an optional free-text edit in Phase 6) is typed.
This skill is the **meta-creator**: it does not itself write production
code. It routes to `new-agent` (agent branch), to `escalate-recurrence`
(hook/rule branch), or composes a new skill/block in-place.
This `SKILL.md` is the INDEX. Each phase lives in its own file and is
executed in order. Never skip a phase. Never re-order phases.
---
## Pipeline overview (7 phases + final report)
| Phase | File | Purpose | Free-text? | AskUserQuestion |
|---|---|---|---|---|
| 1 | [phase-1-intake.md](phase-1-intake.md) | Intake + target-type click | 1 line (`DESC`) | 1× AskUserQuestion |
| 2 | [phase-2-decompose.md](phase-2-decompose.md) | Wave-based decomposition | no | 1× AskUserQuestion |
| 3 | [phase-3-prior-art.md](phase-3-prior-art.md) | Prior-art grep sweep | no | 0 |
| 4 | [phase-4-gap-analysis.md](phase-4-gap-analysis.md) | Gap analysis (multi-select) | no | 1× AskUserQuestion |
| 5 | [phase-5-architecture.md](phase-5-architecture.md) | Architecture (math-first) | no | 1× AskUserQuestion |
| 6 | [phase-6-block-augment.md](phase-6-block-augment.md) | Block augmentation | optional per-block | 1× AskUserQuestion per new block |
| 7 | [phase-7-assemble.md](phase-7-assemble.md) | Recipe assembly (branches on `T`) | no | 1× AskUserQuestion |
Minimum AskUserQuestion count across a full session: **6** — one each in
Phases 1, 2, 4, 5, at least one in Phase 6 (if any gaps selected), and one
in Phase 7. This is the pure-click contract: only intake is free-text.
---
## Variables the pipeline produces
| Name | Set in | Meaning |
|---|---|---|
| `DESC` | Phase 1a | The user's one-paragraph task description |
| `T` | Phase 1b | Target artefact type — Agent / Skill / Hook / Rule / Block / Auto-detect |
| `COMPONENTS` | Phase 2 | 2-5 orthogonal components, each with 3-5 grep keywords |
| `CLASSIFICATION` | Phase 3 | Per-component: REUSE / ADAPT / CREATE / EXTERNAL + evidence grade |
| `GAPS` | Phase 4 | User-selected subset of components that need Phase-6 augmentation |
| `ARCHITECTURE` | Phase 5 | Math-first composition expression + block list + Constructor-Pattern check |
| `BLOCKS_WRITTEN` | Phase 6 | Names of newly persisted `_blocks/*.md` files (possibly empty) |
| `FINAL_NAME` | Phase 7 | Path of the assembled artefact (or handoff target) |
---
## Final report (emit after Phase 7)
```
=== COMPOSE-SOLUTION REPORT ===
Intake: <first 80 chars of DESC>...
Target type: <T (after auto-detect resolution, if applicable)>
Decomposition: <N components>
Prior-art: <M reused, K adapted, L created, X external>
Blocks written: <names> (kit: <before_count><after_count>)
Assembled: <artefact path or "handed off to <skill>">
Next action: <what user should run / review / commit>
Future invocations benefit from the K new blocks — kit is now smarter by K blocks.
```
---
## Rules (apply throughout — enforced at every phase)
- **Pure-click contract.** Only `DESC` (Phase 1a) and optional per-block
edits (Phase 6b "Edit") are typed. Every other decision is an
`AskUserQuestion` call. Count them in the final report.
- **NO DOWNGRADE.** Any phase that fails returns 2-3 constructive paths,
never "can't be done".
- **NO HALLUCINATION (RULE 0.4).** Every block / skill / agent / bridge
name referenced in the session MUST exist on disk. Phase 3 greps, Phase 5
architecture listing, and Phase 7 handoffs all verify before citing. If
grep returns nothing — the component class is CREATE, report it, never
invent a phantom match.
- **Plan Mode First (RULE 0.5).** This skill IS the plan; each phase file
has its own verify-criterion. No Edit/Write before the corresponding
phase's confirm click.
- **Constructor Pattern (RULE ZERO).** Every new block is single-concern,
20-40 LOC, hard-capped at 60 LOC → split. Every new skill phase is < 30
LOC of imperative prose. This `SKILL.md` index file itself must stay
< 200 LOC; phase files each < 150 LOC.
- **Surgical Changes.** Compose-solution writes only to:
- `_blocks/<slug>.md` (Phase 6, user-approved)
- `skills/<slug>/SKILL.md` (Phase 7c, user-approved)
- Hands off to `new-agent` (Phase 7b) or `escalate-recurrence`
(Phase 7d/e) — no direct writes to `_manifests/`, `~/.claude/rules/`,
or `~/.claude/hooks/`.
- **Kit-enrichment feedback loop.** Phase 6 is the virtuous cycle: every
missing block becomes a new permanent block, so the next invocation of
compose-solution (or `new-agent`) finds more prior art in Phase 3.
Report the before/after block count in every session that touched Phase
6 — this makes the loop visible.
---
## References
- [phase-1-intake.md](phase-1-intake.md) · [phase-2-decompose.md](phase-2-decompose.md) · [phase-3-prior-art.md](phase-3-prior-art.md) · [phase-4-gap-analysis.md](phase-4-gap-analysis.md) · [phase-5-architecture.md](phase-5-architecture.md) · [phase-6-block-augment.md](phase-6-block-augment.md) · [phase-7-assemble.md](phase-7-assemble.md)
- `skills/research/SKILL.md` — Variant C "Deep decomposition" wave pattern
(Phase 2 delegation target for heavy tasks)
- `skills/new-agent/SKILL.md` — 8-phase wizard (Phase 7b handoff target)
- `~/.claude/skills/escalate-recurrence/SKILL.md` — hook + rule + wiki
pipeline (Phase 7d/e handoff target)
- `~/.claude/skills/architecture/SKILL.md` — optional, for heavy
architectural decomposition if `research` is overkill
- `_blocks/baseline.md`, `_blocks/rule-math-first.md` — block templates
(Phase 6a shape references)
- `_manifests/kei-*.toml` — 14 kit agents (Phase 7b handoff references)
- `_bridges/*.tmpl` — 11 tool bridges (architecture Phase 5 may reference
them for agent-creation flows)

View file

@ -0,0 +1,46 @@
# Phase 1 — Intake
One free-text line + one click batch. This is the only typed input required
by the whole skill (Phase 6 may add optional per-block edit prose).
## 1a — Ask for the task description
Emit a regular message (NOT AskUserQuestion):
> Describe the task in one paragraph: what do you want to solve, for which
> project or concern, and what's the expected surface (something that runs,
> something that blocks a mistake, something that documents a pattern)?
> Reply in one message.
Store the user's reply verbatim as `DESC`.
## 1b — Target-type click (AskUserQuestion, ONE call)
```json
{
"questions": [
{
"question": "Target artefact type?",
"header": "Type",
"multiSelect": false,
"options": [
{"label": "Auto-detect", "description": "Orchestrator infers from intake — recommended when unsure"},
{"label": "Agent (specialist)", "description": "New kit-agent manifest — specialist for a project or concern"},
{"label": "Skill (user-invoked)", "description": "A /slash skill in ~/.claude/skills/ or KeiSeiKit/skills/"},
{"label": "Hook (enforcement)", "description": "Shell hook registered in settings.json (block / enforce / warn / remind)"},
{"label": "Rule (documentation)", "description": "Rule file in ~/.claude/rules/ with optional hook partner"},
{"label": "Block (reusable)", "description": "Behavioural block in _blocks/ — composable via manifests"}
]
}
]
}
```
Store the choice as `T`. If `T == "Auto-detect"`, leave resolution until
Phase 7 (after architecture is known).
## Verify-criterion
- `DESC` is non-empty.
- `T` is exactly one of the six labels above.
- If either fails — re-ask the failing input; do not fall through.

View file

@ -0,0 +1,49 @@
# Phase 2 — Wave-based decomposition
Goal: break `DESC` into 2-5 orthogonal components that can each be
independently researched and composed.
## 2a — Choose path (heavy vs lightweight)
For heavy / patent-scale / unfamiliar-domain tasks, delegate to the
`research` skill (`skills/research/SKILL.md`, Variant C "Deep decomposition"
is the pattern — Wave 0 decomposition, then Wave 1 per-component
exploration). Invoke via the Agent tool with `subagent_type: kei-researcher`
(or `researcher` if that agent is present in the user's global fleet). Pass
`DESC` as the research question with the constraint:
> Decompose into 2-5 orthogonal components, each with a 1-line description
> and 3-5 distinctive keywords suitable for grep prior-art search.
For lighter tasks (single-feature, obvious stack), do **inline lightweight
decomposition**: emit 3-5 components as a plain markdown bullet list in
chat — one line each — with 3-5 grep keywords per component in parentheses.
## 2b — Confirm decomposition (AskUserQuestion)
```json
{
"questions": [
{
"question": "Decomposition OK?",
"header": "Decomposition",
"multiSelect": false,
"options": [
{"label": "Confirm", "description": "Proceed to Phase 3 prior-art sweep with this decomposition"},
{"label": "Merge / split", "description": "You want to merge two components or split one — reply with one free-text line"},
{"label": "Add component", "description": "A necessary component is missing — reply with one free-text line"},
{"label": "Abort", "description": "Stop — nothing gets written"}
]
}
]
}
```
On `Merge / split` or `Add component` → single free-text prompt, regenerate,
re-ask. Do NOT silently adjust.
## Verify-criterion
- User clicked `Confirm`.
- Each component has ≥ 3 grep keywords (for Phase 3 search).
- Components are orthogonal (no circular dependency between two components).

View file

@ -0,0 +1,52 @@
# Phase 3 — Prior-art grep sweep (parallel)
For EACH component from Phase 2, run three independent searches in parallel
(single message, multiple Bash tool calls).
## 3a — KeiSeiKit reuse
```bash
# Replace <keywords> with the component's 3-5 distinctive keywords as an
# ERE alternation like (foo|bar|baz).
grep -rinlE '<keywords>' _blocks/ _manifests/ skills/ _bridges/ hooks/ 2>/dev/null
```
## 3b — Personal bundle reuse (conditional, skip on missing)
```bash
if [ -d ~/Projects/KeiSeiBundle ]; then
grep -rinlE '<keywords>' ~/Projects/KeiSeiBundle/ 2>/dev/null | head -20
else
echo "KeiSeiBundle: absent — skipping layer B"
fi
```
Document absence in the report — do NOT fabricate a hit.
## 3c — External docs (delegate)
For any component that involves an external API, framework, or third-party
library, delegate a tiny research task to a `kei-researcher` subagent: one
WebSearch call, one WebFetch of the top hit, one-paragraph summary. Skip if
the component is entirely internal.
## 3d — Classify + evidence-grade
For each component produce ONE row:
```
Component N: <one-line>
Keywords: (foo|bar|baz)
3a reuse: <path1>, <path2> or NONE
3b reuse: <path> (bundle) or ABSENT / NONE
3c ext: <URL summary> or INTERNAL
Class: [REUSE | ADAPT | CREATE | EXTERNAL]
Evidence: [E1-E6]
```
## Verify-criterion
- Every component has a classification.
- Every cited file path exists on disk (RULE 0.4 — no fabricated paths).
- If grep returns nothing, class is CREATE and the report says so — no
phantom matches.

View file

@ -0,0 +1,38 @@
# Phase 4 — Gap analysis (AskUserQuestion multi-select)
Present the classification matrix from Phase 3 as a code block (markdown
list) in chat, then emit:
```json
{
"questions": [
{
"question": "Which gaps to close this session?",
"header": "Gaps",
"multiSelect": true,
"options": [
{"label": "Component N — CREATE new block", "description": "No prior art found — draft a new _blocks/ entry in Phase 6"},
{"label": "Component M — ADAPT existing block", "description": "Prior art found but needs edits — copy + modify in Phase 6"},
{"label": "Component K — wire external API", "description": "External dep — reference api-*.md block or add a new one"},
{"label": "Skip — components K, L reuse as-is", "description": "No action needed, they're already covered"}
]
}
]
}
```
Options are GENERATED dynamically — one per component from Phase 3 whose
class ∈ {ADAPT, CREATE, EXTERNAL}. User clicks zero or more. Empty
multi-select is valid: means "reuse only, skip Phase 6".
Substitute the literal component descriptions in the option labels (not the
placeholders shown above — those are the shape). For example, if
Component 2 is "cost guard for fal.ai calls" and its class is CREATE, the
option label becomes `"Component 2: cost guard for fal.ai calls — CREATE new block"`.
## Verify-criterion
- Selected gap list stored as `GAPS` (a list of component-indices with
their chosen action: CREATE / ADAPT / EXTERNAL).
- Empty list is allowed and means Phase 6 is skipped entirely.
- No component has two contradicting actions (e.g. REUSE + CREATE).

View file

@ -0,0 +1,70 @@
# Phase 5 — Architecture proposal (math-first)
Compose the architecture by following `_blocks/rule-math-first.md`.
## 5a — Expression first
One to three lines describing which primitives combine, in which order,
with which invariants. Use this shape:
```
artefact = compose(block_A, block_B, ..., block_N)
where block_* ∈ {_blocks/, newly drafted, skills/, _manifests/}
invariant: <one-line, e.g. "every cube <200 LOC, every handoff verified">
```
## 5b — What is UNNECESSARY?
For each block listed, justify why it's in. If a block can be removed
without losing the user's goal — remove it. Derive-first: explicit claim
"this is the minimal decomposition, nothing removable". Follow the checklist
from `_blocks/rule-math-first.md`:
- Learned parameters / free knobs? WHY? Determined by input?
- Separate blocks for similar concerns? WHY? Can a single block cover both?
- Gate / wrapper layers? WHY? Is a direct reference enough?
## 5c — Constructor Pattern check
Each output cube must be single-concern, file < 200 LOC, function < 30 LOC.
If the proposed assembly violates this, split before proceeding.
## 5d — Count
Show the numbers explicitly in the preview:
- New files: N
- Edits to existing files: M
- Total lines of markdown to be written: L
## 5e — Preview + confirm
Preview as plain text in chat, then:
```json
{
"questions": [
{
"question": "Architecture OK?",
"header": "Architecture",
"multiSelect": false,
"options": [
{"label": "Confirm", "description": "Proceed to Phase 6 block augmentation (if any gaps) then Phase 7 assembly"},
{"label": "Revise component N", "description": "One component's decomposition or reuse choice is wrong — reply with one free-text line"},
{"label": "Remove something", "description": "You see a block that's not strictly necessary — reply which one"},
{"label": "Abort", "description": "Stop — nothing gets written"}
]
}
]
}
```
On `Revise` / `Remove` → ONE free-text prompt, regenerate the architecture,
re-preview.
## Verify-criterion
- User clicked Confirm.
- The expression (5a) is present and < 3 lines.
- The "what is unnecessary" pass (5b) has been applied and is visible in the
preview.
- Constructor Pattern check (5c) passed.

View file

@ -0,0 +1,94 @@
# Phase 6 — Block augmentation (conditional)
Only runs if `GAPS` from Phase 4 is non-empty. For EACH `CREATE` or `ADAPT`
entry in `GAPS`, run this sub-phase in sequence (NOT in parallel — user must
approve each before the next).
## 6a — Draft the block
Template (follow the shape of `_blocks/baseline.md` or
`_blocks/rule-math-first.md` — short, single-concern, imperative voice):
```markdown
# <HEADING pattern name in short caps>
<One-line purpose statement.>
## When to include
<1-3 bullets describing which manifests should list this block in
their `blocks = [...]` array.>
## What it declares
<3-8 imperative bullets. Constructor Pattern: one concern only.>
## References
- <link to upstream rule or external doc, if any>
- <evidence grade [E1-E6]>
```
Target length: 20-40 LOC markdown. Hard ceiling: 60 LOC — above that, SPLIT
into two blocks before continuing.
Slug: kebab-case, 2-4 words. Must not collide with existing `_blocks/*.md`.
Verify via:
```bash
ls _blocks/<slug>.md 2>/dev/null && echo "COLLISION" || echo "free"
```
If collision: append a disambiguator (`<slug>-v2`, or a domain suffix like
`<slug>-patent`).
## 6b — Preview + per-block click (AskUserQuestion)
Emit the draft inline in chat, then:
```json
{
"questions": [
{
"question": "Write this block?",
"header": "Block",
"multiSelect": false,
"options": [
{"label": "Write to _blocks/<slug>.md", "description": "Save permanently — enriches the kit for all future sessions"},
{"label": "Edit (free-text)", "description": "Reply with one free-text message describing changes; I regenerate"},
{"label": "Skip this block", "description": "Don't save this one; proceed to next gap"},
{"label": "Abort session", "description": "Stop the whole skill; nothing else gets written"}
]
}
]
}
```
Resolution:
- **Write** → use Write tool to create `_blocks/<slug>.md` under the repo
root (`~/Projects/KeiSeiKit/_blocks/` when running against the kit repo;
or wherever `$PWD`'s `_blocks/` lives when invoked from another KeiSeiKit
fork).
- **Edit** → single free-text prompt, regenerate, re-preview.
- **Skip** → move to next gap.
- **Abort** → stop; no writes Phase 6 onward.
## 6c — After all gaps processed
Report the block-count delta:
```bash
ls _blocks/ | wc -l
```
Show `before → after` count so the user sees the kit got N blocks smarter
this session. This is the feedback-loop signal — make it visible in every
session that touched Phase 6.
## Verify-criterion
Every block written passes two sanity checks:
- File exists on disk after Write.
- No `{{placeholder}}` literals remain (the assembler's `validator.rs`
rejects those; same hygiene applies here).

View file

@ -0,0 +1,156 @@
# Phase 7 — Recipe assembly (branches on `T`)
Before branching, resolve auto-detect if `T == "Auto-detect"`.
## 7a — Resolve auto-detect (conditional)
Infer target type from architecture (Phase 5):
- Expression mentions a project's CLAUDE.md + stack block + deploy block →
**Agent**.
- Expression is a 3-phase flow with AskUserQuestion calls → **Skill**.
- Expression is a trigger + enforcement pair, pattern-matched on tool input
**Hook** (and, usually, companion **Rule**).
- Expression is documentation + wiki indexing, no automation → **Rule**.
- Expression is a single reusable 20-40 LOC markdown — already handled in
Phase 6 → **Block**.
Present the inferred type:
```json
{
"questions": [
{
"question": "Detected target: <X>. Proceed?",
"header": "Auto-detect",
"multiSelect": false,
"options": [
{"label": "Yes — proceed with <X>", "description": "Run the <X> branch below"},
{"label": "Change to Agent", "description": "Override the inference — go to 7b"},
{"label": "Change to Skill", "description": "Override — go to 7c"},
{"label": "Change to Hook", "description": "Override — go to 7d"},
{"label": "Change to Rule", "description": "Override — go to 7e"},
{"label": "Block only (no assembly)", "description": "Already handled in Phase 6 — skip to final report"}
]
}
]
}
```
Substitute `<X>` with the literal inferred label.
## 7b — Agent branch
Hand off to the `new-agent` skill — it already codifies the 8-phase wizard
(`skills/new-agent/SKILL.md`). Two handoff methods:
1. **Invoke via Agent tool** with `subagent_type: kei-code-implementer` (or
equivalent), prompt: "Run the `new-agent` skill wizard. Use these
already-decided fields from compose-solution: stack, deploy, paid-APIs,
ML, patent-IP, secrets, scrapers. Slug, description, path, gotchas are
derived from DESC. Blocks list preference (from Phase 5 architecture):
<list>."
2. **Instruct user** to run `/new-agent` in a fresh turn if Agent
delegation is unavailable; paste the Phase-5 architecture into that
session.
Compose-solution steps back here — `new-agent` owns the rest.
## 7c — Skill branch
Compose a new `skills/<slug>/SKILL.md` inline:
```markdown
---
name: <slug>
description: <one-line derived from DESC>
argument-hint: <if the skill takes a target, e.g. "<project or path>">
---
# <Human Name><one-line>
<2-3 sentences: what the skill does, when to invoke, who owns the output.>
## Phase 1 — Intake (<AskUserQuestion | free-text>)
<Derived from architecture Phase 5. Escalate-recurrence style: if the
decision space is discrete, use AskUserQuestion; otherwise one free-text
line, strictly validated.>
## Phase 2 — <Action>
<Steps derived from Phase 5 expression. Verify-criterion per step.>
## Phase 3 — Report
<What the user sees at the end. Concise report block.>
## Rules
<Borrow from _blocks/baseline.md if generic enforcement needed.>
```
Minimum three phases (intake / action / report). AskUserQuestion pattern
follows `escalate-recurrence` (see
`~/.claude/skills/escalate-recurrence/SKILL.md` globally, or
`skills/new-agent/SKILL.md` Phase-1b style locally).
Preview + final confirm:
```json
{
"questions": [
{
"question": "Write this skill?",
"header": "Skill",
"multiSelect": false,
"options": [
{"label": "Write to skills/<slug>/SKILL.md", "description": "Save permanently; user can invoke as /<slug>"},
{"label": "Edit (free-text)", "description": "Reply with one message describing changes"},
{"label": "Abort", "description": "Stop — nothing gets written"}
]
}
]
}
```
On `Write``mkdir -p skills/<slug>/ && Write skills/<slug>/SKILL.md`.
## 7d — Hook branch
Delegate to the `escalate-recurrence` skill
(`~/.claude/skills/escalate-recurrence/SKILL.md`). That skill already owns
hook scaffolding at 4 severities (block / enforce / warn / remind) + 5
event types (PreToolUse:Bash, PreToolUse:Edit|Write, PostToolUse:*,
UserPromptSubmit, Stop) and registers via the `update-config` skill.
Instruct the user:
> Run `/escalate-recurrence` in a fresh turn. Use these already-decided
> fields from compose-solution:
> - Pattern name: `<slug>`
> - Two+ concrete trigger instances: <from DESC and Phase-5 architecture>
> - Suggested severity: <warn | enforce | block | remind> — based on
> <one-line justification from DESC>
> - Suggested event: <PreToolUse:Bash | Edit|Write | UserPromptSubmit | ...>
Or invoke via Agent tool if delegation is permitted.
Compose-solution steps back — `escalate-recurrence` owns writes.
## 7e — Rule branch
Same handoff as 7d — `escalate-recurrence` owns the rule + wiki pipeline
(it writes `~/.claude/rules/<slug>.md`, updates `RULES.md`, `MEMORY.md`, and
optionally `CLAUDE.md` Rules Index). Instruct the user to run
`/escalate-recurrence` with Phase-1 choice "No hook" if the user wants
documentation-only.
## 7f — Block only
Already handled in Phase 6. Skip to final report.
## Verify-criterion
- Exactly one branch ran (7b / 7c / 7d / 7e / 7f).
- The resulting artefact path is captured for the final report.