Skip to main content

Agent Skills Framework Extension

Framework Migration Patterns Skill

When to Use This Skill

Use this skill when implementing framework migration patterns patterns in your codebase.

How to Use This Skill

  1. Review the patterns and examples below
  2. Apply the relevant patterns to your implementation
  3. Follow the best practices outlined in this skill

Production-grade framework upgrades, breaking change handling, and automated migrations.

Core Capabilities

  1. Version Analysis - Breaking change detection, deprecation tracking
  2. Automated Codemods - AST transformations for code updates
  3. Incremental Migration - Gradual rollout strategies
  4. Testing Strategies - Regression prevention during migration
  5. Rollback Plans - Safe migration with fallback options

Breaking Change Analysis

// tools/breaking_change_analyzer.rs
use semver::Version;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct BreakingChange {
pub version: Version,
pub description: String,
pub migration_guide: String,
pub affected_apis: Vec<String>,
pub automated_fix: Option<String>,
}

pub struct MigrationAnalyzer {
current_version: Version,
target_version: Version,
breaking_changes: Vec<BreakingChange>,
}

impl MigrationAnalyzer {
pub fn analyze(&self) -> MigrationPlan {
let applicable_changes: Vec<_> = self.breaking_changes
.iter()
.filter(|change| {
change.version > self.current_version &&
change.version <= self.target_version
})
.collect();

let total_changes = applicable_changes.len();
let automated_fixes = applicable_changes.iter()
.filter(|c| c.automated_fix.is_some())
.count();

MigrationPlan {
from_version: self.current_version.clone(),
to_version: self.target_version.clone(),
breaking_changes: applicable_changes.into_iter().cloned().collect(),
total_changes,
automated_fixes,
manual_changes: total_changes - automated_fixes,
estimated_effort_hours: self.estimate_effort(total_changes, automated_fixes),
}
}

fn estimate_effort(&self, total: usize, automated: usize) -> u32 {
let manual = total - automated;
(automated * 2 + manual * 8) as u32
}
}

#[derive(Debug)]
pub struct MigrationPlan {
pub from_version: Version,
pub to_version: Version,
pub breaking_changes: Vec<BreakingChange>,
pub total_changes: usize,
pub automated_fixes: usize,
pub manual_changes: usize,
pub estimated_effort_hours: u32,
}

Automated Codemod (JavaScript)

// codemods/upgrade-react-18.js
module.exports = function(fileInfo, api) {
const j = api.jscodeshift;
const root = j(fileInfo.source);

// Transform ReactDOM.render to createRoot
root
.find(j.CallExpression, {
callee: {
object: { name: 'ReactDOM' },
property: { name: 'render' }
}
})
.forEach(path => {
const [element, container] = path.value.arguments;

// Replace with createRoot API
const replacement = j.callExpression(
j.memberExpression(
j.callExpression(
j.memberExpression(
j.identifier('ReactDOM'),
j.identifier('createRoot')
),
[container]
),
j.identifier('render')
),
[element]
);

j(path).replaceWith(replacement);
});

// Update import statements
root
.find(j.ImportDeclaration, {
source: { value: 'react-dom' }
})
.forEach(path => {
const createRootSpecifier = j.importSpecifier(
j.identifier('createRoot')
);

if (!path.value.specifiers.some(s => s.imported?.name === 'createRoot')) {
path.value.specifiers.push(createRootSpecifier);
}
});

return root.toSource({ quote: 'single' });
};

Incremental Migration Strategy

// src/migration/incremental.rs
use std::collections::HashMap;

pub enum FeatureFlag {
UseNewApi,
UseOldApi,
}

pub struct FeatureFlagManager {
flags: HashMap<String, bool>,
}

impl FeatureFlagManager {
pub fn is_enabled(&self, flag: &str, user_id: &str) -> bool {
// Gradual rollout: 10% → 50% → 100%
let rollout_percentage = self.flags.get(flag).map(|_| 50).unwrap_or(0);

let hash = self.hash_user_id(user_id);
hash % 100 < rollout_percentage
}

fn hash_user_id(&self, user_id: &str) -> u32 {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

let mut hasher = DefaultHasher::new();
user_id.hash(&mut hasher);
(hasher.finish() % 100) as u32
}
}

// Example: Gradual API migration
pub async fn fetch_user_data(
user_id: &str,
feature_flags: &FeatureFlagManager
) -> Result<UserData, Error> {
if feature_flags.is_enabled("use_new_api", user_id) {
// New implementation
new_api::fetch_user(user_id).await
} else {
// Old implementation (fallback)
old_api::fetch_user(user_id).await
}
}

Migration Testing Strategy

// tests/migration_tests.rs
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_backward_compatibility() {
// Test that new code can read old data format
let old_data = r#"{"version": 1, "name": "test"}"#;
let parsed: UserData = serde_json::from_str(old_data).unwrap();

assert_eq!(parsed.name, "test");
assert_eq!(parsed.version, Some(1));
}

#[test]
fn test_forward_compatibility() {
// Test that old code can ignore new fields
let new_data = r#"{"version": 2, "name": "test", "new_field": "value"}"#;
let parsed: UserDataV1 = serde_json::from_str(new_data).unwrap();

// Old struct should ignore unknown fields
assert_eq!(parsed.name, "test");
}

#[tokio::test]
async fn test_dual_write() {
// Write to both old and new storage
let data = UserData::new("test");

old_storage::save(&data).await.unwrap();
new_storage::save(&data).await.unwrap();

// Verify consistency
let old_read = old_storage::load("test").await.unwrap();
let new_read = new_storage::load("test").await.unwrap();

assert_eq!(old_read, new_read);
}
}

