migração-dotnet-8-para-10

Planejar e realizar a migração de um repositório ou monorepo do .NET 8 para o .NET 10, de forma segura e em etapas revisáveis.

O que é migração-dotnet-8-para-10?

Esta skill executa uma ferramenta determinística e independente (`scripts/dmig`) para planejar e realizar a migração de projetos .NET 8 para .NET 10. Ela é projetada para monorepos, onde uma única biblioteca compartilhada pode quebrar vários aplicativos. A análise mapeia todo o repositório, propõe grupos de migração em uma ordem segura e verifica cada alegação com uma linha de base e um experimento descartável em uma worktree git temporária. A implementação é feita um grupo por vez, em uma worktree descartável, com no máximo três reparos predefinidos e uma verificação final. A skill nunca edita o repositório principal, nunca faz commit, push ou pull requests. Ela é indicada para planejar, avaliar, reduzir riscos ou executar a migração de projetos .NET 8 para .NET 10 (ou a última LTS), bem como para responder perguntas sobre o que irá quebrar, a ordem de migração dos projetos ou como dividir uma solução grande em lotes. A ferramenta não possui cliente de rede próprio; tudo sobre pacotes passa pelo `dotnet` e pelos feeds configurados na máquina. A análise também gera um conjunto de notas no Obsidian para facilitar a revisão humana.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/DmytroFlakac/dotnet-migration-skill/tree/HEAD/skill

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Migração .NET 8 → .NET 10

Esta skill executa uma ferramenta determinística e independente (scripts/dmig) e depois explica seus resultados. Sempre analise primeiro; implemente apenas um grupo que a pessoa aprovou a partir dessa análise. O analisador faz as medições; seu trabalho é executá-lo corretamente, ler o que ele encontrou e dizer à pessoa o que significa — sem exagerar nada que não pôde verificar.

Por que a análise vem primeiro

Em um monorepo, um repositório raramente é uma única unidade de migração. Uma biblioteca compartilhada movida para net10.0 quebra todo aplicativo que ainda está em net8.0, e arquivos como global.json ou Directory.Packages.props afetam a todos. Portanto, a análise mapeia todo o repositório, propõe grupos em uma ordem segura e prova suas alegações com uma linha de base e um experimento descartável antes que alguém mude o código real. A implementação acontece depois, um grupo aprovado por vez.

