# Wiring de Laboratórios em Missões — Plano técnico

## Resumo de decisão arquitetural

Trata-se de uma refatoração interna de `componentes/Missoes/Logistica/sinais/Designacoes/Designacoes.php`: substituir os 3 métodos privados utilitários (`calcularEstatisticasPainel`, `prepararDadosLista`, `buscarProdutos`) por chamadas aos Laboratórios já existentes e deletá-los. Nenhum Sinal novo, nenhuma Sonda nova, nenhuma rota nova, nenhum padrão V2 adicional. **Os 4 fluxos de ciclo de vida (criar/designar/transicionar/concluir) ficam parcialmente fora de escopo na prática** — ver seção "Reconciliação com a spec" abaixo. Padrão dominante: instanciar Laboratório no controller, ler `$lab->response`, descartar lógica duplicada.

## Sinal de referência

- **Imitar**: `componentes/Missoes/Logistica/sinais/Edicaorota/Edicaorota.php` — controller V2 que delega aos Laboratórios via `new XxxLaboratorio($args); $lab->response`. Padrão direto, sem injeção/DI extra.
- **Imitar (estrutura de teste)**: `componentes/Missoes/Logistica/sinais/Designacoes/Testes/Integration/MissaoLogisticaCicloVidaIntegrationTest.php` — registra fake callback via `MissaoLogisticaCallbackRegistry::registrar()`, executa fluxo, verifica que callback disparou.
- **Não imitar**: nenhum dos Satélites em `componentes/Constelacoes/Logistica/MissaoLogistica/Satelites/` (são V1/legacy, serão tratados em features futuras — opção C/D do roadmap).

## Reconciliação com a spec (resolve dúvida B + escopo real de US4)

A spec referencia `Missao.php` em US4. **Não existe `Missao.php` no repo** — busca exaustiva (`find componentes -iname Missao.php`) retorna vazio. Os fluxos de ciclo de vida (criar/designar/transicionar/concluir) hoje passam por:

- `MissoesPersistencia` (Satélite V1) — chamado via `galaxiaRoute->setSatelite('MissoesPersistencia')->setOpcao('enviarMissoes')` em `forms/enviar_unificado`.
- `MissoesAprovacao` (Satélite V1) — fluxo de aprovação/conclusão.
- `MissoesStatus` / `MissoesExecucao` (Satélites V1) — transições de status e execução de itens.

A spec linha 19 explicitamente exclui: *"Mexer em fluxos que hoje passam exclusivamente por Satélites (`MissoesPersistencia`, `MissoesAprovacao`, etc.) sem trafegar pelos controllers em escopo."*

**Mapeamento Laboratório → método privado em `Designacoes.php`:**

| Laboratório | Método privado correspondente em controller | Existe? | Ação |
|---|---|---|---|
| `MissaoPainelEstatisticasLaboratorio` | `Designacoes::calcularEstatisticasPainel()` (linha 734) | ✅ | Substituir + deletar |
| `MissaoListaEnriquecedorLaboratorio` | `Designacoes::prepararDadosLista()` (linha 911) | ✅ | Substituir + deletar |
| `BuscarProdutosLaboratorio` | `Designacoes::buscarProdutos()` (linha 1233, **público**) | ✅ | Substituir corpo + manter handler público |
| `CriarMissaoLaboratorio` | — nenhum método privado equivalente em `Designacoes.php` | ❌ | **Out of scope** (lógica vive em `MissoesPersistencia`) |
| `DesignarMissaoLaboratorio` | — | ❌ | **Out of scope** |
| `TransicionarStatusMissaoLaboratorio` | — | ❌ | **Out of scope** |
| `ConcluirMissaoLaboratorio` | — | ❌ | **Out of scope** |

**Recomendação ao orquestrador**: rebaixar US4 para "documentado, ficará para feature posterior C (mover Satélites pro sinal)". US1, US2, US3, US5, US6 ficam no escopo real desta feature. **Pedir confirmação do PO via AskUserQuestion antes do dev iniciar.**

### Incompatibilidades de assinatura

