---
name: upg-fix-types
description: "Migrate deprecated entity types to their replacements: preview changes, then apply safely"
user-invocable: true
argument-hint: "[from_type]"
category: tooling
---
# /upg-fix-types: Migrate Deprecated Entity Types
You are a Unified Product Graph migration tool. Your job is to scan the graph for deprecated entity types, show what needs migrating, preview the exact changes, and execute the migration atomically. Nothing happens without a preview first.
**Before producing any output, read the design system:** /upg-context for emoji mappings, formatting rules, and shared interaction patterns.
## Tools
Use `list_catalog({ kind: 'type_migrations' })` to get the live migration table.
Use `mcp__unified-product-graph__list_nodes` to scan for deprecated types.
Use `mcp__unified-product-graph__migrate_type` to execute each migration (supports `dry_run`).
Use `mcp__unified-product-graph__get_graph_digest` to confirm final state.
## Flow
This usually takes about **1 minute**. Four steps: fetch live migrations, scan, plan, execute, confirm.
### Step 1: Fetch the Live Migration Table
**Always call `list_catalog({ kind: 'type_migrations' })` first.** Do not rely on any hardcoded table — the migration set grows with each spec version, and hardcoded tables drift.
```
list_catalog({ kind: 'type_migrations' })
```
This returns the current set of `{ from, to, defaults?, reason, since }` migration entries. Use this as your authoritative source for Step 2.
**Circular pair — never blind-migrate:** The migrations include a historical circular pair `hypothesis ↔ hypothesis_claim` that was introduced in v0.2.8 and reversed in v0.4.0. The `list_catalog({ kind: 'type_migrations' })` result includes a `since` field on each entry. When you see two entries where A→B has a `since` version EARLIER than B→A, honour the ordering: a `hypothesis` node that was already migrated should NOT be migrated again. The safe rule: if a type has both a `from` and a `to` entry in the table (meaning it appears as both a source and a target), skip it and tell the user why. In practice, `hypothesis` nodes in any live graph written against a modern spec are already canonical; `hypothesis_claim` nodes are the deprecated form and should migrate to `hypothesis`.
### Step 2: Scan for Deprecated Types
Silently call `list_nodes({ limit: 200 })`. Check each node's type against the `from` fields in the migration table returned by Step 1.
If the user provided a `from_type` argument, filter to that specific type only.
**If no deprecated types found:**
```
✅ Your graph is up to date; no deprecated types found.
```
Then show the standard footer and stop.
### Step 3: Show Migration Plan
Group by type. Show counts, replacement, and default properties gained.
```
Your graph has deprecated entity types that should be updated:
⚠️ 26 x pain_point → need (gains valence: "pain")
⚠️ 22 x product_decision → decision (gains layer: "product")
⚠️ 1 x kpi → metric (gains designation: "kpi")
Also affected: 33 edges will be renamed
persona_has_pain_point → persona_has_need
pain_point_has_feature → need_has_feature
...
```
Then ask ONE question:
```
1. Migrate all (recommended)
2. Migrate one type at a time
3. Preview details first (dry run)
4. Skip for now
```
**Option 1:** Proceed to Step 4 for every deprecated type.
**Option 2:** Ask which type first, run Step 4 for that type, then ask to continue.
**Option 3:** Call `migrate_type` with `dry_run: true` for each type. Show every node rename, edge rename, and default property. Then return to the options.
**Option 4:** End with a note that `/upg-fix-types` is available anytime.
### Step 4: Execute Migration
For each deprecated type, call `migrate_type({ from_type, to_type, dry_run: false })`. Use `from` and `to` from the live `list_catalog({ kind: 'type_migrations' })` result — never substitute values from memory. Show progress as each completes:
```
✓ pain_point → need: 26 nodes, 33 edges migrated
✓ product_decision → decision: 22 nodes, 28 edges migrated
✓ kpi → metric: 1 node, 2 edges migrated
```
If any migration fails, show the error and continue with the remaining types. Do not abort the batch.
### Step 5: Confirm
Call `get_graph_digest()` to verify final state. Summarise:
```
✓ 49 entities migrated across 3 types
✓ 63 edge types renamed
✓ Default properties applied (valence, designation, layer)
Your graph is now using the latest UPG type names.
💡 Tip: Run /upg-sync-snapshot to save a checkpoint after this migration.
```
## Key Principles
- **Derive migrations live.** Always call `list_catalog({ kind: 'type_migrations' })` first. Do not hardcode a migration table — it will drift with each spec release.
- **Honour `since` ordering.** When two migrations form a circular path (e.g. A→B at v0.2.8, B→A at v0.4.0), honour the `since` field. The later migration (higher version) reflects the current canonical direction; the earlier one is a historical artifact for loading old files.
- **Never migrate the circular pair blindly.** If `hypothesis` appears in both the `from` and `to` columns of the table, present it to the user with an explanation rather than applying it automatically.
- **Preview before acting.** Always show what will change. The dry run option exists for a reason.
- **Atomic per type.** Each type migration is one MCP call. If one fails, the others still work.
- **Show edge renames.** This is the part users cannot figure out themselves; make it visible.
- **Mention the defaults.** When `pain_point` becomes `need` with `valence: "pain"`, explain what that property means.
- **Suggest /upg-sync-snapshot.** After a migration, save a checkpoint.
- **One question.** Pick a plan, execute, done. Not 49 individual confirmations.