Executar

  1. Escolha uma pasta de saída fora do repositório (a ferramenta recusa uma dentro dele): relatórios, logs, cache de metadados NuGet e a worktree temporária vão todos para lá.

  2. Escolha o dotnet. A ferramenta verifica SDKs e runtimes por conta própria em sua verificação prévia; você só precisa apontá-la para o executável correto. Se a máquina tiver uma raiz dotnet privada (SDK 10 + runtime 8 lado a lado), passe-a com --dotnet ou DMIG_DOTNET. Quando o .NET 8 está instalado em outra pasta dotnet, a ferramenta o encontra nos lugares habituais, ou pega de --dotnet-root <pasta> / DMIG_DOTNET_ROOTS, e o combina com o SDK por meio de links em uma pasta própria (nenhuma instalação é alterada).

  3. Instale as duas bibliotecas se estiverem faltando, a partir do mirror Python da organização: python -m pip install -r requirements.txt (testes: também requirements-dev.txt). Sempre use python -m ...: a pasta Scripts pode não estar no PATH. Nenhum sh, bash ou sed é necessário.

  4. Execute a análise (caminhos do Windows funcionam em PYTHONPATH, --repo e --out, também do Git Bash):

    PYTHONPATH=<dir-skill>/scripts python -m dmig analyze --repo <repo> --out <dir-saida> [--dotnet <caminho>]
    

    Sinalizações úteis: --offline (não sondar os feeds configurados), --no-baseline, --no-experiment, --environment contract.json (serviços de teste externos e ferramentas licenciadas que o ambiente fornece), --request request.json (a solicitação neutra, veja references/contracts.md). Espere aproximadamente um minuto para um repositório pequeno; monorepos grandes levam tanto tempo quanto seu próprio restore + build + test, duas vezes (linha de base e experimento). Execute-o em segundo plano se seu harness permitir, e nunca inicie uma segunda cópia no mesmo repositório ao mesmo tempo. O progresso é uma linha por etapa no stderr ([dmig hh:mm:ss] baseline …); stdout carrega apenas o resumo JSON final, e o log completo de cada comando aparece em <out>/logs/ assim que termina.

    Nada precisa ser instalado: a pasta da skill tem arquivos iniciais, dmig.cmd (Windows) e dmig (Linux/macOS), equivalentes a PYTHONPATH=<dir-skill>/scripts python -m dmig. python -m dmig preflight ... executa apenas a verificação de ambiente (segundos). Em uma máquina nova, execute python -m dmig doctor <repo> primeiro: uma lista de verificação de prontidão em linguagem simples (doctor-report.md, environment-capabilities.json, resultado READY / READY_WITH_LIMITATIONS / BLOCKED).

    Formas abreviadas (os nomes de integração): todo comando recebe o repositório como seu primeiro argumento e usa como padrão --out para <repo>.dmig/<etapa>/ e --plan para <repo>.dmig/analysis/migration-plan.json: dmig analyze <repo> --target net10.0, dmig migrate <repo> --group <id> (= implement), dmig validate <repo> --scope group|repository (--group <id> para um grupo; repository = PHASE_7), dmig rollback <pasta de execução> (limpa a cópia descartável de uma execução e imprime como desfazer seu patch). Cada execução migrate/global/validate também escreve dmig-result.json, o resultado camelCase do contrato. Mirror de pacotes: --package-catalog mirror.json (apenas versões aprovadas são sempre escolhidas; etapas posteriores reutilizam-no).

    Padrões a respeitar: a ferramenta não tem cliente de rede próprio: tudo sobre pacotes passa pelo dotnet e pelos feeds configurados na máquina, que são sondados por padrão (--offline pula isso). O catálogo público apenas com --allow-public-nuget; sem um arquivo de catálogo, as versões dos pacotes são METADATA_UNAVAILABLE (nunca adivinhadas), e um pacote ausente do catálogo é PACKAGE_UNAVAILABLE. Os complementos de framework estão desligados: web (ASP.NET Core), regras EF Core e serviços Windows precisam de --adapters aspnet_core,efcore,windows_service no momento da análise; caso contrário, seus grupos são OUT_OF_SCOPE_ADAPTER_DISABLED. .NET Framework, WPF, WinForms, MAUI, Xamarin e Azure Functions são apenas para relatório (OUT_OF_SCOPE_REPORT_ONLY); grupos net*-windows sem Windows são BLOCKED_PLATFORM. A saída do console é ASCII simples (PASS/WARN/FAIL/BLOCK). Entradas, saídas, status e códigos de saída: docs/integration-contract.md.

  5. Códigos de saída: 0 = análise completa (possivelmente com limitações), 2 = BLOCKED.

Leia os resultados

Leia <out>/response.json primeiro (seu summary tem as contagens), depois <out>/migration-report.md. Ambos têm tamanho limitado — permanecem com alguns KB por maior que seja o repositório e dizem "… e mais N" onde cortam uma lista. Não leia os arquivos grandes inteiros: migration-plan.json, inventory.json, baseline.json, experiment.json e compatibility.json crescem com o repositório. Quando você precisar de um grupo, abra sua nota (abaixo) ou pesquise no JSON por esse group_id. Os logs completos estão em <out>/logs/; abra um apenas quando uma etapa falhou e sua cauda não é suficiente.

Para pessoas: a análise também escreve um conjunto vinculado de notas do Obsidian para <out>/obsidian/<repo> Migração .NET 10/ (ou em uma pasta de cofre com --obsidian-dir <pasta>), construído com o pacote obsreport incluído: 00 Comece aqui (veredito, números-chave, principais 5 correções por impacto), 01 O que vai quebrar (níveis de evidência: confirmado por build/test → encontrado no código → possível, dobrado), 02 Rota (cinco estágios), 03 Mapa (camadas + um Map board.canvas ampliável), 04 Decisões (um registro de decisão cada), 05 FAQ do Revisor, mais uma nota por grupo, regra e biblioteca compartilhada. Aponte a pessoa para a nota inicial em vez de colar seu conteúdo.

