---
description: Build a blast radius for a file/table/endpoint via launch-chart and push it to launch-deck as an interactive radial graph. Use to assess "what breaks if I change X" before refactors, schema migrations, or API contract changes. Chart-first; on chart gaps (no nodes, missing layer, empty edges) files a feedback comment to LaunchSecure so the gap is monitored.
when_to_use: |
  Auto-fire when the user wants to VISUALISE the reverse-dependency blast radius for a specific node (file / table / endpoint / hook) before a refactor, migration, or contract change. Trigger phrases: "what breaks if I change X", "blast radius for X", "impact of refactoring X", "who's affected if I rename / drop / remove X", "scope this migration", "ripple effect of changing X", "is X safe to remove". Deck is required because the deliverable is an interactive radial graph — a flat list of dependents in the terminal misses ring/layer structure. Do NOT auto-fire for: simple "who imports X" or "where is X used" (use /kit:analyse), reading the structure of one file (use chart read_graph directly), planning the change itself (separate step that runs after blast-radius), plain-text dependency summaries the user can read in the terminal, or any request without a clear named target node.
allowed-tools:
  - mcp__launch-deck__server_status
  - mcp__launch-deck__start_server
  - mcp__launch-deck__deck
  - mcp__launch-chart__chart_server_status
  - mcp__launch-chart__detect_project_stack
  - mcp__launch-chart__blast_points
  - mcp__launch-chart__read_graph
  - mcp__launch-secure__kit_feedback_submit
  - Bash
---

# /kit:blast-radius

Calculate the reverse-dependency blast radius for a target node and visualise it as an interactive radial graph in launch-deck. The graph centres on the target and rings out by hop distance across all project layers (db / api / ui / static / etc.).

Parse `$ARGUMENTS`:
- **target** (required) — a node id from the project graph (file path like `lib/permissions/types.ts`, table name like `User`, endpoint id like `POST /api/work-items`). If absent, ask the user.
- **hops=N** — max traversal depth. Default 2.
- **layer=<id>** — restrict to one layer when the same name exists in multiple layers (e.g. `layer=db`).
- **--session=<id>** — deck session name. Default `blast-<target-slug>`.
- **--mode=feature** — render with feature rings (modify / create / ripple) instead of the default structural rings (hop1 / hop2). Use when the radius represents planned change scope rather than pure structural reachability.

Examples:
- `/kit:blast-radius lib/permissions/types.ts`
- `/kit:blast-radius User layer=db hops=3`
- `/kit:blast-radius POST /api/work-items --mode=feature`

## Preflight

1. Confirm both MCPs are wired — `mcp__launch-chart__chart_server_status` and `mcp__launch-deck__server_status`. If either is missing, stop and tell the user to run `npx @launchsecure/launch-kit refresh` (or `npx launch-deck` for the deck server).
2. Run `mcp__launch-chart__detect_project_stack` once. Cache the returned `layers` for the bug-report fallback below.

## 1. Compute the blast points

Call `mcp__launch-chart__blast_points` with `node_id: <target>`, `hops: <hops>`, `direction: "reverse"`, and `layer` if supplied. The tool returns affected nodes (with hop, type, layer, module) plus a summary.

**Chart-gap detection** — if any of these are true, file a feedback comment per the shared `chart-gap` protocol below before stopping:
- `error` is set
- `nodes` is empty AND the user explicitly named a node id that exists on disk (verify by `Read`-ing the path)
- `summary.byLayer` covers fewer layers than `detect_project_stack` reported as available

## 2. Build the manifest

Translate the blast_points result into the deck `blast-radius` block manifest shape. Reuse layer ids/icons/colors from `detect_project_stack` so the visual matches the project's conventions; fall back to:
- db → `database`, `#172554`
- api → `server`, `#1e3a5f`
- ui → `layout-dashboard`, `#0c4a6e`
- static → `file-text`, `#374151`
- shared → `puzzle`, `#4338ca`
- middleware → `shield`, `#1f2937`
- config → `cog`, `#52525b`

Rings:
- structural mode (default): `[{id:"hop1",name:"Direct",color:"#f97316"},{id:"hop2",name:"Indirect",color:"#eab308"}]`
- feature mode: `[{id:"modify",name:"Modify",color:"#f97316"},{id:"create",name:"Create",color:"#22c55e"},{id:"ripple",name:"Ripple",color:"#eab308"}]`

Centre node: `{ name: <target>, description: "<N> direct, <M> indirect (<hops> hops)" }`.

Nodes: map each blast result row to `{ id, name, layer, ring: hop===1 ? "hop1" : "hop2", path, type }`.

Edges: connect the centre to every hop=1 node; connect each hop=2 node to one hop=1 ancestor from its dependency chain (read from `blast_points` `via` field if present, otherwise pick any hop=1 node in the same layer).

## 3. Push to deck

Call `mcp__launch-deck__deck` with `session: <session>`, `mode: "show"`, `blocks: [{ type: "blast-radius", label: <target>, manifest: <built-manifest> }]`.

If the deck server isn't running, call `mcp__launch-deck__start_server` first, then retry.

## 4. Open in browser

After the push, open the per-session URL so the user lands directly on this blast-radius:

```
open "<deck-url>/#<session>"          # macOS
xdg-open "<deck-url>/#<session>"      # Linux
```

`<deck-url>` is the `url` returned by `mcp__launch-deck__server_status` (typically `http://localhost:52829`). The `#<session>` hash deep-links to this exact session.

## Output

After the push, print a terse summary:

```
blast-radius for <target> — <N> direct, <M> indirect (<hops> hops)
  by layer: db 4, api 7, ui 12
  pushed to deck session "<session>" — <deck-url>/#<session>
```

## Chart-gap protocol (shared)

When the chart MCP returns less data than expected, file ONE report via `mcp__launch-secure__kit_feedback_submit` (the kit-self feedback channel — NOT `communication_write`, which would land in the user's own project Comm Hub instead of the launch-kit project) before stopping:

```
title: "launch-chart gap: <one-line>"
source: "kit:blast-radius"
body: |
  Skill: /kit:blast-radius
  Tool:  blast_points(node_id=<id>, hops=<n>, layer=<layer?>)
  Returned: <nodes_count> nodes, layers=<layers_seen>
  Expected: <what-was-expected, e.g. "node exists at <path>" or "layer X should appear">
  Project stack: <one-line summary from detect_project_stack>
```

Do NOT spam — file at most one report per skill invocation. After filing, tell the user "Filed chart-gap report to launch-kit project. Falling back to read_graph + Read." and continue with a degraded path: try `mcp__launch-chart__read_graph` with `search: <target>` to confirm the node exists in any layer; if so, do the blast-radius math from `include_edges: true` results manually; otherwise stop and surface the gap to the user.

## Constraints

- **MCP-first.** Never grep the filesystem to build the manifest — use `blast_points` and `read_graph`.
- **Idempotent on re-run.** Re-pushing to the same session overwrites the previous render — that's fine, just tell the user.
- **Single bug-file per run.** Don't file a comment for every gap; bundle into one report.
- **Plain text output.** No markdown tables, no fenced blocks in the human-facing summary.
