Abaixo do piso? Suba a linha primeiro.
O /arch-adopt recusa um projeto numa linha do Spring Boot abaixo de 4.0. O /platform-upgrade leva o build até a linha que o Initializr serve hoje, deixa o build verde e o diff sem commit, e termina imprimindo /arch-adopt.
O que o export diz hoje
O export lê a linha do Spring Boot no build do projeto e compara com doctor.platform.min_line, hoje 4.0. Abaixo dela, sai com 2 antes de escrever um byte, e o /arch-adopt, que escreve por ele, também. Até o /platform-upgrade, a recusa dizia o problema e parava.
# example: /work/legacy-app, a project on Spring Boot 3.5 (the path and the line vary) ❌ /work/legacy-app builds on Spring Boot 3.5 — this .claude/ is written for 4.0 and later. Its norms, exemplars and architecture-test allowlist use APIs and packages that do not exist on 3.5, so what they generate would not build or would misbehave there. Nothing was written. Migrate the project to Spring Boot 4.0 or later first, then run this again. The `platform-upgrade` skill does that migration; it is delivered with `arch-adopt`. The floor is `doctor.platform.min_line` in .claude/schemas/extensions.json.
O texto é do próprio ArchHook.java, exportPlatformGate, literal. O caminho e a linha 3.5 são exemplo.
Primeiro uma receita, depois uma passada guiada
O que é mecânico é uma receita, escrita a partir de dados, então a mesma entrada dá a mesma receita. O que não é fica com o modelo, um erro de compilação por vez.
Uma receita OpenRewrite
O ArchHook.jar upgrade-recipe a escreve a partir de doctor.platform.upgrade e das renomeações de propriedade que os próprios jars do Spring publicam. O núcleo OpenRewrite, Apache-2.0, a roda pelo wrapper Maven ou Gradle do próprio projeto; a skill nunca presume um no PATH e nunca adiciona um. Duas passadas: o bump, com starters, BOMs e tipos, depois as propriedades de configuração, que precisam do classpath que a primeira deixa.
Um erro de compilação por vez
O que nenhuma renomeação cobre: um test starter, código Jackson 3, uma API que mudou de forma. O modelo lê os primeiros erros, corrige a causa contra as normas e o guia de migração do fornecedor, e compila de novo. Teste que falha é reportado, nunca apagado, pulado ou afrouxado, e o mesmo erro três vezes seguidas interrompe o laço e pergunta.
Os testes rodam primeiro na árvore intocada e de novo no fim. O ArchHook.jar test-diff classifica cada caso: uma regressão, um teste que sumiu e uma falha que o baseline nunca viu saem com 2; uma falha que já existia, ou uma correção, não. Um build vermelho que já era vermelho é reportado como tal.
O que a skill faz, em ordem
Tudo que o procedimento baixa ou escreve fora do projeto vai para um só diretório, o $WORK. Precisa de worktree limpa, um JDK que o build aceite, um wrapper na raiz do projeto e acesso de rede ao Initializr e aos repositórios do motor.
- 1Recusa worktree suja; acha a ferramenta de build e o wrapper. Sem wrapper: para.
- 2Busca a fonte em
$SRC, como oarch-adopt: um projeto abaixo do piso não tem umArchHook.jardeste formato. - 3Resolve o alvo num projeto descartável que o Initializr gera, e baixa os metadados de
dependenciesdele. Versão nunca é escrita de memória. - 4Resolve a versão do motor no repositório que a serve.
- 4bO baseline: roda os testes na árvore intocada, depois o
test-diff snapshot. - 5Passada 1: a versão, os BOMs, as coordenadas, os starters e os tipos.
- 5bSó Gradle: corrige o wrapper que o plugin novo do Boot recusa.
- 6Lista o classpath novo.
- 7Passada 2, sem compilar: as renomeações de propriedade que os jars novos declaram.
- 8O resíduo guiado: compila, lê, corrige a causa, compila de novo.
- 8bO contexto carrega: as classes
@SpringBootTestrodam primeiro e sozinhas. - 9Verifica:
clean verifyouclean build, depois otest-diff compare. - 10Entrega o diff: sem commit, e imprime
/arch-adopt.
› /platform-upgrade [--ref <tag|sha|main>] [--source <local path>] ✅ upgraded — <from line> → <target>, <Maven | Gradle> Source ....... <host>, ref <ref> Engine ....... <engine artifact> <version> Baseline ..... <n> test cases, <n> failing before | none — the tree ran no tests Pass 1 ....... <n> files changed (<n> sources, <n> build) BOMs ......... <n> moved by the recipe, <n> by hand | not moved — no Initializr metadata Wrapper ...... <unchanged | Gradle <from> → <to>> (Gradle only) Pass 2 ....... <n> property renames applied | none declared by the jars Residue ...... <n> edits by hand — <one line each> Context ...... <n> @SpringBootTest classes green | Not verified: context load Verify ....... <green | no worse than the baseline: <n> pre-existing | the regressions, verbatim first line> Not verified . <what no step above ran — one line each | none> Review: git diff · Undo: git checkout -- . Next: /arch-adopt
O relatório é o formato dos docs do nerviz; os sinais de menor e maior marcam o que cada run preenche.
Um run, do começo ao fim
Um projeto Gradle privado no Spring Boot 3, atualizado com o nerviz v0.41.4 em 2026-10-20. O nome do usuário e o do projeto estão borrados. O run levou 8m17s e alterou 12 arquivos.
- Pré-checagens: worktree limpo, Gradle 8.10.2 com wrapper, JDK 21.
- Alvo, vindo do Initializr: Spring Boot
4.1.1. Engine:org.openrewrite:plugin7.39.0 comrewrite-bom8.89.0. - Baseline: 41 casos de teste, 0 falhando.
- Passada 1, no
build.gradle: Boot, Spring Cloud e springdoc atualizados, 3 starters renomeados,spring-boot-starter-cacheadicionado. O wrapper do Gradle foi de 8.10.2 para 8.14.6. - A passada guiada:
DefaultAuthorizationCodeTokenResponseClient, removido no Spring Security 7, virouRestClientAuthorizationCodeTokenResponseClient; um starter de teste virouspring-boot-starter-jdbc-test; o Spring Cloud AWS foi de 3.1.0 para 4.2.0; dois beans passaram para oObjectMapperdo Jackson 3. - Contexto: 5 classes
@SpringBootTestverdes. Verify: verde, e otest-diffachou 0 regressões, 0 testes sumidos, 0 falhas novas.
Não fez commit. Em Not verified citou o login OAuth2, que nenhum teste cobre, e deixou três decisões com o usuário: os pins de versão, o converter de OAuth2 ainda no Jackson 2 e onde o starter de cache fica no build.gradle. Depois imprimiu /arch-adopt.
Limites, ditos com clareza
É só manual: reescreve o build e o código de uma pessoa, então roda quando você pede pelo nome. O território de escrita dela é o arquivo de build da raiz, os arquivos do wrapper e src/**, na raiz do projeto e em qualquer módulo. O .claude/** fica de fora.
- Fazer commit. O diff é seu para revisar.
- Escrever em
.claude/. Isso é do/arch-adopt, a quem ela passa a vez. - Apagar, pular ou afrouxar um teste que falha.
- Renomear código Jackson 3. É uma decisão por ponto, não uma renomeação, então fica na passada guiada.
- Alcançar uma renomeação que nenhum exemplar do próprio nerviz usa; um pacote movido que nenhum deles toca é da passada guiada.
- Editar em volta de um build que esconde a versão. Uma versão do Boot num POM parent que não é do projeto, ou num catálogo de versões, não é lida: ela nomeia o arquivo e pede que você mude essa linha.
- Rodar num projeto que já está no piso ou acima. Ela avisa e para.
Três jobs, e o que eles deixam em aberto
| Job | O que prova |
|---|---|
templates › platform-upgrade | Com rede, no Maven e no Gradle: um fixture na linha GA mais nova abaixo do piso passa pelo procedimento da skill e builda verde na linha do Initializr. O contexto carrega com os starters de cache e Flyway, um BOM do Spring Cloud se move, um starter fixado perde a fixação, um wrapper Gradle antigo é corrigido, e nenhum teste fica pior que antes. |
validate › hooks-cross-platform › upgrade-recipe … | O bump leva o alvo e um passo por renomeação dos dados de produção; cada recusa sai com 2 sem escrever nada. |
validate › hooks-cross-platform › test-diff … | Uma regressão, um teste sumido e uma falha nova saem, cada um sozinho, com 2; uma falha que já existia, uma correção e um skip saem com 0. |
Não provado, de propósito: uma execução agendada do job do motor; o Gradle Kotlin DSL e os builds Gradle multi-módulo; e com que frequência falta uma renomeação nos dados.
- Próximo passo
Revise o diff, depois adote
Depois de revisar o diff, digite
O guia do /arch-adopt →/arch-adopt. O plugin entrega o/platform-upgradejunto com ele, e um projeto adotado o mantém para o próximo piso. - A skill
O contrato, o território de escrita e o que o guard faz com ela.
platform-upgrade · página da skill → - O doc completo
No repositório do nerviz.
15-platform-upgrade.md →