- name
- jgs-v1-migrate-write
- description
- v1→v2 migration write phase: build the v2 model from the live v1 model (packages, part definitions/usages, and requirement definitions/usages, with v1 requirement IDs carried over as join keys). PRO tier required; write-tier on the jgs-magic-sysmlv2-mcp bridge. Requires jgs-magic-sysmlv1-mcp AND jgs-magic-sysmlv2-mcp both running. Trigger: "write the migration", "build v2 from v1", "execute the migration", "write phase", "migrate v1 to v2 now".
- bridges
- ["v1","v2"]
<!--
Copyright (c) 2026 JG Systems Consulting Ltd. All Rights Reserved.
See LICENSE for terms.
-->
# jgs-v1-migrate-write: v1→v2 Migration Write Phase (UC-V1-13)
Build a SysML v2 model from a live SysML v1 model. The v1 bridge is used read-only; every write goes through the v2 bridge after the user approves the migration plan. A re-run never duplicates: existing v2 elements are detected and skipped, and interrupted elements are repaired.
**Invocation:** `/jgs-v1-migrate-write [<v1-root-package>] [into <v2-target-package>]`
## When to use
Use when you want to build the SysML v2 model from a live SysML v1 model: packages, part definitions/usages, and requirement definitions/usages, with v1 requirement IDs carried over as join keys.
## Prerequisites
- `jgs-magic-sysmlv1-mcp` and `jgs-magic-sysmlv2-mcp` both running (the v1 bridge is used read-only).
- `JGS_V2_WRITE_SECRET` set to the v2 bridge write secret; every v2 write, including enabling writes and batch commits, is rejected without it.
---
## What gets migrated
| v1 construct | v2 action | Tools |
|---|---|---|
| Package | Package, same tree position | `mcp__jgs-sysmlv2__create_package` |
| Block (class) | PartDefinition | `mcp__jgs-sysmlv2__create_part_def` |
| Block instance / part property | PartUsage under the mapped v2 owner, typed to its mapped PartDefinition | `mcp__jgs-sysmlv2__create_part_usage`, `mcp__jgs-sysmlv2__set_type` |
| Requirement | RequirementDefinition + RequirementUsage | `mcp__jgs-sysmlv2__create_requirement_def`, `mcp__jgs-sysmlv2__create_requirement_usage`, `mcp__jgs-sysmlv2__set_type` |
| Requirement text | Set on the requirement usage | `mcp__jgs-sysmlv2__set_requirement_text` |
| Requirement ID | Re-applied verbatim on the requirement usage | `mcp__jgs-sysmlv2__set_req_id` |
| Every migrated element except requirement usages (packages, part definitions, requirement definitions) | Traceability line in documentation | `mcp__jgs-sysmlv2__set_documentation` |
| Ports, connections, interfaces, attributes, item defs, constraints, stereotypes | `skipped-unsupported`: counted, reported, never created | none |
## Rules
- **ID map.** Keep a running v1→v2 ID map. Seed it with `map[v1 root id] = v2 target package ID` before the first create. It grows on every create and on every skipped-existing find (record the found v2 ID). Every create passes the mapped v2 ID of the v1 parent as `parent_id` (mapped-parent, never guessed).
- **Unmapped parent means skip.** Any in-scope element whose mapped v2 parent is missing (its v1 owner is out of scope, `skipped-collision`, or `failed`) is recorded as skipped with that cause and is never created; never guess a `parent_id`. This includes part usages whose typed block never entered the ID map.
- **Requirement linkage.** Each v1 requirement produces one RequirementDefinition and one RequirementUsage. The definition goes under the mapped owning package (for a requirement nested under another requirement, the nearest ancestor package in the v1 walk, via the ID map). The usage goes under the mapped v2 ID of the parent requirement's usage (nested) or the mapped package (top-level), then `set_type(usage_id, definition_id)`. The ID map records both `map[def:<v1 id>]` and `map[usage:<v1 id>]`; child requirements parent to the `usage:` entry.
- **Documentation.** Every migrated element except requirement usages gets `set_documentation` with one line: `Migrated from SysML v1 element <v1 element id> (<v1 name>)`. Requirement usages are exempt: `set_requirement_text` replaces documentation, so their documentation IS the v1 text; the requirement's traceability line lives on its definition.
- **Status taxonomy.** `created`: the element was created and every post-create call for it (`set_type`, `set_documentation`, and for requirement usages `set_req_id` / `set_requirement_text`) succeeded. `skipped-existing`: a pre-existing v2 element already matches the qualified name under the target parent; record the found v2 ID, create nothing. `skipped-collision`: two or more v1 siblings under one v1 parent share a name; skip all of them, the user resolves names in v1. `skipped-unsupported`: the construct is in the out-of-scope set; no create attempted. `failed`: a bridge call errored.
- **Repair points.** `set_req_id`, `set_requirement_text`, and `set_type` replace values, so they are safe to re-apply. On a skipped-existing requirement usage, re-apply its ID and text; on any skipped-existing usage, re-apply `set_type` to the mapped definition. An interrupted run heals on the next run.
- **Approval gate.** No v2 write tool is called before the user approves the migration plan in Step 3. There is no batch mode that skips this.
---
## Step 1: Preflight
Call `mcp__jgs-sysmlv1__ping` and `mcp__jgs-sysmlv2__ping`. Either fails: stop with the error table.
Confirm the v2 write secret is available (`JGS_V2_WRITE_SECRET`). State to the user: "Writes target the v2 bridge and require the PRO tier; the run will call enable_writes with the write secret after plan approval."
## Step 2: Read the v1 model (read-only)
Resolve the root: `mcp__jgs-sysmlv1__get_root_package`, or `mcp__jgs-sysmlv1__find_by_name` when a `<v1-root-package>` argument was given (zero results: report not found and stop; several: numbered list, user picks; treat exactly-50 as possibly truncated and offer `find_by_qualified_name`).
Walk with `mcp__jgs-sysmlv1__walk_tree` (`root_id`, `max_depth=10`, `max_elements=2000`). If the returned element count equals 2000, warn: "Inventory may be incomplete: walk_tree was truncated at 2000 elements. Re-run scoped to individual packages."
`walk_tree` reports no truncation and `list_children` is unpaged, so verify completeness per package: compare each package's visited child count against `mcp__jgs-sysmlv1__list_children`'s returned count; where they differ, enumerate that package's subtree node by node with `list_children`.
Collect, per element (`mcp__jgs-sysmlv1__get_element` / `mcp__jgs-sysmlv1__describe_element`):
- Packages in tree order.
- Blocks.
- Part properties and instances: owning element, containment depth, and the v1 ID of the block they type (needed for `set_type` on the v2 side).
- Requirements: ID, name, text, owning parent from the containment walk, hierarchy.
Count out-of-scope constructs by type. Never use `search()` for inventory (50-result cap).
## Step 3: Migration plan and approval gate
Build the plan: one row per intended v2 create (v1 ID, v1 name, v2 action, mapped parent path, v2 name), plus the skipped list (`skipped-unsupported`, `skipped-collision`) with reasons. The plan also names the v2 target package (Step 4 resolves it).
Present the plan and this exact prompt:
> "This plan creates N elements in the v2 model '<target>'. Nothing has been written yet. Approve? (yes / no)"
- **yes:** proceed to Step 4.
- **no:** stop. Nothing was written; say so.
## Step 4: Write the v2 model
Resolve the v2 write target first. With `into <v2-target-package>` given as a qualified name: `mcp__jgs-sysmlv2__find_by_qualified_name`; zero matches: stop with the error table; several: numbered list, user picks, plan records the choice. A bare name is resolved with `mcp__jgs-sysmlv2__find_by_name` and the user confirms the single intended package before it is used. With no target given: `mcp__jgs-sysmlv2__get_root_package` (fresh-model migration).
Seed `map[v1 root id] = v2 target package ID`. Call `mcp__jgs-sysmlv2__enable_writes` with the write secret once.
Write in dependency order, one named batch per level (`mcp__jgs-sysmlv2__begin_batch` takes a batch name; `mcp__jgs-sysmlv2__commit_batch(batch_id)` commits it):
1. Root target package: only when the resolved target is a fresh model root that does not exist yet (the target resolution at the start of this step determines which case applies); skip this level when migrating into an existing package.
2. Subpackages (walk order).
3. Part definitions.
4. Part usages, ordered by containment depth (a usage under another usage comes after its owner). After each create, `mcp__jgs-sysmlv2__set_type(usage_id, mapped PartDefinition ID)`.
5. Requirement definitions (under the mapped owning package).
6. Requirement usages (nested: under the mapped parent requirement's usage). After each create: `set_type(usage_id, definition_id)`, `mcp__jgs-sysmlv2__set_requirement_text(usage_id, v1 text)`, `mcp__jgs-sysmlv2__set_req_id(usage_id, v1 ID)`.
**Find-before-create, every element:** `mcp__jgs-sysmlv2__find_by_name` is project-wide (paged, 200 default; it has no parent filter). Call it with the element name and match client-side on qualified name within the target parent, or call `mcp__jgs-sysmlv2__find_by_qualified_name` (compose the qualified name from the mapped parent path plus the element name). A match means `skipped-existing`: record the found v2 ID in the ID map and apply the repair-point rule (re-apply `set_req_id` / `set_requirement_text` on requirement usages, `set_type` on usages). Never create a duplicate.
**Documentation:** after every successful create except requirement usages, `mcp__jgs-sysmlv2__set_documentation(element_id, "Migrated from SysML v1 element <v1 element id> (<v1 name>)")`. Requirement definitions also get this line.
Pause at a checkpoint prompt between levels: "Level complete: N created, M skipped. Continue? (y/n)". On n: stop; the manifest records what was completed.
## Step 5: Verify
Re-query created elements with `find_by_qualified_name` (or `find_by_name` + client-side qualified-name match). Every approved plan row must end in exactly one terminal status: `created`, `skipped-existing`, `skipped-unsupported`, `skipped-collision`, or `failed`; the five together must cover every row. For each requirement usage, read the element detail back with `mcp__jgs-sysmlv2__get_element` and confirm its requirement ID echoes the v1 ID. Report any mismatch as `failed`.
## Step 6: Migration manifest and teardown
Call `mcp__jgs-sysmlv2__disable_writes`. Then output:
```markdown
## v1→v2 Migration Manifest: [v1 root] into [v2 target]
*Generated: [date]*
### Summary
- [n] created, [n] skipped-existing, [n] skipped-unsupported, [n] skipped-collision, [n] failed
- ID map coverage: [n] of [n] in-scope v1 elements mapped
### Created
| v1 ID | v1 name | v2 ID | v2 name |
|-------|---------|-------|---------|
| ... | | | |
### Skipped
| Status | v1 ID | v1 name | Cause / found v2 ID |
|--------|-------|---------|---------------------|
| ... | | | |
### Next steps
Run /jgs-v1-cross-model to verify requirement coverage against the new v2 model.
```
Offer to write the manifest to a file (agent filesystem tools only).
---
## Error handling
| Symptom | Cause | Recovery |
|---------|-------|----------|
| Ping fails on either bridge | Bridge not running or wrong port | Stop; fix the bridge; re-run (safe: existing elements are skipped) |
| 403 `tier-denied` on v2 writes | Session tier below WRITE | Stop writes; check the PRO licence and the `enable_writes` secret |
| Named v2 target not found (or ambiguous bare name) | `into` argument wrong or too vague | Stop before `enable_writes`; nothing written; user corrects the argument and re-runs |
| Duplicate-name v1 siblings | Same-name elements under one v1 parent | Skip all of them as `skipped-collision`; report in manifest; user resolves names in v1 |
| Mid-batch failure | Bridge error during a level | Partial writes of the failed level may persist; do NOT delete to unwind. Commit completed levels, record failed rows, re-run after the fix: re-run skips existing and repairs interrupted elements |
| `find_by_name` truncated | Over 200 matches project-wide | Page with `offset`, or use `find_by_qualified_name` for the exact element |
## Common Mistakes
| Mistake | Fix |
|---------|-----|
| Calling any v1 bridge write tool, or `enable_writes` on v1 | This skill is read-only on v1; writes happen only through `mcp__jgs-sysmlv2__*` after approval |
| Using `set_documentation` on a requirement usage | `set_requirement_text` replaces documentation; the two clobber each other; requirement usages get text + ID only, definitions get the traceability line |
| Treating `find_by_name` results as parent-scoped | It is project-wide and paged at 200; match qualified names client-side or use `find_by_qualified_name` |
| Guessing a v2 parent instead of using the ID map | Every `parent_id` comes from the map; skipped-existing finds update the map |
| Creating under a name that already exists | Find-before-create is mandatory on every element; existing means `skipped-existing` + repair, never a second create |
| Writing before plan approval | The Step 3 gate is unconditional |
GitHubで見る