
blast-radius
Before modifying shared code (types, APIs, utilities), find all consumers. Prevents partial migratio
作者 maxtheman|オープンソース
Blast Radius Assessment
Purpose
Know exactly what will break before changing shared code. Prevents "fixed one thing, broke three others."
When to Use
- Changing a type definition
- Modifying a function signature
- Renaming a prop or field
- Altering API response shape
- Updating shared utility
- Any change to exported symbols
Prerequisites
- Change clearly defined (what's changing, how)
- HelixDB indexed and connected
- Repo Prompt connected
Included Files (Optional)
This skill can bundle extra files in its directory.
scripts/read_file.py: quick file-read preview script (demo/testing)- Run (from this skill folder):
python3 scripts/read_file.py path/to/file --max-bytes 4096 - Run (absolute path, user-scope install):
python3 ~/.codex/skills/blast-radius/scripts/read_file.py path/to/file - (Optional) If you use
uv:uv run python scripts/read_file.py path/to/file
- Run (from this skill folder):
scripts/run_uv.sh: convenience wrapper- Runs with plain
python3by default - If you add a
pyproject.tomlto this skill, it will create/use an isolated env at~/.Mx/skill-envs/blast-radius(override withMX_SKILL_ENVS_DIR) and run viauv - Run:
bash ~/.codex/skills/blast-radius/scripts/run_uv.sh scripts/read_file.py README.md --max-bytes 200
- Runs with plain
Protocol
Step 1: Define the Change
Document before starting:
| Property | Value |
|---|---|
| Target file | src/types/product.ts |
| Symbol | Product type |
| Change type | Add field / Remove field / Rename / Change type |
| Before | { sku: string } |
| After | { sku: string, skuSource: "auto" | "manual" } |
| Breaking | New required field |
Step 2: Find All Consumers (HelixDB)
For types:
helix: get_references("<TypeName>")
For functions:
helix: get_call_hierarchy("<functionName>")
For components:
helix: get_references("<ComponentName>")
For renamed fields:
helix: search_code("<oldFieldName>", limit: 50)
Step 3: Categorize Impact
For each consumer, read the usage:
read_file(path: "<consumer>", start_line: N, limit: 20)
Categorize by risk:
| Category | Definition | Action Required |
|---|---|---|
| Direct | Uses changed field/param directly | MUST update |
| Passthrough | Receives and passes without transforming | MAY need type annotation |
| Type-only | Only imports the type | Update if renamed |
| Test | Test asserting on old shape | MUST update fixtures |
| Indirect | Uses via intermediate | Check intermediate |
Step 4: Build Update Plan
Order by dependency (roots first):
- Type definitions (the contract)
- Producers (where data created)
- Direct consumers
- Passthroughs
- Tests
Step 5: Load Impact Set (Repo Prompt)
manage_selection(op: "set", paths: [<all impacted files>], mode: "codemap_only")
workspace_context(include: ["tokens", "selection"])
If over budget, prioritize:
- Direct consumers → full
- Tests → full
- Passthroughs → codemap
Output Format
## Blast Radius: [Change Description]
### Change Definition
| Property | Before | After |
|----------|--------|-------|
| File | src/types/product.ts | - |
| Symbol | Product | - |
| Field | - | skuSource: "auto" \| "manual" |
| Breaking | - | Yes (new required field) |
### Impact Assessment
#### By Category
| Category | Count | Files |
|----------|-------|-------|
| Direct | 3 | Products.tsx, Catalog.tsx, QuoteBuilder.tsx |
| Passthrough | 1 | ProductList.tsx |
| Type-only | 2 | index.ts, types.ts |
| Test | 2 | product.test.ts, catalog.test.ts |
#### Detailed Impact
| File | Category | Risk | Specific Change Needed |
|------|----------|------|------------------------|
| Products.tsx | Direct | HIGH | Add skuSource to form state |
| Catalog.tsx | Direct | HIGH | Display skuSource indicator |
| QuoteBuilder.tsx | Direct | MED | Handle missing skuSource |
| ProductList.tsx | Passthrough | LOW | Type annotation only |
| product.test.ts | Test | HIGH | Update all Product fixtures |
| catalog.test.ts | Test | HIGH | Update assertions |
### Update Order
| Order | File | Change | Depends On |
|-------|------|--------|------------|
| 1 | types/product.ts | Add skuSource field | - |
| 2 | convex/products.ts | Populate skuSource in queries | Step 1 |
| 3 | Products.tsx | Consume skuSource | Steps 1-2 |
| 4 | Catalog.tsx | Display skuSource | Steps 1-2 |
| 5 | QuoteBuilder.tsx | Handle skuSource | Steps 1-2 |
| 6 | product.test.ts | Update fixtures | Steps 1-5 |
### Migration Checklist
- [ ] All direct consumers identified
- [ ] Update order determined
- [ ] Tests identified for update
- [ ] Rollback plan documented
Verification After Changes
Search for stragglers:
helix: search_code("<old_field_name>", limit: 20)
If results found → migration incomplete.
Limitations
- Dynamic property access (
obj[key]) not detected - String-based field access (
obj["field"]) may be missed - Runtime-only consumers (config files, external systems) invisible
- Transitive dependencies may need recursive queries
Risk Levels
| Change Type | Typical Risk | Mitigation |
|---|---|---|
| Add optional field | Low | Usually safe, verify defaults |
| Add required field | High | All consumers must update |
| Remove field | High | Must verify no usage remains |
| Rename field | High | Find-replace across all consumers |
| Change type | Medium-High | Verify coercion doesn't hide bugs |
| Change optionality | Medium | Required→optional safe; reverse risky |
Next Actions
- Execute
coordinate-changeswith the update order - After changes, run
verify-seams - If pattern likely to recur,
extract-contract