# ENG-1439 — Integridade da embalagem no ciclo de vida da tarefa

## Contexto

A tarefa `90224` foi encontrada com `picking_orders.shipping_packaging_id` nulo. O cliente consumidor exibe a embalagem como `undefined` e falha ao tentar reiniciar a tarefa.

O backend possui dois fluxos para iniciar tarefas de separação:

- rota legada `stock/expedition/output/picking-order/{pickingOrder}/start`, com `shipping_packaging_id` obrigatório;
- rota V2 `stock/picking-order/{pickingOrder}/start`, com `shipping_packaging_id` atualmente opcional.

O escopo desta correção é exclusivamente o backend `rex-back`, incluindo dados existentes, integridade de banco, contrato de API, validações, services e testes Pest. O cliente mobile não será alterado.

## Regra funcional

- Tarefas iniciadas pela rota legada sempre precisam de embalagem.
- Na rota V2, tarefas relacionadas a `StockIO` do setor de expedição precisam de embalagem.
- A rota V2 pode iniciar sem embalagem quando a tarefa não estiver relacionada a `StockIO` de expedição.
- A regra deve considerar tarefas com `StockIO` associado diretamente e tarefas que chegam aos `StockIOs` por meio dos produtos da tarefa.
- A mesma mensagem funcional deve ser usada nas validações dos dois fluxos.

## Design

### FormRequests

O `PickingOrderStartRequest` legado manterá `required|exists` para `shipping_packaging_id`. A validação específica de início não deve alterar o comportamento da rota de troca de embalagem, que reutiliza esse request.

O `App\Http\Requests\V2\PickingOrderStartRequest` continuará aceitando embalagem nula por padrão, mas adicionará uma validação condicional baseada na tarefa da rota. A tarefa deverá resolver suas associações diretas e indiretas e exigir embalagem quando qualquer `StockIO` associado pertencer ao setor `EXPEDITION`.

### Services

Os services legado e V2 receberão uma proteção defensiva antes de qualquer alteração de status ou início de estoque. Se o DTO chegar com embalagem nula em um fluxo que exige embalagem, o service interromperá a operação com a mesma mensagem funcional do FormRequest.

No V2, a proteção deve respeitar a mesma classificação do FormRequest: exigir embalagem somente para tarefas relacionadas à expedição. O fluxo de tarefas não relacionadas à expedição continuará aceitando embalagem nula.

As validações devem ocorrer antes de efeitos colaterais, preservando a transação e impedindo início parcial da tarefa ou dos `StockIOs`.

## Tratamento de erro

Uma mensagem de domínio única será reutilizada nos dois fluxos. A validação do FormRequest retornará erro de validação para chamadas HTTP normais; a proteção do service cobrirá chamadas internas ou caminhos que contornem o FormRequest.

## Integridade de dados e recuperação

As novas tarefas e alterações nos estados `STARTED` e `PAUSED` devem sempre possuir `shipping_packaging_id`. Essa regra será protegida por uma constraint PostgreSQL `NOT VALID` na tabela `picking_orders`, permitindo a convivência temporária com registros legados inválidos sem alterar seus dados durante o deploy.

Os registros legados inválidos serão corrigidos pelo fluxo operacional de troca de embalagem. Após a regularização dos registros, uma etapa posterior poderá executar `VALIDATE CONSTRAINT`.

O fluxo de troca de embalagem deverá continuar disponível para tarefas pausadas e persistir a nova associação. Assim, uma tarefa pausada que tenha sido corrigida ou encontrada sem embalagem poderá receber uma embalagem antes de ser reiniciada.

Todos os fluxos que alteram `status` ou `shipping_packaging_id` deverão ser revisados, incluindo pausa, retorno para pendente, troca, transferência e exclusão de embalagem. A constraint será a última barreira contra atualizações diretas, jobs ou integrações que contornem os services.

## Testes

Adicionar ou atualizar testes Pest de feature para:

- rejeitar a rota legada sem `shipping_packaging_id`;
- rejeitar DTO nulo no service legado;
- iniciar a rota legada com embalagem válida;
- rejeitar a rota V2 de tarefa de expedição sem embalagem;
- cobrir tarefa V2 ligada diretamente a `stock_io`;
- cobrir tarefa V2 ligada indiretamente via `stock_io_products`;
- permitir tarefa V2 não relacionada à expedição sem embalagem;
- iniciar tarefa V2 com embalagem válida;
- rejeitar chamada do service V2 com embalagem nula quando a tarefa exigir embalagem;
- rejeitar no banco tarefa `STARTED` sem embalagem;
- rejeitar no banco tarefa `PAUSED` sem embalagem;
- permitir tarefa `PENDING` sem embalagem;
- vincular nova embalagem a tarefa pausada e reiniciá-la com sucesso;
- garantir que transferência ou exclusão de embalagem não deixe tarefa iniciada/pausada inválida;
- corrigir registros legados pelo fluxo de troca de embalagem;
- garantir que falhas não alterem status da tarefa nem iniciem os `StockIOs`;
- preservar o retorno da embalagem nos resources/listagens quando ela existir.

## Critérios de aceite

- Nenhuma tarefa de expedição pode ser iniciada sem embalagem.
- A API retorna a mensagem funcional padronizada em ambos os fluxos.
- Tarefas não relacionadas à expedição não perdem o comportamento opcional da rota V2.
- Chamadas inválidas não produzem efeitos parciais.
- Nenhuma nova tarefa `STARTED` ou `PAUSED` pode ser persistida sem embalagem.
- A tarefa pausada sem embalagem possui um caminho de recuperação por troca de embalagem.
- A cobertura Pest protege as duas rotas, os dois formatos de associação de `StockIO` e os services.
