# Fase B1 — Socket V2 isolado

> Objetivo da fase: realtime da V2 funcionando em **rooms próprias `_v2`**, atrás de uma interface — a peça-chave que torna os labs testáveis sem `$galaxia`. **Sem cross-talk com a V1.**
> Ref. PRD: §3 (Eventos/) + §11. Fonte-cópia: `componentes/Missoes/Logistica/sinais/Edicaorota/Eventos/EdicaoRotaSocketNotifier.php`.

---

## B1-1 — `CentralBroadcastInterface` ✅

- **Status:** ✅ · **Esforço:** S · **Depende de:** B0-1
- **Objetivo:** definir o contrato (= o "schema" do payload do front, **num lugar só**).
- **Arquivos:** `Eventos/CentralBroadcastInterface.php`
- **Critérios de aceite:**
  - [x] Métodos tipo `rotaAtualizada(int $rotaId, array $campos)`, `rotaRemovida(int $rotaId)`, `markersAtualizados(array $markers)`.
  - [x] Documenta o envelope (`action`, `data`, `timestamp`) e os campos — esse é o contrato do front F-3.

## B1-2 — `CentralSocketNotifier` (impl, rooms `_v2`) ✅

- **Status:** ✅ · **Esforço:** M · **Depende de:** B1-1
- **Objetivo:** implementação real (Scaledrone), best-effort, **sem `$galaxia`**, gateada por `WEBSOCKET_ENABLED`.
- **Arquivos:** `Eventos/CentralSocketNotifier.php`
- **Critérios de aceite:**
  - [x] Publica **só** em `galaxia_logistica_central_v2` / `galaxia_logistica_board_v2`.
  - [x] Cópia adaptada do `EdicaoRotaSocketNotifier` (cURL → fallback; nunca lança; `error_log`).
  - [x] Respeita `WEBSOCKET_ENABLED`.

## B1-3 — `CentralBroadcastRegistry` ✅

- **Status:** ✅ · **Esforço:** S · **Depende de:** B1-1
- **Objetivo:** resolver o notifier por registry (real ↔ spy/no-op) — habilita unit test e `WEBSOCKET_ENABLED=false`.
- **Arquivos:** `Eventos/CentralBroadcastRegistry.php`
- **Critérios de aceite:**
  - [x] Idiom `registrar`/`resolver`/`temRegistro`/`reset` (espelho do `EdicaoRotaCallbackRegistry`).
  - [x] Chave de contexto própria (`central_v2`) — não colide com registries da V1.

## B1-4 — Bootstrap do controller registra o notifier ✅

- **Status:** ✅ · **Esforço:** S · **Depende de:** B1-2, B1-3
- **Objetivo:** no `Central2::bootstrap()`, registrar o notifier real idempotentemente (substitui o TODO(B1)).
- **Arquivos:** `Central2.php`
- **Critérios de aceite:**
  - [x] Registro idempotente (`temRegistro` antes de `registrar`).
  - [x] Labs resolvem o broadcaster via registry, nunca chamam Scaledrone direto.

## B1-5 — Testes Eventos + schema do payload ✅

- **Status:** ✅ · **Esforço:** M · **Depende de:** B1-2, B1-3
- **Objetivo:** TddTest do notifier (com spy) e teste que **fixa as chaves** do payload (semente do P-3).
- **Arquivos:** `Testes/Eventos/CentralSocketNotifierTddTest.php`
- **Critérios de aceite:**
  - [x] Spy captura `action`/`data` e afirma rooms `_v2`. (31/31 PASS)
  - [x] Teste de schema falha se uma chave do payload for renomeada/removida. (Reflection trava nomes de método + parâmetros)