| Laboratório | Assinatura do construtor | Método privado original | Incompatibilidade |
|---|---|---|---|
| `MissaoPainelEstatisticasLaboratorio` | `__construct(array $itens, array $strategyConfig = [])` | `calcularEstatisticasPainel(array $itens, array $strategyConfig)` | **Compatível** — argumentos idênticos. Retorno: `$lab->response` em vez de retorno direto. |
| `MissaoListaEnriquecedorLaboratorio` | `__construct(array $missoes, object $galaxiaRoute)` | `prepararDadosLista(array $missoes)` | **Pequena**: Laboratório precisa de `$this->galaxiaRoute`; original usava `$this->galaxiaRoute` implicitamente. Solução: passar `$this->galaxiaRoute` no `new`. Sem adapter necessário. |
| `BuscarProdutosLaboratorio` | `__construct(string $termoBusca, int $limite, object $galaxiaRoute)` | `buscarProdutos(?array $data = [])` (público — ponto de entrada HTTP, faz `echo json_encode + exit`) | **Estrutural**: Laboratório retorna array `['status'=>'success','produtos'=>[]]`; original faz `echo + exit`. Solução: handler público continua extraindo `termo` e `limite` de `$data/$_POST/$_GET`, instancia o Laboratório, e o controller faz `echo json_encode($lab->response); exit;`. Sem alteração de contrato HTTP. |

Nenhum dos 3 exige adapter inline nem mudança em Laboratório. As 190 testes continuam válidas sem alteração.

## Estrutura proposta

### Novos arquivos

Nenhum.

### Arquivos alterados

- `componentes/Missoes/Logistica/sinais/Designacoes/Designacoes.php`
  - Substituir corpo de `lista()` (linha 312): `$dadosLista = $this->prepararDadosLista($missoes);` → `$dadosLista = (new MissaoListaEnriquecedorLaboratorio($missoes, $this->galaxiaRoute))->response;`
  - Substituir corpo de `painel()` (linha 646): `$estatisticasPainel = $this->calcularEstatisticasPainel($itens, $strategyConfig);` → `$estatisticasPainel = (new MissaoPainelEstatisticasLaboratorio($itens, $strategyConfig))->response;`
  - Substituir corpo de `buscarProdutos()` (linhas 1233–1328): mantém handler público (preserva contrato HTTP — `echo + exit`), mas o conteúdo entre extração de input e `echo` vira `$lab = new BuscarProdutosLaboratorio($termoBusca, $limite, $this->galaxiaRoute); echo json_encode($lab->response); exit;`.
  - Adicionar `use` statements no topo: `MissaoPainelEstatisticasLaboratorio`, `MissaoListaEnriquecedorLaboratorio`, `BuscarProdutosLaboratorio`.
  - Deletar métodos privados `calcularEstatisticasPainel` (linhas 734–905) e `prepararDadosLista` (linhas 911–1170, incluindo o código morto pós-return que segue até ~1170).
- `componentes/Missoes/Plataforma/sinais/Api/Bootstrap.php`
  - **Auditoria (resolve dúvida A)**: hoje **zero callbacks** registrados em `MissaoLogisticaCallbackRegistry`. Ver seção dedicada abaixo.
  - **Nenhum registro novo nesta feature** — feature só ativa o broadcast; donos de callback se registram em features futuras.

## Auditoria de callbacks registrados (resolve dúvida A — AC5.1/AC5.2)

Comando executado: `grep -rn "MissaoLogisticaCallbackRegistry::registrar\|MissaoLogisticaCallbackRegistry" componentes/ --include="*.php"`.

**Resultado:**

- `componentes/Missoes/Plataforma/sinais/Api/Bootstrap.php`: **NÃO registra** `MissaoLogisticaCallbackRegistry`. Só registra `EdicaoRotaCallbackRegistry::registrar(RomaneioVeiculoEdicaoRotaCallback::MODULO, ...)` (linhas 79–86), que pertence a outro Registry e é irrelevante aqui.
- `componentes/Missoes/Logistica/sinais/Designacoes/Testes/Integration/MissaoLogisticaCallbackIntegrationTest.php`: registra `IntegrationFakeCallback` mas dentro de testes (escopo `Testes/`), com `reset()` em `setUp/tearDown`. **Não vaza para produção** — `Testes/` não é incluído no autoload de runtime.
- `componentes/Missoes/Logistica/sinais/Designacoes/Testes/Integration/MissaoLogisticaCicloVidaIntegrationTest.php`: idem (registra `IntegFakeCb`, com `reset()`).
- Nenhum outro consumidor (Romaneio, Coletas, BI etc.) registra callback no Registry de Missão Logística hoje.

