FIN-68. Move a assinatura do plano para outra opção de plano à venda na mesma comunidade (de outro plano também, ex.: Starter → Growth). Só o próprio assinante; assinatura de outra pessoa ou de outra comunidade responde 404. A assinatura continua a mesma (mesmo `id`, histórico, período e adicionais); muda `productId`, `billingAmount` e `billingInterval`. Veja a prévia em `POST /change-tier/quote`.
**Upgrade** (opção mais cara na mesma periodicidade, com `immediate: true`): vale na hora e cobra agora, no cartão salvo do membro (o padrão, ou `paymentMethodId`), a diferença proporcional aos dias que faltam no período; a próxima renovação já vem no preço novo. Abaixo do piso (menos de 3 dias ou de R$ 10) troca sem cobrar. A cobrança é uma venda como as outras: taxa da plataforma e `feePayer` da opção nova, parcelas até o `maxInstallments` da prévia (`installments`). Se o cartão for recusado ou a cobrança não for confirmada na hora, **nada muda**: 402 (recusa) ou 502 (provedor fora do ar). Sem cartão salvo: 400 `param = paymentMethodId`.
**Agendada** (opção mais barata ou de mesmo preço, outra periodicidade — mensal ↔ anual, sem proporcional entre períodos —, upgrade com `immediate: false`, ou upgrade que tiraria um adicional): nada é cobrado agora. Na renovação de `effectiveDate` a assinatura passa para a opção nova e a cobrança já é no preço e na periodicidade dela. Uma nova troca agendada substitui a anterior; dá para desfazer com `DELETE /scheduled-change`.
**Adicionais** (F-37): os que a opção nova oferece continuam (no valor da periodicidade nova); os que ela não oferece terminam na troca. **Contrato** (F-35): o contrato em vigor continua até o fim; sem contrato, uma opção nova com contrato começa o dela na troca. **Cupom**: deixa de valer na troca.
Recusas, todas antes de qualquer cobrança: 400 `param = id` quando a assinatura não está `ACTIVE`, tem cancelamento agendado, é cortesia ou é um adicional ligado a um plano; 400 `param = newProductId` para a mesma opção, opção que não é de plano, fora de venda, em outra moeda, ou já assinada; 404 `newProductId` de outra comunidade ou inexistente; 403 `newProductId` para um adicional sem o plano que ele exige; 403 `param = id` quando a comunidade não tem informações comerciais aprovadas (só no upgrade cobrado); 409 `param = id` enquanto há uma cobrança de renovação do próximo período em aberto (PIX ou boleto já gerado, ou cartão em análise). O texto da recusa vem em `errors[0].message`.
Responde 200. `data`: `mode` (`IMMEDIATE` ou `SCHEDULED`), `changeType`, `scheduledReason`, `effectiveDate`, `currentProduct`, `newProduct`, `subscription` (como ficou), `scheduledChange` (o mesmo objeto de `GET /scheduled-change`, ou `null`), `charge` (`purchaseId`, `orderId`, `amount`, `currency`, `installments`, `feeBreakdown` só com a taxa da plataforma; `null` sem cobrança), `addOns`, `contract`, `couponEnds`.