# Changelog of Brazil Electricity Tariffs — Tarifas de Energia ANEEL (`matheus_dev_natal/brazil-electricity-tariffs-aneel`) Actor

- **URL**: https://apify.com/matheus_dev_natal/brazil-electricity-tariffs-aneel/changelog.md
- **Full Actor documentation**: https://apify.com/matheus_dev_natal/brazil-electricity-tariffs-aneel.md

## Changelog

### 0.1.10 (2026-08-28)

#### Corrigido

- **Um soluço curto da fonte derrubava o run inteiro.** O canário de 27/ago/2026 falhou com `SSL: UNEXPECTED_EOF_WHILE_READING` nas 3 tentativas — que somadas cobriam apenas ~15 s. A API da ANEEL voltou sozinha logo depois (a mesma consulta passou em 1,7 s no run seguinte), então nada estava quebrado no actor nem no filtro do prefill: a janela de retry é que era curta demais para uma indisponibilidade momentânea.
- Retry passou de 3 para **5 tentativas**, com backoff exponencial **limitado a 15 s** e timeout por tentativa reduzido de 30 s para 20 s. A janela vai a ~130 s no pior caso, mantendo folga de mais de 2x contra o limite de 5 minutos do teste diário da plataforma.
- Testes de regressão para a política de retry (recuperação na última tentativa, teto do backoff, orçamento total da janela contra o limite de 5 min, e a mensagem de erro que aponta o proxy como plano B). Suíte foi de 14 para 19 testes.

### 0.1.9 (2026-08-21)

- **Escala de desconto por nível de assinatura ligada:** US$ 1,00 (sem desconto) · US$ 0,85 (Bronze) · US$ 0,70 (Silver) · US$ 0,60 (Gold) por 1.000 registros.
- **Preço reduzido de US$ 3,00 para US$ 1,00 por 1.000 registros entregues** (US$ 0,001 por item). Sem taxa de start e sem cobrança por run que não devolve nada; o custo de plataforma continua por conta do autor. Motivo: entrada mais acessível enquanto o autor constrói reputação na Store — o custo medido é US$ 0,07/1.000 resultados, então a margem segue folgada.

### \[0.1] — Correções de dados (20/ago/2026, mesmo dia da publicação)

> Corrigido **dentro da versão 0.1**, de propósito: quem já estivesse usando o actor
> passa a receber o dado certo automaticamente. Criar uma 0.2 deixaria usuários
> presos à versão com o valor errado.

#### Corrigido

- **Bandeira tarifária: unidade errada por 1000×.** O campo da ANEEL é R$/MWh (o recurso "Adicional" nomeia a coluna `VlrAdicionalBandeiraRSMWh`), mas era publicado como `adicionalPorKwh`. Agora saem dois campos com unidade explícita: `adicionalPorMwh` (valor original) e `adicionalPorKwh` (convertido). Bandeira amarela vigente: R$ 18,85/MWh = R$ 0,01885/kWh.
- **Enum de bandeira divergente da fonte.** O schema declarava "Vermelha Patamar 1/2" e omitia "Escassez Hídrica"; a ANEEL publica "Vermelha P1", "Vermelha P2" e "Escassez Hídrica". Três dos cinco valores reais não passariam na validação do schema declarado. Corrigido para espelhar a fonte.
- Testes de regressão para os dois casos, incluindo um que compara o enum declarado com os valores reais da fonte. Suíte foi de 11 para 14 testes.
- **Visão padrão do dataset escondia o período de vigência.** Numa consulta de histórico, duas revisões que mantiveram a mesma tarifa apareciam como linhas idênticas — davam impressão de duplicata. A visão agora mostra `inicioVigencia`, `fimVigencia`, `unidade` e `resolucaoHomologatoria`, que são o que distingue e o que permite citar a fonte.

### \[0.1] — Publicado em 20/ago/2026

#### Output schema (requisito de publicação)

- Adicionado `.actor/output_schema.json` e referenciado no `actor.json` via `output`. A documentação lista o output schema como **obrigatório para publicar na Store** — o console sinalizava com X vermelho.
- Ele declara *onde* o resultado está e como acessá-lo (o dataset schema declara *o que* cada item contém). Expõe dois links prontos: JSON e CSV.

#### Cobrança pelo evento nativo da plataforma

- Troca do evento customizado `tarifa-entregue` (com `Actor.charge()` explícito no código) pelo evento nativo **`apify-default-dataset-item`**, que a plataforma cobra automaticamente a cada item gravado no dataset padrão.
- **Motivo:** manter os dois ativos cobraria o usuário duas vezes por registro. Além disso, o evento nativo é estruturalmente mais seguro — dispara na própria gravação, não depende de o código lembrar de chamar a cobrança no ponto certo.
- `src/charging.py` e a constante `CHARGEABLE_EVENT` removidos (viraram código morto).

#### Correção do acesso à API a partir da plataforma

- O primeiro run bem-sucedido na plataforma falhou com `SSL: UNEXPECTED_EOF_WHILE_READING` nas 3 tentativas. Diagnóstico: não é TLS (o servidor negocia TLS 1.3 e o container usa OpenSSL 3.x) nem bloqueio geográfico geral — é o WAF da ANEEL derrubando conexões vindas de IP de datacenter.
- **`proxyConfiguration` era um campo morto:** existia no input schema desde a Fase 2, mas nem `main.py` nem `scraper.py` o liam. Agora está ligado de verdade (`Actor.create_proxy_configuration` → `proxy_url` propagado às três funções de fetch) e vem **ligado por padrão**, já que na plataforma o proxy é praticamente obrigatório para este alvo.
- User-Agent identificável adicionado (antes ia o `python-httpx/0.28.1` padrão). Verificado contra a API real: status 200. **Foi esta a correção que resolveu** — 3 runs consecutivos na plataforma passaram com conexão direta, sem proxy, depois da mudança.
- Proxy volta a vir **desligado por padrão**, com a evidência dos 3 runs: cobrar proxy do usuário sem necessidade encarece o run à toa. Continua disponível como plano B, e a mensagem de erro de rede aponta para ele.
- Mensagem de erro de rede agora explica o sintoma e sugere proxy residencial BR, em vez de só repetir o erro de SSL cru.

#### Correção do primeiro build na plataforma

- `requirements.txt` pinava `apify>=2.0.0,<3.0.0`, mas todo o teste local rodou com **apify 4.0.1**. O container instalava a 2.7.3, que traz `crawlee` 0.6.12 — incompatível com `pydantic` >= 2.13 (`TypeError: cannot specify both default and default_factory`) — e o run falhava no import, antes de executar qualquer linha do actor. Constraints alinhadas com as versões efetivamente testadas (`apify>=4.0.1`, `httpx>=0.28.1`).
- Causa raiz confirmada por reprodução em ambiente limpo: a constraint antiga reproduz o erro exato do container; a nova importa sem erro.

#### Reorganização pré-publicação

- Actor movido para pasta própria e autocontida (`actors/brazil-electricity-tariffs-aneel/`), separado dos documentos de planejamento do workspace.
- Slug técnico em inglês (`brazil-electricity-tariffs-aneel`) e título bilíngue inglês-primeiro, para não perder a busca internacional da Store.
- README reescrito em inglês com resumo em português — ele é a página de venda na Store, não documentação interna.
- `actor.json` passou a referenciar `dataset_schema.json` (via `storages.dataset`), `readme` e `changelog`, e a declarar `minMemoryMbytes: 256` — o schema de saída existia mas não estava conectado à plataforma.
- `.actorignore` adicionado como rede de segurança do que sobe no push.

Construção (Fase 3) e QA exaustivo local (Fase 4).

- Modos `tarifas_distribuidora`, `ranking` e `bandeira` contra a API oficial de dados abertos da ANEEL.
- Preço: US$ 0,003 por registro entregue, sem taxa de start.
- **Correções encontradas no QA da Fase 4, antes de qualquer publicação:**
  - Prefill de `distribuidora` trocado de "CPFL JAGUARI" (dado real, mas obsoleto desde 2018) para "EDP ES" (tarifa vigente confirmada).
  - `ranking` não tinha `sort` na busca de candidatos — o dedupe por distribuidora pegava uma linha arbitrária, misturando tarifa de 2026 de uma distribuidora com tarifa de 2010 de outra. Corrigido com `sort=DatInicioVigencia desc` + filtro de vigência ainda válida hoje.
  - `classeConsumo` era um campo livre no input, mas a combinação classe/subclasse real da ANEEL não é livre — variava por subgrupo (B1=Residencial, B2=Rural, B3=Não se aplica, B4=Iluminação pública) e algumas opções do dropdown (ex. "Comercial") nunca existiam na fonte, devolvendo dataset vazio silencioso pra B2/B3/B4. Removido como input; agora é derivado automaticamente do subgrupo.
  - `distribuidora` passou a ser normalizada para maiúsculo — a API é case-sensitive e "edp es" minúsculo devolvia vazio.
  - `competencia` (modo bandeira) ganhou validação de formato explícita — antes, um formato inválido devolvia dataset vazio sem indicar o motivo.