**Conclusão da auditoria** (AC5.1/AC5.2 satisfeitos):

| Modulo registrado | Onde | Em produção? | Ação |
|---|---|---|---|
| (nenhum) | Bootstrap | — | Nada a fazer |
| `integ_test_cb` (`IntegFakeCb`) | Teste de integração | Não (só dentro do teste, com reset) | Manter — é fixture de teste |
| `integracao_teste` (`IntegrationFakeCallback`) | Teste de integração | Não (só dentro do teste, com reset) | Manter — é fixture de teste |

**Impacto runtime do wiring**: como nenhum callback de produção está registrado, ativar os Laboratórios de ciclo de vida hoje seria um **no-op observável** (broadcast itera sobre array vazio). Isso reforça que adiar US4 (lifecycle) não tem custo de negócio imediato — não há consumidor esperando os eventos disparar até que algum outro sinal (ex.: Romaneio, BI) registre seu callback no Bootstrap.

## Sondas e schema

N/A — feature não toca schema.

## Endpoints / fluxo

| Método | Rota | Handler | Mudança |
|---|---|---|---|
| GET/POST | rota Galaxia `Designacoes/lista` | `Designacoes::lista()` | Internamente chama `MissaoListaEnriquecedorLaboratorio` |
| GET/POST | rota Galaxia `Designacoes/painel` | `Designacoes::painel()` | Internamente chama `MissaoPainelEstatisticasLaboratorio` |
| POST | rota Galaxia `Designacoes/buscarProdutos` (AJAX, retorna JSON) | `Designacoes::buscarProdutos()` | Internamente chama `BuscarProdutosLaboratorio`; `echo json_encode + exit` preservados |

Nenhuma rota adicionada. Contrato HTTP idêntico (mesmas chaves, mesmos tipos, mesma ordem).

## Padrões de extensibilidade

Já existentes (não alterar nesta feature): `MissaoLogisticaCallbackRegistry` + `MissaoLogisticaCallbackInterface` cobrem broadcast de eventos. **Nesta feature não criamos nem registramos callbacks novos** — apenas verificamos que o registry está pronto para receber consumidores futuros.

## Ordem de implementação (sequencial)

1. Adicionar `use` statements no topo de `Designacoes.php` para os 3 Laboratórios.
2. Substituir chamada em `lista()` (linha 312) → instanciar `MissaoListaEnriquecedorLaboratorio`. Rodar smoke test manual da listagem.
3. Substituir chamada em `painel()` (linha 646) → instanciar `MissaoPainelEstatisticasLaboratorio`. Rodar smoke test manual do painel.
4. Substituir corpo de `buscarProdutos()` (linhas 1244–1325) preservando `echo json_encode + exit`. Rodar smoke test manual da busca AJAX.
5. Deletar `calcularEstatisticasPainel` (linhas 734–905) e `prepararDadosLista` (linhas 911 até início de `buscarOperadores` em ~1172, incluindo qualquer código morto).
6. Rodar a suíte 190/190 (testes em `componentes/Missoes/Logistica/sinais/Designacoes/Testes/Laboratorios/*StandaloneTddTest.php`) e os 2 integration tests existentes.
7. Adicionar 1 smoke test de integração novo cobrindo a rota `lista` (lista renderiza com Laboratório plugado), em `Testes/Integration/DesignacoesListaWiringIntegrationTest.php`.
8. Executar `/review` e endereçar blockers.

## Riscos e decisões não-óbvias

1. **Código morto pós-return em `prepararDadosLista`**: a feature anterior já mencionou (em comentário no `MissaoListaEnriquecedorLaboratorio`) que linhas 989–1127 são código morto. Confirmar via leitura antes de deletar — se houver `if (false)` ou `return` antecipado seguido de lógica, deletar tudo. Mitigação: dev faz diff com `prepararDadosLista` original e confirma equivalência funcional via testes do `MissaoListaEnriquecedorLaboratorio` (que cobrem o caminho ativo).
2. **`buscarProdutos` é endpoint público AJAX, não método privado**: a spec/PRD lista junto dos privados, mas o método é `public function buscarProdutos`. Não pode ser deletado — só o corpo é substituído. AC3.1 fala em "substituir por chamada ao Laboratório e em seguida deletado" — interpretar como "deletar a lógica duplicada interna", **não** o handler público. **Confirmar com PO via AskUserQuestion.**
3. **Callbacks ativarão broadcast sem consumidor real**: como auditoria mostrou, hoje 0 callbacks de produção. Ativar lifecycle (US4) seria seguro mas inútil. Decisão: **não fazer US4 nesta feature** — adiar para quando US4 vier acompanhada de pelo menos 1 consumidor real (ex.: notificar Romaneio).
4. **Suíte 190/190 não cobre o controller**: cobre os Laboratórios isoladamente (StandaloneTdd). Wiring no controller fica sem cobertura automática até criarmos o smoke test de integração da rota `lista`. AC6.3 cobre isso.

## Breaking changes

Nenhum. Contrato HTTP, payload, headers, ordem de operações idênticos.

## Plano de teste

- **Unit**: nenhum teste novo de Laboratório (190 já cobrem). Rodar os 3 testes Standalone (`MissaoPainelEstatisticasStandaloneTddTest.php`, `MissaoListaEnriquecedorStandaloneTddTest.php`, `BuscarProdutosStandaloneTddTest.php`) para confirmar verde.
- **Integration**: criar `Testes/Integration/DesignacoesListaWiringIntegrationTest.php` que invoca a rota `lista` end-to-end contra `dev_gx_goldie` e verifica que o response contém as estatísticas (sinal de que o Laboratório foi chamado). Bootstrap segue padrão de feedback_integration_tests (`$_SESSION` em raiz e dashboard).
- **Manual (smoke tests)**:
  - `painel` de uma missão renderiza estatísticas idênticas pré/pós-wiring (comparar JSON do `estatisticasPainel`).
  - `lista` renderiza missões na mesma ordem, com mesmas badges, contadores e descrições enriquecidas com romaneio.
  - `buscarProdutos` por código, código de barras e descrição retorna o mesmo array de produtos.

## Out of scope (confirmando spec + acréscimos técnicos)

Da spec:
- Mover Satélites/Enums/Strategies para o sinal (opção C).
- Deletar shims V1 (opção D).
- Criar Laboratórios novos.
- Mudar contrato HTTP, payload de resposta, ordem observável.
- Mexer em fluxos que passam exclusivamente por Satélites (`MissoesPersistencia`, `MissoesAprovacao` etc.).

Acréscimos técnicos desta análise:
- **US4 inteira (criar/designar/transicionar/concluir)** — não há método privado correspondente em `Designacoes.php` nem existe `Missao.php`. Pluging desses Laboratórios exige refatorar Satélites V1 (`MissoesPersistencia` etc.), que está fora do escopo da spec linha 19. **Sujeito a confirmação do PO.**
- **Registro de callbacks reais no Bootstrap** — auditoria mostrou nenhum hoje; não há nada a remover ou plugar. Quando outros sinais quiserem consumir, eles próprios adicionam em PRs futuros (mesmo padrão do `EdicaoRotaCallbackRegistry`).

## Timing de rebase com `feature/migracao-imports-missoes-sondas` (resolve dúvida C)

Estado verificado:
- `git merge-base feature/migracao-imports-missoes-sondas feature/wiring-laboratorios-missoes` → `21ec68f2` (= HEAD atual de `migracao-imports-missoes-sondas`).
- `wiring-laboratorios-missoes` só adiciona 2 commits acima da base: `80a929c6` (PRD bruto) e `dbb19deb` (spec). Nenhum commit de código ainda.
- Ambos os branches estão limpos (`git status` sem mudanças locais).

**Recomendação**: **manter base atual e seguir**. Se `migracao-imports-missoes-sondas` receber fixes do tester/reviewer, rebase é trivial — esta branch ainda não tem código de produção, só PRD/spec/techplan, então conflito praticamente impossível. Esperar bloquearia o pipeline sem ganho. Caso a base receba fix que **mude assinatura/import** dos 3 Laboratórios em escopo (improvável — escopo de `migracao-imports` é trocar imports, não APIs), o dev faz `git rebase feature/migracao-imports-missoes-sondas` antes do PR; merge-base atualizado torna isso 1 comando.

**Critério de re-rebase**: depois que o dev implementar e antes de abrir PR, rodar `git fetch && git rebase feature/migracao-imports-missoes-sondas` para garantir HEAD da base atualizado. Sem espera ativa.