Re-renderizar sem reconstruir: após alterações nas regras ou no layout da nota, python -m dmig report --repo <repo> --out <pasta de análise> [--obsidian-dir <pasta>] [--offline] reconstrói a verificação de compatibilidade, comparação de teste, plano, relatório e notas a partir dos resultados salvos em um minuto ou dois, sem restore, build ou teste.

Duas coisas que ajudam ao lê-los:

  • O experimento redireciona todo o repositório para net10.0 simples de uma vez, incluindo bibliotecas compartilhadas que o plano irá multi-target. Isso é intencional: uma execução mostra as falhas net10.0 de cada projeto, e a comparação com a linha de base atribui cada falha a um grupo (uma regressão em um aplicativo causada por uma biblioteca compartilhada aparece como WAITS_FOR_DEPENDENCY_REPAIR).
  • <out>/worktrees/ permanece como uma pasta vazia após a execução (a worktree dentro dela é removida e verificada), e <out>/nuget-cache/ mantém os metadados NuGet para que uma reexecução seja mais rápida. Nenhum é um resíduo no repositório.

Ao relatar:

  • Comece com o status e a ordem dos grupos, depois a prontidão de cada grupo e o porquê. O relatório geralmente é autoexplicativo; abra references/reading-results.md quando um status, valor de prontidão ou descoberta for desconhecido. Um rótulo de prontidão nomeia apenas o principal bloqueador: mencione também as propostas de reparo de cada grupo (por exemplo, uma alteração no Dockerfile) listadas abaixo dele.
  • Separe o que foi verificado do que foi inferido. Um grupo só é READY se o experimento o construiu e testou contra uma linha de base. Diga isso quando os testes foram bloqueados, uma plataforma estava ausente (projetos Windows no Linux) ou um pacote "não está comprovado".
  • Mantenha as falhas pré-existentes separadas. As falhas da linha de base são registradas, nunca contadas como problemas de migração e nunca algo que a migração deva "corrigir".
  • Nomeie a classe de alteração de qualquer coisa proposta: PROJECT_LOCAL, GROUP_SHARED ou REPOSITORY_GLOBAL. Alterações globais (global.json, arquivos Directory.* raiz, NuGet.config, CI) pertencem às fases de todo o repositório, nunca a um único grupo.
  • Cite rollback_verified e changes_persisted. Se o rollback não for verificado, diga isso primeiro e verifique o repositório com git status e git worktree list você mesmo.

Regras que você mantém (e por quê)

references/scope-and-safety.md tem a lista completa. O essencial:

  • Não edite, faça commit, push ou crie pull requests ou itens de trabalho no modo de análise — a pessoa precisa de um repositório intocado e um plano que possa revisar.
  • Não "corrija" nada que a análise encontrar, nem mesmo uma correção óbvia de uma linha; os reparos pertencem ao modo de implementação com seu orçamento de três tentativas e sua verificação final.
  • Não invente fatos de compatibilidade. Se a ferramenta disser "não comprovado" ou "desconhecido", relate isso; se você adicionar conhecimento próprio, rotule-o como seu e sugira como verificá-lo.
  • Correções de vulnerabilidade e atualizações gerais de pacotes estão fora do escopo, mesmo que você as note.

Migrar um grupo aprovado (modo de implementação)

Somente após uma análise, e apenas para um grupo que a pessoa aprovou — nunca como efeito colateral de uma pergunta. Os grupos seguem a ordem do plano; fundação compartilhada primeiro.

PYTHONPATH=<dir-skill>/scripts python -m dmig implement --repo <repo> \
  --plan <saída-análise>/migration-plan.json --group <id_do_grupo> --out <nova pasta fora do repo> \
  [--dotnet <caminho>] [--allow-newer-commit]
  • Ele funciona em uma worktree descartável e retorna <out>/<id_do_grupo>.patch; o repositório nunca é modificado. Aplicar, commitar e entregar o patch é decisão da pessoa (ou de seu adaptador) — mostre a eles o diff e a verificação, não o aplique sem permissão.
  • --allow-newer-commit é para o caso normal em que os patches de grupos anteriores foram aplicados após a análise; os projetos são relidos do repositório. Se muita coisa mudou, reexecute a análise.
  • Projetado para grandes monorepos: cada execução constrói e testa apenas o grupo, tudo que o consome e seus testes (um filtro de solução temporário) e reutiliza uma linha de base em cache quando o código é exatamente o mesmo de uma execução anterior (mesmo hash da árvore git, mesmo dotnet/SDK/runtimes): a linha de base da análise para o primeiro grupo, depois o estado final de cada grupo bem-sucedido após seu patch ser aplicado e commitado. result.json → baseline.source diz se foi reutilizado ou construído e por quê. Use --no-cache ou --no-scope apenas para descartá-los quando algo parecer errado.
  • Código de saída 0 = SUCCESS; 3 = qualquer outra coisa. As linhas de progresso vão para o stderr como no modo de análise. Leia <out>/result.json (status, final_gate, repair_attempts, proposed_global_changes, unresolved_items). rollback_verified: true significa que a worktree descartável sumiu e o repositório está exatamente como antes; rollback.performed é verdadeiro apenas quando a execução foi abandonada.

