# Review (ciclo 2) — alocacao-wms

**Base**: `dev_team`
**HEAD**: `feature/alocacao-wms` (`ab94cf2b`)
**Arquivos tocados**: 53 (49 de código/i18n + 4 docs de PRD; `image.png` e `PRD/separacao-fila-throughput/*` são ruído de árvore, não da feature)
**Linhas**: +7268 / -3

## Sumário

Segundo ciclo após correção. **Os 2 blockers (B1, B2) e os 4 majors (M1–M4) do `06-review.md` foram resolvidos** — verifiquei cada um contra o código e o framework, não só contra os comentários. O worker cron agora itera por tenant com sessão sintética idêntica ao padrão canônico `dashboard_expedicao_diario.php` (B1); a view Luz `item_card.php` existe e o delegate está wired corretamente (B2); a progressão de status PENDENTE→EM_ANDAMENTO→CONCLUIDA foi implementada de fato no Laboratório com guarda de transição (M1); a contaminação de Edicaorota/Central saiu do diff — restou só o card de criação no Central (M2); as chaves i18n existem nos **3 idiomas com traduções reais e distintas** (M3); e a criação de missão `ALOCACAO_WMS` no Central foi entregue via Laboratório dedicado + form (M4). `php -l` limpo em todos os arquivos; zero raw SQL em writes. Recomendação: **Merge** — restam apenas 1 major novo de baixa gravidade (i18n no form do Central, regressão pontual do fix M4) e 2 minors já conhecidos, todos aceitáveis com TODO.

## Verificação dos itens do ciclo anterior

| Item | Status | Evidência |
|------|--------|-----------|
| **B1** — worker sem contexto de tenant | ✅ **Resolvido** | `crons/wms_alocacao_integracao.php:82-94` itera `foreach ($blocks)` e seta `$_SESSION['galaxiaUserInfo']` + `$_SESSION['dashboard']['galaxiaUserInfo']` com `customerData->id = $block` — idêntico a `dashboard_expedicao_diario.php:150-155`. Confirmei em `ModelInteligencia.php:1303` que `customerQuery` lê exatamente `galaxiaUserInfo->customerData->id`, aplicado tanto em `find()` (`:513-514`) quanto em `update()` (`:1015-1016`). Logo `buscarPendentes*` e `marcarIntegracao*` ficam tenant-scoped. |
| **B2** — view inexistente `item_card.php` | ✅ **Resolvido** | `App/html/luz/alocacaowms/item_card.php` agora existe (63 linhas); `AlocacaoWmsHandler.php:124` renderiza `../html/luz/alocacaowms/item_card` (path correto); delegate `Luz_AlocacaoWmsItemCard` registrado em `App.php:568`. |
| **M1** — progressão de status (AC6.2/6.3) | ✅ **Resolvido** | `ConfirmarAlocacaoLaboratorio.php:138-193` `atualizarStatusMissaoAposConfirmacao`: conta itens pendentes, transita para CONCLUIDA quando `totalPendentes === 0` (AC6.3), EM_ANDAMENTO no primeiro item (AC6.1), no-op quando parcial (AC6.2), com `podeTransicionarPara()` antes de gravar. Usa `make()`/`save()` — mesmo padrão de `MissoesStatus.php:442-444`. Comentário enganoso em `MissoesBipagem.php:829-837` corrigido. |
| **M2** — contaminação de escopo | ✅ **Resolvido** | Diff de `Edicaorota/*` saiu por completo. Único toque em `Central/html/central.php` são +14 linhas do card de criação (entregável do M4). |
| **M3** — i18n só em pt-br | ✅ **Resolvido** | +156 entradas em cada `pt-br/en/es.json` com **traduções reais e distintas** (ex.: "Confirmar alocação" / "Confirm allocation" / "Confirmar asignación"). Varri todas as strings `show()` das views `alocacaowms/*` → 0 sem chave. |
| **M4** — criação no Central não entregue | ✅ **Resolvido** | `Central/Central.php:678-727` `criarAlocacaoWms()` (delega ao Laboratório), `Central/Laboratorios/CriarAlocacaoWmsLaboratorio.php` (lógica + `quantidade_obrigatoria` em `configuracoes`), `Central/forms/criar_alocacao_wms.php`, card em `central.php`. |
| m1 — LIMIT em PHP | ⚠️ Mantido | `WmsAlocacaoSonda.php:191,209` ainda `array_slice`. |
| m2 — `$required=['codigo']` | ⚠️ Mantido | `WmsLocalizacaoSonda.php:45` inalterado (read-only, inofensivo). |
| m3 — comentário enganoso | ✅ Resolvido | Junto com M1. |

## Issues

### 🔴 Blocker (0 issues)

Nenhum. Os dois blockers do ciclo anterior foram corrigidos e verificados contra o framework.

### 🟡 Major (1)

