Skip to main content

migrate

[UDS] Guide systematic code migration, framework upgrades, and technology modernization. Use when: planning a framework or major-version upgrade, assessing migration risk, capturing contract-test fixtures before an API migration. Not for: in-place improvement that keeps the same framework — use /refactor; database schema design — use /database. Keywords: migration, framework upgrade, modernization, breaking change, dependency upgrade, 遷移, 升級, 技術現代化.

Source facts

Repository
AsiaOstrich/universal-dev-standards
Last source activity
August 17, 2026 at 06:20
Detected SKILL.md language
Mixed languages
Stars
80
Forks
14

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
migrate
scope
universal
description
[UDS] Guide systematic code migration, framework upgrades, and technology modernization. Use when: planning a framework or major-version upgrade, assessing migration risk, capturing contract-test fixtures before an API migration. Not for: in-place improvement that keeps the same framework — use /refactor; database schema design — use /database. Keywords: migration, framework upgrade, modernization, breaking change, dependency upgrade, 遷移, 升級, 技術現代化.
allowed-tools
Read, Grep, Glob, Bash(npm:*, git:*)
argument-hint
[migration target or framework | 遷移目標或框架]
# Migration Assistant | 遷移助手 Guide systematic code migration, framework upgrades, and technology modernization. 引導系統性程式碼遷移、框架升級與技術現代化。 ## Usage | 使用方式 | Command | Purpose | 用途 | |---------|---------|------| | `/migrate` | Start interactive migration guide | 啟動互動式遷移引導 | | `/migrate --assess` | Risk assessment only | 僅風險評估 | | `/migrate "Vue 2 to 3"` | Guide specific migration | 引導特定遷移 | | `/migrate --deps` | Dependency upgrade analysis | 依賴升級分析 | | `/migrate --rollback` | Plan rollback strategy | 規劃回滾策略 | ## Migration Types | 遷移類型 | Type | Examples | Risk | 風險 | |------|----------|------|------| | **Framework Upgrade** | React 17→18, Vue 2→3, Angular 15→17 | Medium-High | 中高 | | **Language Migration** | JS→TS, Python 2→3, Java 8→17 | High | 高 | | **API Version** | REST v1→v2, GraphQL schema update | Medium | 中 | | **Database Migration** | MySQL→PostgreSQL, SQL→NoSQL | Very High | 極高 | | **Build Tool** | Webpack→Vite, Grunt→ESBuild | Low-Medium | 低中 | | **Package Manager** | npm→pnpm, pip→poetry | Low | 低 | ## Risk Assessment Matrix | 風險評估矩陣 | | Low Impact | Medium Impact | High Impact | |---|-----------|---------------|-------------| | **Low Complexity** | Safe (proceed) | Caution | Plan carefully | | **Medium Complexity** | Caution | Plan + test | Staged rollout | | **High Complexity** | Plan + test | Staged rollout | Full SDD spec | | | 低影響 | 中影響 | 高影響 | |---|--------|--------|--------| | **低複雜度** | 安全(直接進行) | 謹慎 | 仔細規劃 | | **中複雜度** | 謹慎 | 規劃 + 測試 | 分階段發布 | | **高複雜度** | 規劃 + 測試 | 分階段發布 | 完整 SDD 規格 | ## Workflow | 工作流程 1. **ASSESS** - Evaluate current state, identify breaking changes 2. **PLAN** - Create migration checklist with dependencies 3. **PREPARE** - Set up codemods, compatibility layers, feature flags 4. **MIGRATE** - Execute migration in phases with tests 5. **VERIFY** - Run full test suite, check for regressions 6. **CLEANUP** - Remove compatibility shims, old dependencies --- 1. **評估** - 評估現狀、識別破壞性變更 2. **規劃** - 建立含依賴關係的遷移清單 3. **準備** - 設定 codemods、相容層、功能旗標 4. **遷移** - 分階段執行遷移並測試 5. **驗證** - 執行完整測試套件、檢查回歸 6. **清理** - 移除相容層、舊依賴 ## API Migration Contract Tests | API 遷移合約測試 When migrating an API endpoint from one tech stack to another (PHP → .NET, Express → Spring, Python → Go), unit tests on the **new** implementation verify against the **new DTO** — they cannot catch fields that the legacy returned but the new implementation forgot. Missing fields, renamed fields, type drift, and top-level vs nested placement drift will silently survive into production and break the existing frontend that still expects the legacy shape. This is **NOT** caught by unit tests, integration tests, or code review alone. A real 2026-05-24 production incident shipped with 67/67 green tests and was discovered by the customer. 當 API endpoint 從一個技術棧遷至另一個(PHP → .NET、Express → Spring 等),對**新**實作的單元測試只驗證**新 DTO**——無法捕捉「舊版有但新版漏掉」「欄位 rename」「型別漂移」「頂層 vs nested 層級漂移」等問題。這些缺陷會靜默流入生產,導致前端(仍預期舊版回應 shape)失靈。 **僅靠單元測試、整合測試或 code review 無法防止**。2026-05-24 真實 PROD 事故:67/67 測試全綠流入正式環境,由客戶發現缺漏。 ### Mandatory rule | 強制規則 Every migrated API endpoint **MUST** ship with at least one contract test that compares the new implementation's response against a fixture captured from the legacy implementation. Structural equivalence (keys, types, placement), not value equality, is verified. 每個被遷移的 API endpoint **必須**至少有一份 contract test,比對新實作的 response 與從 legacy 捕獲的 fixture。驗證的是結構性等價(keys、type、層級位置),而非值等價。 ### Fixture capture protocol | Fixture 捕獲協議 **While legacy is still running (typical migration window) | Legacy 仍運行(典型遷移窗口):** ```bash # 1. Capture ≥3 representative inputs (happy path, edge case, empty result) curl -X POST $LEGACY_BASE/endpoint -d @input1.json \ > tests/fixtures/migration/endpoint/scenario1.json curl -X POST $LEGACY_BASE/endpoint -d @input2_empty.json \ > tests/fixtures/migration/endpoint/scenario2_empty.json curl -X POST $LEGACY_BASE/endpoint -d @input3_edge.json \ > tests/fixtures/migration/endpoint/scenario3_edge.json # 2. Scrub PII and volatile values (timestamps, generated IDs) jq 'walk(if type == "string" and test("@") then "redacted@example.com" else . end)' \ tests/fixtures/migration/endpoint/scenario1.json > tmp && mv tmp ... # 3. Commit fixtures git add tests/fixtures/migration/endpoint/ ``` **When legacy is already retired but source-readable | Legacy 已退役但 source 可讀:** - Trace through legacy source code, manually construct the expected response shape - Document each field's origin (SQL column, computed expression, hardcoded) in a sibling `.notes.md` file - 從 legacy source code 推導預期 response shape;每個欄位來源(SQL 欄位 / 計算式 / hardcoded)記錄於同位置 `.notes.md` ### Contract test template **C# / xUnit:** ```csharp [Theory] [InlineData("scenario1")] [InlineData("scenario2_empty")] [InlineData("scenario3_edge")] public async Task Endpoint_ResponseShape_MatchesLegacyFixture(string scenario) { var fixture = LoadFixture($"migration/endpoint/{scenario}"); var response = await CallNewImpl(fixture.Input); // StructuralEquivalence checks keys + types + placement, ignores values StructuralEquivalence.Assert(response, fixture.ExpectedShape); } ``` **TypeScript / Jest:** ```typescript import { structuralEquivalence } from "./test-utils/structural-equivalence"; describe.each([ ["scenario1"], ["scenario2_empty"], ["scenario3_edge"], ])("Endpoint response shape vs legacy fixture (%s)", (scenario) => { test("matches", async () => { const fixture = loadFixture(`migration/endpoint/${scenario}.json`); const response = await callNewImpl(fixture.input); structuralEquivalence(response, fixture.expectedShape); }); }); ``` `structuralEquivalence` / `StructuralEquivalence.Assert` rule: same set of keys at each level (no missing, no extra unless explicitly opted in), same primitive type per key, same placement (top-level vs nested). Values can differ (timestamps, IDs); types and structure cannot. ### Field-by-field migration audit checklist Before merging any migrated endpoint: - [ ] All legacy response fields mapped to new DTO (no silent drops) - [ ] Naming preserved where possible (avoid `TotalX` rename that drops the "per-member" semantic) - [ ] Top-level vs nested placement preserved - [ ] Type compatibility verified (string→int conversions explicit, not coincidental) - [ ] Error path return codes match legacy (`509` not `506`; `404` not `400`) - [ ] Contract test fixture committed under `tests/fixtures/migration/` - [ ] Cross-link to [contract-test-assistant](../contract-test-assistant/SKILL.md) for ongoing consumer-side verification 合併前必確認: - [ ] 所有 legacy response 欄位 mapping 至新 DTO(無 silent drop) - [ ] 命名儘量保留 - [ ] 頂層 vs nested 層級保留 - [ ] 型別相容性已明確驗證 - [ ] Error path return code 與 legacy 一致 - [ ] Contract test fixture 已 commit - [ ] Cross-link 至 contract-test-assistant 做持續消費端驗證 ## Post-Cutover Data Reconciliation | Cutover 後生產資料對帳 > **Implements**: XSPEC-284 R2 (axis ③ persisted-data semantics) / closes UDS issue [#134](https://github.com/AsiaOstrich/universal-dev-standards/issues/134). Contract tests (above) and `behavior-snapshot` catch **interface** divergence but are blind to **persisted-data semantic** divergence. Two blind spots both share: 1. **You can only assert what you thought to enumerate.** The rules that actually ship broken are the *implicit, undocumented* ones — especially the semantics of a persisted field (when is it non-zero? when is it overwritten?). Nobody writes a scenario for a rule they don't know exists. 2. **Per-request parity ≠ data-at-rest parity.** A field written by an **asynchronous** process (delivery-receipt sync, settlement job, status reconciler) against a live external provider is not a deterministic request you can replay. Its correctness only emerges in **aggregate over real production volume**, not in a single happy-path snapshot. Contract test 與 `behavior-snapshot`只能捕捉**介面**分歧,對**持久化資料語義**分歧視而不見。兩者共有兩個盲區:(1) 你只能驗證你想得到要列舉的規則——真正出包的永遠是沒人寫下來的隱含規則(某欄位何時非零、何時被覆寫);(2) per-request parity ≠ data-at-rest parity——由**非同步**程序(DR sync、結算批次、狀態對帳器)對 live 外部供應商寫入的欄位,不是可重放的確定性請求,其正確性只在**真實生產量的聚合**中浮現。 ### Failure fingerprint | 事故指紋(#134) 某企業 SMS 平台 PHP→.NET 重寫:每筆金額由**非同步** DR sync 覆寫(`record.Cost = gatewayDr.Cost`)。legacy 對 carrier-failure 仍計費,rewrite 寫 gateway 回報的 `0` → cutover 邊界兩側同一失敗狀態的金額分歧。**所有既有 gate 全部漏接**(response shape 相同 → contract test 過;無人 curated「失敗仍計費」場景;欄位由背景作業對 live gateway 寫入 → 不可重放)。最後靠 ops 跑生產 `SUM(cost) GROUP BY status, day` 跨邊界彙總才發現。**單日抽樣甚至誤判「失敗不計費=正常」**——只有跨 cutover 邊界的多週聚合才揭露真相。 ### Mandatory rule | 強制規則 When a migration loads legacy data into the **same store** as new data, the old/new boundary is a **free differential oracle**. For each business-critical persisted field you **MUST**: - Define **aggregate reconciliation invariants** comparing the distribution of **legacy-origin vs new-origin** rows along key dimensions (e.g. `SUM(money) / COUNT(*) GROUP BY status, period`). - Run them **on a schedule against production** and alert when divergence exceeds a declared tolerance. - Investigate over a **multi-week window spanning the cutover** — never a single-day sample (a sampled check can confirm a *wrong* conclusion). 當 migration 將 legacy 資料載入與 new 相同的**儲存**,新舊邊界即是**免費差分神諭**。對每個 business-critical 持久化欄位**必須**:定義聚合對帳不變量(比對 legacy-origin vs new-origin 列沿關鍵維度的分佈)、對生產**排程執行**並於分歧超過宣告容差時告警、以跨 cutover 的**多週窗口**調查(切忌單日抽樣,抽樣可能坐實錯誤結論)。 ### Cutover-boundary reconciliation SQL template | 對帳 SQL 模板 ```sql -- Reconcile a money/state field across the migration cutover boundary. SELECT status, SUM(CASE WHEN created < @cutover THEN 1 ELSE 0 END) AS legacy_rows, SUM(CASE WHEN created < @cutover AND money_field > 0 THEN 1 ELSE 0 END) AS legacy_nonzero, SUM(CASE WHEN created >= @cutover THEN 1 ELSE 0 END) AS new_rows, SUM(CASE WHEN created >= @cutover AND money_field > 0 THEN 1 ELSE 0 END) AS new_nonzero FROM records GROUP BY status; -- Invariant: nonzero-ratio per status must not differ across the boundary beyond tolerance. ``` ### Tolerance & alerting guidance | 容差與告警指引 | Aspect | Guidance | 指引 | |--------|----------|------| | **Invariant type** | nonzero-ratio / `SUM` / `COUNT` / `DISTINCT` / checksum per `GROUP BY status, period` | 每維度的非零比率 / 聚合相等 / checksum | | **Tolerance** | Declare per field; 0% for hard accounting invariants, a small ε only for known legitimate drift (e.g. rounding) | 逐欄宣告;硬會計不變量 0%,僅已知合法漂移容許小 ε | | **Window** | Multi-week, spanning cutover; bucket by `period` to localise the boundary | 多週、橫跨 cutover;以 `period` 分桶定位邊界 | | **Schedule** | Standing post-cutover cron (daily) until boundary rows age out of active reporting | post-cutover 排程(每日)直到邊界列退出活躍報表 | | **Alert** | Page on divergence > tolerance; route via `observability-assistant` alert rules | 分歧超過容差即告警;經 `observability-assistant` 告警規則路由 | ### Gate 0 — Implicit-rule capture for persisted business fields | 隱含規則擷取 Before migrating any feature that writes a persisted business field, **explicitly answer for each such field** three questions, then lock the answer as a snapshot scenario **or** a reconciliation invariant: > 1. **When is this value SET?** 何時設值? > 2. **When is it OVERWRITTEN?** 何時被覆寫?(尤其非同步路徑) > 3. **When is it ZEROED / nulled?** 何時歸零/清空? **High-risk implicit-rule checklist** — empirically recurring fingerprints | 高風險隱含規則檢查清單(經驗反覆出現的指紋): - [ ] **Billing / charge semantics** — charged on submit vs on delivery; refund-on-failure? | 計費語義(提交時計費 vs 送達時計費;失敗退費?) - [ ] **Enum / status-code mapping** — every legacy code mapped; "success set" defined identically | 列舉/狀態碼對映(每個 legacy 碼都對映;「成功集合」定義一致) - [ ] **Null / empty handling** — empty string vs null vs absent; default-on-missing | 空值處理(空字串 vs null vs 不存在;缺值預設) - [ ] **Field-name casing / serialization** — snake_case vs camelCase binding | 欄位命名大小寫/序列化(snake_case vs camelCase 綁定) - [ ] **Timezone** — stored UTC vs local; report boundaries | 時區(存 UTC vs local;報表邊界) - [ ] **Rounding / type coercion** — `"2.00"` (text) parsed as int → dropped to 0 | 四捨五入/型別強轉(`"2.00"` 文字被當 int 解析 → 掉成 0) ### 3-gate positioning | 3-gate 定位表 Make the boundary between gates explicit so each axis has an owner and nothing falls into the seam: | Gate | Scope | When | 範圍 / 時機 | |------|-------|------|------| | [`behavior-snapshot`](../../core/behavior-snapshot.md) | per-request, **curated** scenarios | pre-UAT CI | per-request、人工 curated 場景;pre-UAT CI | | Contract tests (above / #112) | response **shape** (keys / types / placement) | unit / integration | response shape(keys/型別/層級);單元/整合 | | **This section (#134)** | **aggregate, data-at-rest semantics of async-written fields, over real volume** | **post-cutover, scheduled, production** | **非同步寫入欄位的聚合、靜態資料語義,跨真實量;post-cutover 排程生產** | > Cross-ref: [`behavior-snapshot`](../../core/behavior-snapshot.md) (curated golden masters), [`observability-assistant`](../observability-assistant/SKILL.md) (reconciliation schedule + alert templates). ## Background Job / Side-Effect Completeness | 背景作業/副作用完整性 > **Implements**: XSPEC-284 R3 (axis ⑤). Migration inventories (`/vo-inventory`, XSPEC-200 `type:background_job`) and Devil's-Advocate grep (XSPEC-201 Step 4) **annotate** cron / queue consumers / scheduled batches / webhooks / mail-send points — but annotation alone proves nothing. A background job can be listed in the manifest, exist in code, and still **never actually run** in the new system. 遷移清單與副作用 grep 只是**標注**背景作業——標注本身不證明任何事。背景作業可能在 manifest 列出、程式碼存在,卻在新系統**從未真正執行**。 ### Mandatory rule | 強制規則 For every background side-effect carried over from legacy, verify **two** things — annotation is not enough: | Check | Pre-flight | Post-cutover | |-------|-----------|--------------| | **(a) Exists** — the cron / queue consumer / webhook / mail point is implemented in the new system | source grep + registration check | — |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub