# Task 009 — Laboratórios `Cancelar` e `Consultar`

**Depende de:** 002, 003, 008
**Bloqueia:** 010

## Objetivo

Operações auxiliares para o ciclo de vida.

## Deliverables

### `Laboratorios/CancelarOtpLaboratorio.php`

Construtor `(array $entrada)`:
- `entrada` precisa de `otp_id` **OU** (`contexto` + `referencia_externa`).
- Carrega OTP. Se já estado final → resposta `success` (idempotente).
- Atualiza status → `CANCELADO`, `cancelado_em = now`, `motivo_cancelamento = entrada['motivo'] ?? null`.
- Registra evento `cancelado`.
- Resolve `OtpEventoRegistry::resolver($contexto)` se houver e chama `aoCancelar($otp)` (try/catch — falha vira evento de auditoria, não reverte).

### `Laboratorios/ConsultarOtpLaboratorio.php`

Construtor `(array $entrada)`:
- Aceita `otp_id` ou `(contexto, referencia_externa)`.
- Busca o OTP **mais recente** para o par (final ou ativo).
- Resposta com `otp_id`, `status`, `expira_em`, `tentativas`, `tentativas_restantes`, `dados_adicionais`. **Não retorna `codigo_hash` nem `destinatario`** — porta minimalista; consumidor pode pegar via Sonda direta se precisar mais.

## Critério de aceite

- `Cancelar` é idempotente.
- `Consultar` não tem efeitos colaterais.
- Lint OK.