#### M5 — i18n: form do Central (`criar_alocacao_wms.php`) tem strings sem `show()`
**Onde**: `Central/forms/criar_alocacao_wms.php:107,122,125,135,147,149,158` (0 chamadas `show()` no arquivo)
**Problema**: O fix do M4 introduziu um form novo com ~8 strings visíveis cravadas: "Descrição da Missão", "Operador responsável", "Fila aberta", "Quantidade obrigatória", "Operador deve informar quantidade…", "Produtos", etc. Nenhuma passa por `show()`, então não há chave i18n e en/es caem no literal PT. É a mesma classe de defeito do M3 (que foi corrigido em outro lugar), re-introduzida neste arquivo.
**Por que é major (e não blocker)**: É modal interno de gestor (não fluxo do operador), escopo pequeno; classifico como major pela mesma régua usada no M3 do ciclo anterior. Mas é regressão direta de um fix — deve ser fechado antes de considerar a feature 100%.
**Como corrigir**: Envolver as strings visíveis em `show()` e adicionar as chaves correspondentes em `pt-br/en/es.json`, espelhando o que já foi feito para as views `alocacaowms/*`.

### 🟢 Minor (2)

#### m1 — `buscarPendentes*` aplica `LIMIT` em PHP, não na query
**Onde**: `Sondas/WmsAlocacaoSonda.php:191,209` (`array_slice($rows, 0, $limite)`)
**Problema**: Traz todas as linhas pendentes/falha e fatia em PHP; os índices parciais `idx_wms_alocacoes_integ_*` existem para varredura eficiente — o `array_slice` derrota o propósito sob volume. Mantido do ciclo anterior.
**Como corrigir**: Empurrar o limite para o Postgres (`->limit($limite)` se a API da Sonda suportar) em vez de cortar em memória.

#### m2 — `WmsLocalizacaoSonda` declara `$required = ['codigo']`
**Onde**: `Sondas/WmsLocalizacaoSonda.php:45`
**Problema**: Pela memória `modelinteligencia_save_gotchas`, `$required` populado pode quebrar `create()`. A Sonda é read-only hoje (inofensivo), mas inconsistente com `WmsAlocacaoSonda.php:50` que deixa `$required = []` justamente por isso. Mantido do ciclo anterior.
**Como corrigir**: Zerar `$required` por consistência.

### ⚪ Nit (2)

#### n1 — Cores hex hardcoded
**Onde**: `App/html/alocacaowms/item.php` (paleta indigo `#4f46e5`/`#6366f1`/…) e `Central/forms/criar_alocacao_wms.php:47,63,84,107` (`#6366f1`, `#f87171`)
**Problema**: Cores cravadas em vez de tokens de tema. Vários trechos já usam `var(--app-*)`/`var(--dm-*)` com fallback (bom), mas a paleta indigo e os vermelhos de erro estão cravados.
**Como corrigir**: Migrar para variáveis de tema onde existirem.

#### n2 — Worker tem 1 SELECT raw (tenant-discovery)
**Onde**: `crons/wms_alocacao_integracao.php:60-70` (`SELECT DISTINCT block … via $pdo->prepare`)
**Problema**: É leitura (não write), necessária para descobrir tenants **antes** de existir qualquer sessão, e está documentada com comentário explícito. Não viola `feedback_no_raw_sql` (que mira writes). Registro só como nota — é o trade-off correto do padrão `dashboard_expedicao_diario.php`.

## Pontos fortes

- **B1 corrigido no nível certo**: o worker não tenta "desligar" o `customerControl` na mão — estabelece a sessão sintética por tenant, deixando o framework resolver o `block` de forma idêntica ao cron de produção já validado (`dashboard_expedicao_diario.php`). Falha isolada por tenant (`try/catch` no loop) não derruba o ciclo. Solução robusta, não gambiarra.
- **M1 implementado com o enum de transição**: `podeTransicionarPara()`/`estadoFinal()` guardam a escrita; `finalizado_em`/`finalizada_por` carimbados; `make()`/`save()` espelham `MissoesStatus.php:442-444` (precedente real do repo). AC6.1/6.2/6.3 efetivamente cobertos.
- **M3/i18n exemplar**: 3 idiomas com tradução real (não cópia de PT); varredura de `show()` → zero chave faltando nas views do operador.
- **M4 segue V2**: lógica no `CriarAlocacaoWmsLaboratorio`, dispatcher fino no `Central.php`, registro idiomático nas factories (`ALOCACAO_WMS` => Strategy, uma chave por mapa, sem if/else no core), delega a `MissoesPersistencia::criacao`.
- **Zero raw SQL em writes** em todo o código novo; `php -l` limpo nos 49 arquivos.
- **B2 wired ponta a ponta**: view existe, Handler aponta certo, delegate registrado.

## Recomendação

✅ **Merge.** Os 2 blockers e 4 majors do ciclo anterior estão resolvidos e verificados contra o framework (não apenas contra comentários). Resta 1 major novo de baixa gravidade — **M5** (strings sem `show()` no form do Central, regressão pontual do fix M4) — que deve entrar com TODO rastreável ou ser fechado em um commit rápido antes do merge final. Os 2 minors (m1 LIMIT em PHP, m2 `$required`) são aceitáveis com TODO. Arquitetura V2 sólida e aderente ao techplan.
