# Task 008 — Eventos pós-validação: Interface + Registry

**Depende de:** 001
**Bloqueia:** 007 (usa o Registry), 013

## Objetivo

Permitir que cada contexto consumidor registre callbacks executados quando o OTP correspondente muda de estado.

## Deliverables

### `Eventos/OtpEventoInterface.php`

```php
interface OtpEventoInterface {
    public function aoValidar(object $otp, array $extras = []): void;
    public function aoExpirar(object $otp): void;     // default no-op em classe base
    public function aoCancelar(object $otp): void;    // default no-op
}
```

### `Eventos/OtpEventoBase.php` (abstrata)

Implementação default vazia para `aoExpirar` e `aoCancelar`. Consumidor estende e sobrescreve só o que precisa.

### `Eventos/OtpEventoRegistry.php`

Espelho de `OtpCanalRegistry`:
- `registrar(string $contexto, string $classe)` — valida `is_subclass_of(...,OtpEventoInterface)`.
- `temRegistro(string $contexto): bool`
- `resolver(string $contexto): OtpEventoInterface`
- `reset()` — testes.

## Semântica

- O **contexto** identifica unicamente o consumidor (1 contexto = 1 evento). Se múltiplos consumidores precisarem do mesmo contexto, criar contextos distintos.
- Erros lançados pelos métodos do evento são capturados no Laboratório que dispara — **não revertem o status**. São registrados como `falha_evento` em `verificacoes_otp_eventos`.

## Critério de aceite

- Registro de classe que não implementa interface → `InvalidArgumentException`.
- Resolução de contexto desconhecido → `RuntimeException`.
- Cobertura em testes (012).