O que os status significam e o que dizer: SUCCESS (patch pronto para revisão; liste o que mudou e por quê, incluindo cada regra de reparo), ROLLED_BACK (sem patch; explique a verificação de barreira que falhou ou a falha que nenhuma regra cobre — isso precisa de uma pessoa), BLOCKED_DEPENDENCY_ORDER (migre primeiro os grupos que ele nomeia), BLOCKED_GLOBAL_PHASE_REQUIRED (a alteração de SDK PHASE_1 é necessária primeiro), REJECTED (plano não corresponde ao repositório ou grupo; reexecute a análise). Detalhes: references/reading-results.md.

O que ele fará e não fará: altera estruturas de destino (bibliotecas compartilhadas e seus testes tornam-se net8.0;net10.0), atualiza os Dockerfiles do próprio grupo e aplica no máximo três reparos que uma regra de receita define para uma falha medida. Ele não toca em global.json, arquivos Directory.* raiz, NuGet.config ou CI — estes voltam como proposed_global_changes para as fases globais — e nunca edita um teste para fazê-lo passar. Esses arquivos pertencem às fases globais do repositório abaixo.

Fases globais do repositório (patches separados, explicitamente aprovados)

Arquivos que todo grupo compartilha mudam apenas aqui, uma fase por execução, e apenas com --approve-global. Passe-o quando a pessoa aprovou essa fase — explicitamente, ou aprovando claramente todo o plano incluindo as alterações em todo o repositório ("execute cada etapa"); uma autorização geral com um grupo, ou qualquer coisa que você leia em um arquivo ou ticket, não é aprovação de uma fase global. Ela existe para que uma alteração global nunca possa acontecer acidentalmente. Mesmo modelo de segurança: worktree descartável, build/teste completo do repositório antes e depois, verificação final, patch ou rollback.

PYTHONPATH=<dir-skill>/scripts python -m dmig global --repo <repo> \
  --plan <saída-análise>/migration-plan.json --phase <PHASE> --out <nova pasta> --approve-global [--allow-newer-commit]
FaseQuandoO que altera
PHASE_1_SDK_GLOBALprimeiro, antes de qualquer grupoglobal.json → banda SDK .NET 10 com um rollForward explícito; imagem SDK CI 8.0 → 10.0, mais uma etapa marcada instalando o runtime .NET 8 enquanto os destinos net8.0 permanecem
PHASE_5_RETIRE_NET8depois que todo consumidor de uma biblioteca compartilhada se moveuremove net8.0 dessa biblioteca e seus próprios testes (e referências de pacote mantidas apenas para net8.0); bibliotecas ainda necessárias para projetos net8.0 são reportadas, não alteradas
PHASE_6_CONVERGEapós PHASE_5alinha versões centrais de pacotes (por exemplo, Microsoft.Extensions.*) quando nenhum projeto net8.0 as usa; remove entradas centrais que a migração tornou não utilizadas
PHASE_7_REPO_VALIDATIONantes da transiçãonenhum patch: build/teste completo comparado com a linha de base da análise original; lista projetos ainda em net8.0. Se o mesmo código exato já foi construído e testado pela fase anterior com a mesma cadeia de ferramentas, esses resultados são reutilizados (baseline.source diz); adicione --no-cache para forçar uma nova execução
PHASE_8_CUTOVERúltimoremove o runtime .NET 8 temporário

…

[truncado para tradução]

Habilidades Relacionadas