Rollback Strategy

# .github/workflows/safe-migration.yml
name: Safe Migration Deployment

on:
push:
branches: [migration/v2]

jobs:
deploy-with-rollback:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Deploy new version (canary)
run: |
kubectl set image deployment/myapp \
myapp=myapp:v2 \
-n production \
--record

- name: Monitor metrics
run: |
# Wait 5 minutes and check error rates
sleep 300
./scripts/check-metrics.sh

- name: Automatic rollback on failure
if: failure()
run: |
kubectl rollout undo deployment/myapp -n production
echo "Rollback triggered due to metrics failure"

Usage Examples

Analyze Migration

Apply framework-migration-patterns skill to analyze breaking changes from React 17 to React 18

Automated Codemod

Apply framework-migration-patterns skill to create codemod for API migration

Incremental Rollout

Apply framework-migration-patterns skill to implement gradual migration with feature flags

Success Output

When this skill is successfully applied, you MUST output:

✅ SKILL COMPLETE: framework-migration-patterns

Completed:
- [x] Breaking change analysis complete with migration plan
- [x] Automated codemods created for transformable changes
- [x] Incremental migration strategy implemented with feature flags
- [x] Testing strategy executed with backward compatibility verified
- [x] Rollback plan documented and tested

Outputs:
- Migration plan: [file path] (from_version → to_version, effort estimate)
- Codemods: [file paths] (automated transformations)
- Feature flag config: [file path] (gradual rollout)
- Test suite: [file path] (compatibility tests)
- Rollback procedure: [file path]

Completion Checklist

Before marking this skill as complete, verify:

  • Breaking changes identified between current and target version
  • Migration plan created with effort estimates (automated vs manual)
  • Codemods written and tested for automated transformations
  • Feature flags implemented for gradual rollout
  • Backward compatibility tests passing
  • Forward compatibility tests passing (old code ignores new fields)
  • Dual-write strategy tested if applicable (write to old + new)
  • Rollback plan documented with automatic rollback triggers
  • Monitoring and metrics configured for migration health

Failure Indicators

This skill has FAILED if:

  • ❌ Migration deployed without analysis of breaking changes
  • ❌ Codemods produce incorrect transformations or break code
  • ❌ All-at-once migration attempted without gradual rollout
  • ❌ Backward compatibility broken (old data can't be read)
  • ❌ Forward compatibility broken (new fields crash old code)
  • ❌ No rollback plan or rollback fails when executed
  • ❌ Migration causes production outage or data loss
  • ❌ Manual changes required but not documented in migration guide

When NOT to Use

Do NOT use this skill when:

  • Patch version upgrade with no breaking changes (standard dependency update)
  • Framework not actually changing (configuration changes only)
  • Migration scope too small to justify automation overhead (use manual update)
  • Deprecated framework with no migration path (requires full rewrite, not migration)
  • Internal tool with single developer (overhead > benefit)

Use alternatives:

  • For patch updates: Standard npm update or cargo update
  • For full rewrites: greenfield-architecture skill
  • For small manual changes: Direct code changes with review
  • For config-only changes: Configuration management tools

Anti-Patterns (Avoid)

Anti-PatternProblemSolution
Big-bang migrationAll-at-once update causes wide outageIncremental migration with feature flags
No automated codemodsMassive manual effort, error-proneWrite AST transformations for repetitive changes
Skipping compatibility testsRuntime failures in productionTest backward and forward compatibility
No rollback planStuck on broken versionAlways have automated rollback procedure
Ignoring deprecation warningsSudden breaking changesTrack and address deprecations proactively
Over-automating edge casesCodemod creates bugsAutomate common patterns, flag edge cases for manual review
No gradual rolloutCan't detect issues earlyUse feature flags for 10% → 50% → 100% rollout
Missing migration guideManual steps undocumentedCreate comprehensive guide for non-automated changes

Principles

This skill embodies:

  • #1 Recycle → Extend → Re-Use → Create - Leverage existing migration tools (codemods, feature flags)
  • #2 First Principles - Understand WHY framework changed before migrating
  • #8 No Assumptions - Verify compatibility, don't assume migration succeeded
  • #9 Research When in Doubt - Check official migration guides and changelogs
  • #11 Resilience and Robustness - Rollback plans and gradual rollout ensure stability

Full Standard: CODITECT-STANDARD-AUTOMATION.md

Migration Readiness Checklist

Pre-migration assessment to ensure successful upgrade:

CategoryCheckStatusNotes
AnalysisBreaking changes documentedReview CHANGELOG, migration guide
Deprecation warnings addressedRun build, check warnings
API changes mapped to codebasegrep for deprecated APIs
TestingTest coverage >80%Run coverage report
Backward compatibility tests existOld data format → new code
Forward compatibility tests existNew data format → old code
AutomationCodemods written for repetitive changesjscodeshift, ast-grep
CI/CD pipeline updatedNew build commands, deps
Feature flags configuredGradual rollout ready
RollbackRollback procedure documentedkubectl rollout undo, etc
Rollback tested in stagingVerify rollback works
Monitoring alerts configuredError rate, latency thresholds
TeamTeam trained on new APIsWorkshop, documentation review
Migration schedule communicatedStakeholder alignment

Go/No-Go Decision:

All ☐ checked → ✅ Proceed with migration
Any ☐ unchecked → ⚠️ Address before proceeding

Effort Estimation Formula:

Hours = (automated_changes × 0.5) + (manual_changes × 4) + (testing × 8) + (rollback_prep × 4)

Integration Points

  • cicd-automation-patterns - Automated migration deployment
  • rust-development-patterns - Rust-specific migrations
  • rust-qa-patterns - Migration testing